diego1# 突破局域網限制,實現互聯網範圍內控制你的ROS機器人

更多創客作品,請關注筆者網站園丁鳥,蒐集全球極具創意,且有價值的創客作品
ROS機器人知識請關注,diegorobot
業餘時間完成的一款在線統計過程分析工具SPC,及SPC知識分享網站qdo


1.概述

ROS機器人系統有一個侷限就是,所有Robot都必須在一個局域網內,雖然有robot web tools工具集可以實現通過web瀏覽器控制ROS機器人,但仍然是要求Robot和瀏覽器必須在同一個局域網內。有許多的應用是需要跨地域,跨網絡進行監控機器人的,本文介紹一種突破局域網限制,可以實現互聯網範圍內通過Web對機器人進行控制。

2.原理

實現的原理還是使用robot web tools工具集,增加一箇中轉的服務器,本文中此服務器命名爲diegoserver。

2.1robot web tools基本原理

robot web tools工具集中實現通過web控制機器人的是通過rosbridge,和roslibjs兩個包,通過websocket實現(具體如何安裝,請搜索網絡,這裏不做介紹),先來看一下實現的架構

在這裏插入圖片描述

robot web tools 提供了一個rosbridge的包,通過topic/service與robot機器人通信,並將相應的topic/service封裝成json格式的消息。
roslibjs,是一個java script實現的rosbridge客戶端,通過websocket與rosbridge通信,roslibjs負責在web端實現發佈消息,訂閱消息的基本功能,更上層的js包,有ros2djs,ros3djs,keyboardteleopjs等上層包,可以實現地圖,導航,3d,鍵盤控制等功能,具體功能可以參考官網http://robotwebtools.org/ 網上大部分文章都是翻譯官網文章。

2.2 diegoserver 原理

在這裏插入圖片描述
diegoserver實現的原理簡單的來說,就是增加了一箇中繼服務器,服務器部署在互聯網上,實現跨局域網的遠程控制

diegobridge是一個部署在和robot,rosbridge同一局域網的一段pyton程序,實現rosbridge和diegoserver通訊。

3. cmd_vel的web發佈

下面實現一個最基本的cmd_vel消息的web發佈過程

3.1 web端實現

web端實現完全按照roslibjs的規範就可以,只要將ros的連接到diegoserver(也可以是你自己的服務器)即可,具體實現網上有很多參考代碼。本文用的是官網的示例代碼。如下是js的代碼,用到了keyboardteleopjs,可以通過鍵盤的實現cmd_vel topic的發佈

<script type="text/javascript" type="text/javascript">
    /**
     * Setup all visualization elements when the page is loaded.
     */
    function init() {
        // Connect to ROS.
        var ros = new ROSLIB.Ros({
            url: 'ws://diegoserver:5556/rosbridge'
        });

        // Initialize the teleop.
        var teleop = new KEYBOARDTELEOP.Teleop({
            ros: ros,
            topic: '/cmd_vel'
        });

        // Create a UI slider using JQuery UI.
        $('#speed-slider').slider({
            range: 'min',
            min: 0,
            max: 100,
            value: 90,
            slide: function (event, ui) {
                // Change the speed label.
                $('#speed-label').html('Speed: ' + ui.value + '%');
                // Scale the speed.
                teleop.scale = (ui.value / 100.0);
            }
        });

        // Set the initial speed .
        $('#speed-label').html('Speed: ' + ($('#speed-slider').slider('value')) + '%');
        teleop.scale = ($('#speed-slider').slider('value') / 100.0);
    }
</script>

html代碼

</div>
                    <div id="speed-label"></div>
                    <div id="speed-slider"></div>
                </div>

3.2服務器端實現

服務器端採用Flask開發,使用flask-socketio包實現websocket通信,服務器本質上就是對rosbridge包的轉發,非常簡單,如下是轉發代碼:

from flask_socketio import send, emit, Namespace
import random
import json

class RosBridgeNamespace(Namespace):

    def __init__(self, socketio, namespace=None):
        super().__init__(namespace=namespace)
        self.socketio=socketio
    
    def on_connect(self):
        print('############## some ros connect')
        
    def on_disconnect(self):
        print('disconnect')

    def send_to_front(self,data):
        self.socketio.emit('data',
                      json.dumps(data),
                      namespace='/rosbridge',broadcast=True)
    
    def send_to_rosbridge(self,data):
        self.socketio.emit('diegoserver',
                      data,
                      namespace='/rosbridge',broadcast=True)
        
    def on_rosbridge(self, data):#response for rosbridge
        self.send_to_front(data)


    def on_operation(self,data):# response for web client
        print('**************** receive operation message from web roblibjs client')
        self.send_to_rosbridge(data)

3.3 diegobridge的實現

rosbridge實現使用robot web tools中roslibpy包實現與rosbridge包的通信,通過socketio實現與diegoserver的通信,代碼如下:

from __future__ import print_function
import roslibpy
import socketio
import time
import json

sio = socketio.Client()
sio.connect('wt://diegoserver:5556', namespaces=['/rosbridge'])

client = roslibpy.Ros(host='localhost', port=9090)
client.run()

print('my sid is', sio.sid)

host = 'localhost'
port = 9090


class DiegoTalker():
    def __init__(self, topic, topic_type):
        self.topic=topic
        self.topic_type=topic_type

    def talk(self,data):
        talker = roslibpy.Topic(client, self.topic, self.topic_type)
        talker.publish(roslibpy.Message(data))
        talker.unadvertise()

class RosbridgeNamespace(socketio.ClientNamespace):
    def on_connect(self):
        pass

    def on_disconnect(self):
        pass

    def on_diegoserver(self, data):
        print('I received a message from the diego server')    
        if json.loads(data)['topic'] =='/cmd_vel' and json.loads(data)['op']=='publish':
            talker=DiegoTalker('/cmd_vel', 'geometry_msgs/Twist')
            talker.talk(json.loads(data)['msg'])

sio.register_namespace(RosbridgeNamespace('/rosbridge'))

實現的原理也很簡單,收到diegoserver發佈的cmd_vel消息後轉發給rosbridge

4.運行

首先運行rosbridge
roslaunch rosbridge_server rosbridge_websocket.launch
接着運行diegobridge
python3 diegobridge.py
運行後,即可以看到rosbridge輸出信息顯示已經有一個client連接

在這裏插入圖片描述

這時候打開diegoserver的控制界面,通過鍵盤就可以控制

在這裏插入圖片描述

這是我們用rostopic echo /cmd_vel就可以看到從遠程web客戶端發佈的cmd_vel 消息

在這裏插入圖片描述

當然可以發佈,也可以訂閱,原理相同,下圖就是通過這樣的方法遠程訂閱/map,並在web顯示的效果

在這裏插入圖片描述

考慮的網絡的穩定性,遠程控制可能會有實時性的問題,當然這個要看實際的應用場景,要實現一個產品化的應用,應該考慮如下問題:

  • 實時性
  • ROS的topic是高頻率,實時發佈的,服務器端應該增加高速緩存機制,
  • 安全性,基於互聯網的應用,應該充分考慮安全性,如通信過程加密等,這個非常重要,機器人一旦被網絡劫持,將有不可預想的後果。
  • 帶寬問題,如涉及視頻,導航的數據帶寬需求是非常大的
  • 其他…
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章