以下內(nèi)容為本人的學習筆記,如需要轉(zhuǎn)載,請聲明原文鏈接微信公眾號「ENG八戒」https://mp.weixin.qq.com/s/Igm51siCI-4FUtumMWwW-w
ROS 作為一個非常優(yōu)秀的機器人開發(fā)框架,內(nèi)部各個功能邏輯被劃分成各個節(jié)點(進程),而各個節(jié)點之間數(shù)據(jù)指令訪問非常頻繁,形式比如發(fā)布訂閱主題、調(diào)用服務(wù)等。
那么在機器人外部如果想要訪問其內(nèi)部數(shù)據(jù),比如做一個數(shù)據(jù)面板,實時監(jiān)控機器人的各項傳感器數(shù)據(jù)和地圖軌跡,甚至遙控運動,又該如何從 ROS 內(nèi)部獲取或者發(fā)送數(shù)據(jù)呢?
有個 ROS 包就專門為解決上面的需求而生,Rosbridge 提供了基于 JSON 格式的數(shù)據(jù)訪問 WebSocket 接口,方便非 ROS 軟件和 ROS 系統(tǒng)通信。WebSocket 接口特別適用于服務(wù)器和客戶端之間的高效通信,那么在啟動了 Rosbridge 后,我們可以把 ROS 系統(tǒng)當作服務(wù)器后端使用,然后通過客戶端對其訪問。
話不多說,馬上開始體驗之旅~
安裝環(huán)境
Rosbridge 依賴于 ROS 的安裝,目前 ROS 主要運行于 Linux 平臺,并且已經(jīng)迭代到了 ROS2 多個版本,目前主流 ROS 應用版本都是 ROS2 了。但很多教程都是介紹 ROS1,殊不知 ROS1 已經(jīng)脫離實際使用市場了,皆因 ROS2 通信性能的巨大優(yōu)化,后邊八戒會有個專題介紹,敬請關(guān)注!
如果你還沒安裝好 ROS2,可以參看一下八戒之前寫的《Linux 流暢安裝 ROS2》。但是之前用的版本是 crystal,在 apt 里搜了下找不到對應的 Rosbridge 包,而且 Ubuntu 18 環(huán)境下只能找到 dashing 版本的 Rosbridge apt 安裝包,所以決定升級系統(tǒng)到 Ubuntu 20 并且重新安裝 ROS2 foxy。
為何選擇 ROS2 的 foxy 版本呢?這個和底層的 DDS 通信協(xié)議實現(xiàn)版本有關(guān),這里不展開了,后續(xù)介紹 ROS2 通信性能巨大優(yōu)化時再聊。
參考《Linux: 流暢安裝 ROS2》時,由于系統(tǒng) Ubuntu 版本不一樣,所以 apt 安裝源需要注意變更為
# 默認注釋了源碼鏡像以提高 apt update 速度,如有需要可自行取消注釋
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse
# deb-src http://security.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse
# 預發(fā)布軟件源,不建議啟用
# deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse
# # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse
安裝 ROS 完成后記得在 ~/.bashrc 中追加啟動環(huán)境,要不然每次啟動終端都要手動載入一次環(huán)境
$ echo "source /opt/ros/foxy/setup.bash" >> ~/.bashrc
確認 ROS2 指令有效
$ ros2
只要 ros2 指令返回沒有提示該指令不存在就表示環(huán)境 OK。
接著安裝 foxy rosbridge 包
$ sudo apt install ros-foxy-rosbridge-server
ROS 訂閱和發(fā)布消息
在 ROS 內(nèi)部收發(fā)消息的方式有很多,其中比較簡單的方式就是創(chuàng)建一個主題(Topic),并在此基礎(chǔ)上發(fā)布訂閱消息。對于主題來說,發(fā)布就是以主題的名義發(fā)送消息,訂閱就是只接收和主題相關(guān)的消息。
為了簡單演示發(fā)布訂閱的大概過程,下面用指令的形式執(zhí)行。
創(chuàng)建一個節(jié)點,該節(jié)點訂閱主題為 /browser_topic
而且類型為 std_msgs/String
的消息,同時打印接收到的消息
$ ros2 topic echo /browser_topic std_msgs/String
指令 topic 用于主題相關(guān),子命令 echo 用于將主題的消息輸出。
由于系統(tǒng)中還沒有任何的其它節(jié)點被啟動,也沒有相應的主題消息被發(fā)布,所以訂閱后暫時看不到任何的消息打印。
接著創(chuàng)建一個節(jié)點,該節(jié)點發(fā)布主題為 /browser_topic
和類型為 std_msgs/String
的消息
$ ros2 topic pub /browser_topic std_msgs/String "data: 'hello fellow, i am a robot'"
publisher: beginning loop
publishing #1: std_msgs.msg.String(data='hello fellow, i am a robot')
publishing #2: std_msgs.msg.String(data='hello fellow, i am a robot')
publishing #3: std_msgs.msg.String(data='hello fellow, i am a robot')
publishing #4: std_msgs.msg.String(data='hello fellow, i am a robot')
publishing #5: std_msgs.msg.String(data='hello fellow, i am a robot')
...
子命令 pub 用于發(fā)布主題消息,data: 'hello fellow, i am a robot'
是 JSON 格式數(shù)據(jù)作為主題 /browser_topic
的消息發(fā)送出去。發(fā)布消息的節(jié)點會循環(huán)發(fā)送消息,直到被終止。
如果需要發(fā)布消息的節(jié)點在發(fā)布一次消息后自動退出,可以在命令結(jié)尾添加 -1
。
發(fā)布消息的節(jié)點建立后,可以看到訂閱主題 /browser_topic
的消息節(jié)點開始輸出接收到的消息
data: hello fellow, i am a robot
---
data: hello fellow, i am a robot
---
data: hello fellow, i am a robot
---
data: hello fellow, i am a robot
---
data: hello fellow, i am a robot
---
...
瀏覽器訪問 ROS
眾多的客戶端中,數(shù)瀏覽器比較統(tǒng)一,而且瀏覽器的 API 接口極為豐富和易于使用,用于機器人的數(shù)據(jù)展示再適合不過了,那么如何實現(xiàn)機器人和瀏覽器之間的數(shù)據(jù)流動呢?如果瀏覽器和機器人在局域網(wǎng)內(nèi)的不同終端里呢?
在 Rosbridge 出現(xiàn)之前,ROS 外界程序和 ROS 內(nèi)部節(jié)點溝通只能通過比較底層的傳輸層協(xié)議通信,比如 TCP、UDP等。為了解決通信的麻煩,Rosbridge 提供了 websocket 接口開放給 ROS 外部程序訪問,同時針對瀏覽器還提供了基于 Javascript 的庫(roslibjs)方便網(wǎng)頁調(diào)用 Rosbridge 的 websocket 接口。
roslibjs 庫的官方下載鏈接
https://github.com/RobotWebTools/roslibjs/releases
啟動 Rosbridge
Rosbridge 是一系列包的集合,通常以 rosbridge_suite 的開發(fā)包形式提供,如需要讓 ROS 外界程序和 ROS 內(nèi)部節(jié)點溝通,需要啟動 ROS 包 rosbridge_server 以提供 websocket 接口支持。
$ ros2 launch rosbridge_server rosbridge_websocket_launch.xml
rosbridge_websocket_launch.xml
是啟動 websocket 接口的配置文件。原來 rosbridge_server 默認的服務(wù)端口是 9090,如果需要修改成其它端口,可以修改這個配置文件的 port
字段對應的值,比如 9090
改為 9080
$ cat /opt/ros/foxy/share/rosbridge_server/launch/rosbridge_websocket_launch.xml
<launch>
<arg name="port" default="9080" />
<arg name="address" default="" />
<arg name="ssl" default="false" />
<arg name="certfile" default=""/>
<arg name="keyfile" default="" />
網(wǎng)頁面板
ROS 后端已經(jīng)準備好,那么接下來就設(shè)計一個略微簡陋的網(wǎng)頁程序,提供訪問 ROS 的 demo 面板。
這個頁面主要功能設(shè)計要點:
-
連接本地主機的 rosbridge 服務(wù),地址為
ws://localhost:9090
。 -
打開頁面或者刷新頁面后發(fā)布一次主題為
/browser_topic
的消息 “hi, robot”。 -
訂閱主題為
/browser_topic
的消息,接收到消息后打印到頁面。
按照標準 html 頁面格式編寫網(wǎng)頁文件內(nèi)容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<h1>Browser communicate with robot via Rosbridge of ROS2</h1>
<p>What will this page do:</p>
<ul>
<li>Connect rosbridge at <code>ws://localhost:9090</code></li>
<li>Publish a "hi, robot" ROS messages to ros topic <code>/browser_topic</code> once after page opened or pressing F5</li>
<li>Start subscribe ROS messages from ros topic <code>/browser_topic</code> & print it on this page</li>
</ul>
<p>View the full tutorial at <a href="https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzUxMTgxMzExNQ==&scene=124#wechat_redirect" target="_blank">公眾號: ENG八戒</a></p>
<hr/>
<p>Connection: <span id="status" style="font-weight: bold;">N/A</span></p>
<p><code>/browser_topic</code> messages sended: <ul id="messages_send" style="font-weight: bold;"></ul></p>
<p><code>/browser_topic</code> messages received: <ul id="messages_recv" style="font-weight: bold;"></ul></p>
<script type="text/javascript" src="../js/roslib.js"></script>
<script type="text/javascript">
// TODO: Add custom JS code here
</script>
</body>
</html>
啟動當前網(wǎng)頁看看
$ firefox html/index.html
這里調(diào)用火狐瀏覽器 firefox 來打開網(wǎng)頁 index.html,換成其它主流瀏覽器也可以,比如 chrome 等。
index.html 頁面雖然已經(jīng)加載了 Javascript 庫 roslibjs,但這時的網(wǎng)頁還是靜態(tài)頁面,缺乏自定義的腳本代碼實現(xiàn)功能邏輯,那么接下來嘗試添加 Javascript 代碼給頁面添加上前面設(shè)計好的功能邏輯。
前面在設(shè)計頁面的時候預留了添加功能邏輯代碼的位置
<script type="text/javascript">
// TODO: Add custom JS code here
</script>
首先,使用 roslibjs 庫提供的全局對象 ROSLIB 創(chuàng)建 ros 對象,并指定后端服務(wù)接口地址 ws://localhost:9090
const ros = new ROSLIB.Ros({ url: "ws://localhost:9090" });
localhost 表示服務(wù)器位于本地主機,端口是 9090。Javascript 返回的對象一般存儲在 const 類型的變量中。
開始的時候提了個需求,如果瀏覽器和機器人在局域網(wǎng)內(nèi)的不同終端里,瀏覽器又如何訪問機器人呢?這個時候只需要把創(chuàng)建 ros 對象時 localhost
替換為 rosbridge_server 服務(wù)運行所在的主機的網(wǎng)絡(luò) IP 地址即可,比如
const ros = new ROSLIB.Ros({ url: "ws://192.168.234.151:9090" });
接著添加連接狀態(tài)回調(diào),一旦連接上顯示 yes,連接關(guān)閉則顯示 no,連接發(fā)生故障則顯示 errored out 末尾追加故障信息。狀態(tài)顯示在 id 為 status 的頁面 span 元素中
ros.on("connection", () => {
document.getElementById("status").innerHTML = "yes";
});
ros.on("error", (error) => {
document.getElementById("status").innerHTML = `errored out (${error})`;
});
ros.on("close", () => {
document.getElementById("status").innerHTML = "no";
});
使用全局對象 ROSLIB 創(chuàng)建主題為 /browser_topic
的對象,用于監(jiān)聽接收消息和主動發(fā)布消息,并且指定主題的消息類型為 std_msgs/String
const my_topic_object = new ROSLIB.Topic({
ros: ros,
name: "/browser_topic",
messageType: "std_msgs/String",
});
設(shè)置接收到主題消息后的執(zhí)行回調(diào),把接收到的消息作為字符串添加到 id 為 messages_recv
的頁面 ul 元素中
my_topic_object.subscribe((message) => {
const ul = document.getElementById("messages_recv");
const newMessage = document.createElement("li");
newMessage.appendChild(document.createTextNode(message.data));
ul.appendChild(newMessage);
});
使用全局對象 ROSLIB 創(chuàng)建一個消息對象,數(shù)據(jù)用 JSON 格式封裝。在打開頁面或者刷新頁面后,主動發(fā)送一次該消息,并且把消息的 data 字段值作為字符串添加到 id 為 messages_send
的頁面 ul 元素中
var greet_msg = new ROSLIB.Message({
data : "hi, robot"
});
my_topic_object.publish(greet_msg);
{
const ul = document.getElementById("messages_send");
const newMessage = document.createElement("li");
newMessage.appendChild(document.createTextNode(greet_msg.data));
ul.appendChild(newMessage);
}
最后,重新打開頁面 index.html 或者刷新該頁面,看看執(zhí)行效果
該頁面調(diào)用 roslibjs 庫在發(fā)布消息后,同時也會接收到自己發(fā)布出去的消息,因為訂閱的主題和發(fā)布主題是一樣的。文章來源:http://www.zghlxwxcb.cn/news/detail-817727.html
當然,接收到的消息也包含了從 ros 系統(tǒng)發(fā)布的同樣主題的消息。文章來源地址http://www.zghlxwxcb.cn/news/detail-817727.html
到了這里,關(guān)于ROS: 如何通過網(wǎng)頁訪問機器人內(nèi)部數(shù)據(jù)?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!