我的AI之路(26)--使用ROSBridge WebSocket和roslibjs構建一個簡單的控制機器人的web demo
在一個複雜的機器人後端控制平臺系統開發完成以前,往往需要對你的機器人產品進行簡單的軟體架構設計驗證或進行控制測試,這時,如果能花比較少的時間快速做一個web頁面或者一個Android app來作此用途的話能節省不少人力,本人花比較少的時間做了一個web demo和幾個安卓app用於不同機器人的通訊和控制的驗證和測試,先只說怎麼做web demo,實現安卓app的思路跟基於Java EE開發機器人控制平臺的思路比較相似,關鍵技術是使用Java WebSocket建立與機器人上的Rosbridge之間的雙向長連線和實現自定義的應用協議與rosbridge v2.0 Protocol 之間的轉換來實現應用和ROS通訊的解耦合,就先不說了,後面有空再說,先只說說怎麼做一個簡單的web demo。
前面說過,ROSBridge提供了使用tcp/udp/websocket連線呼叫機器人上的ROS來實現對機器人的控制的途徑,ROSBridge提供了WebSocket Server可以連線,那麼寫一個web頁面使用websocket連線到Rosbridge遵循rosbridge v2.0 Protocol 與ROS進行互動就可以控制機器人了,roslibjs就是個可以用於此目的工具庫,roslibjs是ROS JavaScript庫,看它的原始碼就知道,實際上它的下層就是使用websocket與Rosbridge進行通訊,寫過JavaScript的對ROS有一定了解後可以用它很快實現一個頁面來控制機器人,另外,如果頁面中如果還需要有2D、3D視覺化效果的話,還需要用到ros2djs和ros3djs,此外還需要用到一些相關javascript支援庫。
具體步驟:
1.首先當然得安裝rosbridge:
sudo apt-get install ros-kinetic-rosbridge-suite
2.獲取相關JavaScript庫(我把收集到的這些js庫和引用到的相關css檔案打包上傳到這裡了,設定了5積分下載為防惡意訪問):
獲取roslib.js,ros3d.min.js,ros2d.min.js(也可以從https://static.robotwebtools.org下載)
git clone https://github.com/RobotWebTools/roslibjs.git
git clone https://github.com/RobotWebTools/ros2djs.git
git clone https://github.com/RobotWebTools/ros3djs.git
把下面這些js檔案下載到本地並且與roslib.js、ros3d.min.js,ros2d.min.js放到同一個目錄scripts下供稍後web頁面使用:
https://static.robotwebtools.org/threejs/current/three.js
https://static.robotwebtools.org/threejs/current/ColladaLoader.js
https://static.robotwebtools.org/threejs/current/STLLoader.js
https://static.robotwebtools.org/EventEmitter2/current/eventemitter2.min.js
https://static.robotwebtools.org/roslibjs/current/roslib.js
https://static.robotwebtools.org/ros2djs/current/ros2d.min.js
https://static.robotwebtools.org/ros3djs/current/ros3d.min.js
https://static.robotwebtools.org/keyboardteleopjs/current/keyboardteleop.js
https://github.com/rctoris/mjpegcanvasjs/blob/develop/src/MjpegCanvas.js
另外:https://github.com/mrdoob/three.js 這裡可以找到JavaScript 3D的全部js檔案。
roslib.js,ros2d.js,ros3d.js的API可以這裡查:
roslibjs APIs: http://robotwebtools.org/jsdoc/roslibjs/current/
ros2djs APIs: http://robotwebtools.org/jsdoc/ros2djs/current/
ros3djs APIs: http://robotwebtools.org/jsdoc/ros3djs/current/
3.如果需要用到模擬視訊監控,還需下載和編譯安裝一個支援HTTP streaming of ROS
images的web_video_server包:
cd ~/catkin_ws/src
git clone https://github.com/RobotWebTools/web_video_server.git
cd ..
catkin_make
4. 主要程式碼 (可以參考<<ROS Robotics Projects>>一書的第12章對應的html原始碼,尤其可以在speechcommands.html的基礎上修改,不過要注意的是,speech_commands示例程式碼已被作者早就從https://github.com/qboticslabs/ros_robotics_projects上刪除,需要從歷史版本中下載,事實上這個上面的不少程式碼都已經不能直接使用,因為有些檔案或者引用的檔案都找不著了,需要自己想辦法琢磨解決錯誤,所以僅供參考,下載後恐怕多半跑不起來 :) ):
(1)包含用到的js和css:
<link rel="stylesheet" type="text/css" href="scripts/jquery-ui.css"/>
<link rel="stylesheet" type="text/css" href="scripts/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="scripts/font-awesome.min.css"/>
...
<script type="text/javascript" src="scripts/jquery.min.js"></script>
<script type="text/javascript" src="scripts/bootstrap.min.js"></script>
<script type="text/javascript" src="scripts/jquery-ui.min.js"></script>
<script type="text/javascript" src="scripts/eventemitter2.min.js"></script>
<script type="text/javascript" src="scripts/roslib.min.js"></script>
<script type="text/javascript" src="scripts/bootbox.min.js"></script>
<script type="text/javascript" src="scripts/three.js"></script>
<script type="text/javascript" src="scripts/ColladaLoader.js"></script>
<script type="text/javascript" src="scripts/STLLoader.js"></script>
<script type="text/javascript" src="scripts/ColladaLoader2.js"></script>
<script type="text/javascript" src="scripts/ros3d.min.js"></script>
<script type="text/javascript" src="scripts/mjpegcanvas.js"></script>
<script type="text/javascript" src="scripts/keyboardteleop.js"></script>
(2) 對speech_commands.html做的主要修改(改變連線控制和增加了3D視覺化控制元件):
function connect() {
var connectButton;
if (connected) { // disconnect
ros.close();
} else {
if(hasEverConected){
bootbox.alert ("請重新整理頁面後再連線!"); //因為roslibjs和ros3djs沒有資源管理和釋放功能,所以不得不這麼限制!否則每次連線頁面會重複建立Viewer object!
return;
}
robotUrl = document.getElementById("robotUrlEntry").value.trim();
if (robotUrl == '') {
bootbox.alert ("請輸入URL和port");
return;
}
robotUrl = robotUrl.replace("https:", "wss:");
robotUrl = robotUrl.replace("http:", "ws:");
if ((robotUrl.slice (0,5) != "wss://") && (robotUrl.slice (0,4) != "ws://") &&
(robotUrl.charAt(robotUrl.length - 5) != ":")) {
var r = bootbox.alert
("URL應該以http, https, ws或wss開頭, 並以埠結尾, 例如 ':9090'.");
return;
}
ros = new ROSLIB.Ros({ // Connecting to ROS.
url: robotUrl
});
//////////////////////////////建立視覺化控制元件////////////////////////////////////////////////
ip = location.hostname;
if(ip=="")ip="localhost";
res_path= "http://"+ip+"/share";
if(!hasEverConected)
{
viewer = new ROS3D.Viewer({
background : 000,
divID : 'urdf',
//width : 1280,
//height : 600,
width : 800,
height : 400,
antialias : true
});
// Add a grid.
viewer.addObject(new ROS3D.Grid());
// Create the Stream viewer.
streamViewer = new MJPEGCANVAS.MultiStreamViewer({
divID : 'mjpeg',
host : 'localhost',
width : 800,
height : 400,
host : ip,
port : 8080,
interval : 200,
topics : [ '/camera/rgb/image_raw', '/camera/rgb/image_raw',
'/camera/rgb/image_raw' ],
labels : [ 'Robot View', 'Left Arm View', 'Right Arm View' ]
});
hasEverConected=true;
}
// Setup a client to listen to TFs.
tfClient = new ROSLIB.TFClient({
ros : ros,
fixedFrame : base_frame,
angularThres : 0.01,
transThres : 0.01,
rate : 10.0
});
// Setup the URDF client.
urdfClient = new ROS3D.UrdfClient({
ros : ros,
tfClient : tfClient,
//path : 'http://resources.robotwebtools.org/',
path : res_path,
rootObject : viewer.scene,
loader : ROS3D.COLLADA_LOADER
});
// Initialize the teleop.
teleop = new KEYBOARDTELEOP.Teleop({
ros : ros,
topic : teleop_topic
});
} //else
ros.on('connection', function() {
localStorage.robotUrl = robotUrl;
connectButton = document.getElementById("connectButton");
connectButton.innerHTML = "斷開";
connectButton.style.background="#00cc00"; // green
say ('connected');
connected = true;
console.log ('Connected to websocket server.');
});
ros.on('error', function(error) {
console.log (error);
bootbox.alert ('Error connecting to websocket server. ');
});
ros.on('close', function() {
if (connected) { // throw away a second call
connected = false;
connectButton = document.getElementById("connectButton");
connectButton.style.background = "#006dcc";
connectButton.innerHTML = "連線"
say ('connection closed');
console.log('Connection to websocket server closed.');
}
});
} //function connect()
4.需要用到3D視覺化效果,那麼還需要安裝tf2_web_republisher,tf2_web_republisher的作用是計算TF資料並通過rosbridge_server發給ros3djs client(ROSLIB.TFClient 例項),ROSLIB.TFClient物件訂閱來自tf2_web_republisher的TF資料並更新ROS3D.Viewer物件,ROS3D.Viewer物件將URDF model在瀏覽器裡視覺化:
cd ~/catkin_ws/src
git clone https://github.com/RobotWebTools/tf2_web_republisher
sudo apt-get install ros-kinetic-tf2-ros
cd ~/catkin_ws
catkin_make
5.頁面裡用到3D效果,如果urdf檔案也放在機器人上(或者模擬機器人所在的Linux伺服器上):
var urdfClient = new ROS3D.UrdfClient({
ros : ros,
tfClient : tfClient,
path : 'http://localhost/share',
rootObject : viewer.scene,
loader : ROS3D.COLLADA_LOADER
});
那麼還需安裝個http sever,比如安裝apache,下面是安裝apache2並修改配置和啟動:
sudo apt-get install apache2
#把urdf所在的資料夾share通過連結放到apache的頂級目錄下
ln -s /opt/ros/kinetic/share /var/www/html
cd /etc/apache2
vi apache2.conf
#做如下修改:
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
Header set Access-Control-Allow-Origin http://localhost/share
</Directory>
#Enabling module headers. otherwise, "Invalide command Header" will be seen when you starting apache2.service
sudo a2enmod headers
#start apache
systemctl restart apache2.service
如果apache裡不做上面的Allow-Control-Allow-Origin設定,會報跨域訪問錯誤:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/share/turtlebot_description/meshes/stacks/hexagons/pole_bottom.dae. (Reason: CORS request did not succeed).
做了上面的改動後,Firefox可以了,但Chrome瀏覽器還不行, 需下載最新谷歌跨域擴充套件外掛,在谷歌瀏覽器輸入:chrome://extensions,然後把下載好的檔案拖入chrome://extensions頁面,點選安裝即可完成安裝;不需要特殊設定,就可以完成跨域請求了。
6. 啟動模擬機器人及相關節點和Server的命令:
roslaunch turtlebot_gazebo turtlebot_world.launch
rosrun web_video_server web_video_server
rosrun tf2_web_republisher tf2_web_republisher
roslaunch rosbridge_server rosbridge_websocket.launch
7.拷貝demo目錄(在speech_commands包上做的修改:補齊了原來缺失的js檔案和根據需要修改或增加了speech_commands.html的程式碼)到apache下並訪問它:
cp -rf demo /var/www/html
#假設模擬機器人所在的伺服器的IP是192.168.1.133,在瀏覽器裡輸入下面的地址即可開啟demo並操控機器人
http://192.168.1.133/demo/demo.html
相關文章
- 一個最簡單的WebSocket hello world demoWeb
- 簡單的websocket demoWeb
- 用Java構建一個簡單的WebSocket聊天室JavaWeb
- 使用 Python 構建一個簡單的 RESTful APIPythonRESTAPI
- [譯] 使用 Node 和 OAuth 2.0 構建一個簡單的 REST APIOAuthRESTAPI
- rosbridge簡單的安裝記錄ROS
- 使用WebSocket實現一個簡單的頁面聊天Web
- [譯] 如何使用 Phaser 3 和 TypeScript 在瀏覽器中構建一個簡單的遊戲TypeScript瀏覽器遊戲
- 用Java構建一個簡單的WebSocket聊天專案之新增HTTP介面排程JavaWebHTTP
- 關於 WebSocket 和 HTTP 區別的思考以及一個最簡單的 WebSocket 的客戶端和伺服器實現WebHTTP客戶端伺服器
- [轉]:如何快速構建一個簡單的程式
- 程式碼來構建一個簡單的compilerCompile
- 嘗試從零開始構建我的商城 (一) :使用Abp vNext快速一個簡單的商城專案
- 關於SSM框架的一個簡單DemoSSM框架
- 一個簡單的介面測試框架 demo框架
- Web 端語音對話 AI 示例:使用 Whisper 和 llama.cpp 構建語音聊天機器人WebAI機器人
- Vue.js SSR Step by Step (2) – 一個簡單的同構DEMOVue.js
- 一個簡單的構建React元件動畫方案React元件動畫
- 基於 WebSocket 的 PPT 遠端控制器簡單實現Web
- 一個最簡單的web componentsWeb
- 如何構建AI文化:AI的啟蒙之路AI
- 給 Java 和 Android 構建一個簡單的響應式Local CacheJavaAndroid
- 給 Java 和 Android 構建一個簡單的響應式Local CaJavaAndroid
- 使用 Redis 和 Python 構建一個共享單車的應用程式RedisPython
- 使用 Vue.js 和 Flask 來構建一個單頁的AppVue.jsFlaskAPP
- 如何簡單方便的建個人網站網站
- 聊聊UDP、TCP和實現一個簡單的JAVA UDP小DemoUDPTCPJava
- 使用 LangChain 構建聊天機器人LangChain機器人
- 使用 sshuttle 構建一個窮人的虛擬專網
- 使用 shuttle 構建一個窮人的虛擬專網
- [譯] 使用 React 和 ImmutableJS 構建一個拖放佈局構建器ReactJS
- 一個可以自動構建CURD控制器的go-apiGoAPI
- 用 Go 編寫一個簡單的 WebSocket 推送服務GoWeb
- 一個超級簡單的 go Web 框架GoWeb框架
- C# WebSocket的簡單使用【使用Fleck實現】C#Web
- 使用PHP內建web伺服器,實現簡單的除錯應用PHPWeb伺服器除錯
- swoole 的練習 demo(3)- 簡陋的 websocket 專案Web
- 利用angular4和nodejs-express構建一個簡單的網站(九)—使用者登入AngularNodeJSExpress網站