安卓与ROS通信的现状

因为ROS官方支持的语言绑定只有C++和Python,所以目前安卓想与ROS通信,必须借助半官方的rosjava包,而Rosjava太重了,因为它跟C++/Python一样,是一个全功能的ROS绑定,意即你可以在Java(android)平台上创建Master Node,然后其他Node(C++/Python)可以连上这个Master,进行分布式通信!这对于桌面Java或许还能接受,但对于android实在是过于复杂了。
另外,rosjava的gradle脚本太复杂,需要很深的gradle知识才能将其集成到自己的android工程,很多公司嫌麻烦直接导入rosjava的demo工程,然后将自己的代码添加进去,团队里如果有新人加入,则还要重新搭建一个rosjava环境,太麻烦了。

rosbridge协议

很多人都觉得移动平台or嵌入式系统要实现跟ROS进行分布式通信成本太高昂,大家寻思用C/S架构可能更符合移动平台的需求,于是提出了rosbridge协议,该协议的基本思想是将节点间的分布式通信,改成client节点与一个代理节点进行C/S通信,然后代理节点再将请求转发给server节点,这样移动端就不需要实现整个ROS平台,只需要跟代理节点通信即可
这是一篇比较rosjava跟rosbridge优劣的pdf,简单来说,就是移动平台以牺牲做server节点的代价,换来了轻量级ROS交互的能力。不过特殊情况下rosjava还是有用的,比如机器人的底盘调用机械臂的service,如果机械臂只支持rosbridge,则调用不可行——不过这种情况通过pub/sub应该也能解决。

ROSBridgeClient库

要让android能收发rosbridge消息,首先要支持WebSocket这种特殊的传输通道才能实现android接收ROS端publish(推送)过来的消息,目前实现WebSocket的大部分集中在桌面Java,比如Jetty、Netty等,其中Jetty因为用到了某些Dalvik VM不支持的java类而导致不能在android上使用。另外android自身的webview对WebSocket的支持较晚,不能保证全机型覆盖,所以Java-WebSocket这个用java.nio包里的类实现的WebSocket就脱颖而出。
有了传输通道,剩下的就是怎么组包发送了,这个库不仅要将发送的Java类型转换成语言无关的ROS消息类型(反之亦然),还要将ROS操作(订阅、发布、调用service、广播topic等)转换成rosbridge里规定的json串,在评估了java_rosbridge库和ROSBridgeClient库后,我选择了后者,因为前者虽然更小巧,但是用的jetty来实现WebSocket通信,没法跑在android上。

添加std_msgs包里的消息类型

在试用ROSBridgeClient库的过程中,我发现作者连std_msgs里的消息类型——例如String——都没有实现,却而代之的,是一个 精巧的注解加反射机制实现的meta message类型,要扩展很简单,见我fork出来的repo 。
在摸索std_msgs的过程中,我弄明白一个机制:ROS的内置类型其实并不是实际存在的,它必须对应到具体语言的内置类型,所以为了跨语言通信,所有Message只能使用Wrapper类型,这就解释了为什么std_msgs包里一堆wrapper了,因为每个msg文件里的内置类型(比如string),都是不存在的,必须对应到Java的String,或Python的str、或C++的std::string,唯独不能对应ROS的string,因为ROS不是一门语言。

上文为DarrenChan陈驰博文所写,我们发现相较于ROSjava而言ROSBridge更易于开发,同时适用于JAVA、C#等语言具有更好的扩展性。同时能够跨平台设计实现。

ROSBridge是一个可用于非ROS系统和ROS系统进行通信的功能包,非ROS的系统使用指定数据内容的基于JSON(或BSON)格式的网络请求(ROSBridge支持TCP、UDP、WebSocket三种网络通讯方式)来调用ROS的功能,既然非ROS系统能通过ROSBridge基于TCP/UDP/WebSocket与机器人上的ROS进行交互,那就是实现了外部系统和机器人上的ROS的解耦合,也就是外部系统完全可以与机器人使用不同的开发语言不同的OS平台。 这里参照了Arnold-FY-Chen的相关博客。

ROS是用在机器人本体上的(前面说过,ROS只是个中间件,跑在机器人内安装的Ubuntu之类Linux上,而且两者的版本安装要匹配,要按ROS官网上指定的来),而管理和控制机器人的机器人后端(或者叫服务端)控制系统(或者叫平台)通常是使用Java,C#之类的语言开发的。

ROSBridge就非常适合用于两者之间的交互通讯实现机器人后端控制系统对机器人的控制 (这里的说的控制不仅仅包含机器人遥控器对机器人的那种运动和语音之类的手段控制功能,而且还包括机器人后端控制系统向机器人下发配置数据、地图与导航路径数据、任务数据、特殊动作实时控制、软件更新等等数据以及机器人向机器人后端控制系统上传音视频设备实时获取的音视频数据、地图坐标数据、各种传感器收集的数据、告警数据、任务执行相关数据等等)

另外,我觉得机器人之间也适合使用ROSBridge来进行通讯,无论另外的机器人使用的是Ubuntu+ROS还是纯Android的还是三者都使用了(三者都使用了的情况常见于有人机交互界面采用上下位机两块板子的机器人)。 当然,如果融资多、人力资源充裕、工期不紧张并且有特殊大数据传输要求,完全可以不使用ROSBridge,自己用C++开发一个TCP/WebSocket Sever部署在Linux上,作为机器人本体上的ROS与机器人后端控制系统之间的通讯的桥梁。如果创业公司需要快速出产品、人手又少、没多少钱烧,那么基于现有的ROSBridge来实现机器人后端控制系统与机器人之间的通讯还是比较好的选择。

ROS默认安装没有包含ROSBridge,需要执行下面命令来安装它:

sudo apt-get install ros-<rosdistro>-rosbridge-suite

比如:

sudo apt-get install ros-kinetic-rosbridge-suite

(或者也可以从 https://github.com/RobotWebTools/rosbridge_suite 获取到完整的源码包,从下载的包可以看到其实源码都是用python写的脚本,另外是一些msg和srv的定义文件,然后使用catkin编译和安装)

安装完后,可以在/opt/ros/kinetic/lib/python2.7/dist-packages/下看到两个重要的包rosbridge_server和rosbridge_library。

ROSBridge内容包括通讯协议规范定义rosbridge v2.0 Protocol Specification和代码实现。

之后加入ROS环境

source /opt/ros/indigo/setup.bash

创建工作空间和下载代码

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
git clone https://github.com/RobotWebTools/rosbridge_suite.git

编译

cd ~/catkin_ws
catkin_make

加入工作环境

cd ~/catkin_ws
source devel/setup.bash

rosbridge_server、rosbridge_library、rosapi就是ROSBridge的代码实现部分,三部分的功能分别是:

rosbridge_server\color{red}{rosbridge\_server}rosbridge_server

说明:

介绍rosbridge_server提供的多种服务器模式及实现

代码目录结构:
├── CHANGELOG.rst
├── CMakeLists.txt
├── launch                            #启动
│   ├── rosbridge_tcp.launch          #启动TCP服务器,调用rosbridge_tcp.py
│   ├── rosbridge_udp.launch          #启动UDP服务器,调用rosbridge_udp.py
│   └── rosbridge_websocket.launch    #启动WEBSOCKET服务器,调用rosbridge_websocket.py
├── package.xml
├── scripts
│   ├── rosbridge_tcp -> ./rosbridge_tcp.py
│   ├── rosbridge_tcp.py              #ros TCP节点, 利用SocketServer实现TCP通讯
│   ├── rosbridge_udp -> rosbridge_udp.py
│   ├── rosbridge_udp.py              #ros UPD节点,利用reactor.listenUDP实现UDP通讯
│   ├── rosbridge_websocket -> rosbridge_websocket.py
│   └── rosbridge_websocket.py        #ros websocket节点,利用tornado.web实现websocket通讯
├── setup.py
└── src├── backports│   ├── __init__.py│   └── ssl_match_hostname│       ├── __init__.py│       ├── LICENSE.txt│       └── README.txt├── rosbridge_server             #服务器处理│   ├── __init__.py│   ├── tcp_handler.py           #实现RosbridgeTcpSocket类,用于处理TCP消息│   ├── udp_handler.py           #实现RosbridgeUdpFactory类和RosbridgeUdpSocket类,用于处理UDP消息│   ├── websocket_handler.py     #实现RosbridgeWebSocket类,用于处理websocket消息└── tornado                      #Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本├── auth.py├── autoreload.py├── concurrent.py├── curl_httpclient.py├── escape.py├── gen.py├── http1connection.py├── httpclient.py├── httpserver.py├── httputil.py├── __init__.py├── ioloop.py├── iostream.py├── locale.py├── log.py├── log.pyc├── netutil.py├── options.py├── platform│   ├── asyncio.py│   ├── auto.py│   ├── auto.pyc│   ├── caresresolver.py│   ├── common.py│   ├── epoll.py│   ├── epoll.pyc│   ├── __init__.py│   ├── interface.py│   ├── kqueue.py│   ├── posix.py│   ├── select.py│   ├── twisted.py│   └── windows.py├── process.py├── simple_httpclient.py├── speedups.c├── stack_context.py├── tcpclient.py├── tcpserver.py├── template.py├── test│   ├── auth_test.py│   ├── concurrent_test.py│   ├── csv_translations│   │   └── fr_FR.csv│   ├── curl_httpclient_test.py│   ├── escape_test.py│   ├── gen_test.py│   ├── gettext_translations│   │   └── fr_FR│   │       └── LC_MESSAGES│   │           ├── tornado_test.mo│   │           └── tornado_test.po│   ├── httpclient_test.py│   ├── httpserver_test.py│   ├── httputil_test.py│   ├── import_test.py│   ├── __init__.py│   ├── ioloop_test.py│   ├── iostream_test.py│   ├── locale_test.py│   ├── log_test.py│   ├── __main__.py│   ├── netutil_test.py│   ├── options_test.cfg│   ├── options_test.py│   ├── process_test.py│   ├── README│   ├── resolve_test_helper.py│   ├── runtests.py│   ├── simple_httpclient_test.py│   ├── stack_context_test.py│   ├── static│   │   ├── dir│   │   │   └── index.html│   │   └── robots.txt│   ├── tcpclient_test.py│   ├── templates│   │   └── utf8.html│   ├── template_test.py│   ├── test.crt│   ├── testing_test.py│   ├── test.key│   ├── twisted_test.py│   ├── util.py│   ├── util_test.py│   ├── websocket_test.py│   ├── web_test.py│   └── wsgi_test.py├── testing.py├── util.py├── web.py├── websocket.py└── wsgi.py
重要文件说明:

SocketServer

  • SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端
  • https://docs.python.org/2/library/socketserver.html
  • http://www.cnblogs.com/zhangkui/p/5655428.html
  • http://blog.csdn.net/ghostfromheaven/article/details/8653421

Twisted/reactor

  • Twisted 是用Python实现的基于事件驱动的网络引擎框架

  • http://www.cnblogs.com/whiggzhaohong/p/5401679.html

  • http://www.tuicool.com/articles/MJBviuM

tornado

  • Tornado是FriendFeed使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本
  • http://www.tornadoweb.cn/
  • http://www.tornadoweb.cn/documentation
  • http://www.tornadoweb.org/en/stable/

rosbridge_library\color{red}{rosbridge\_library}rosbridge_library

说明:

介绍rosbridge_library各文件及功能

代码目录结构:

├── CHANGELOG.rst
├── CMakeLists.txt
├── msg                                #定义消息
│   ├── Num.msg                        #定义数字消息
│   ├── TestChar.msg                   #定义字符消息
│   ├── TestDurationArray.msg          #定义Duration数组消息
│   ├── TestHeaderArray.msg            #定义Header数组消息
│   ├── TestHeader.msg                 #定义Header消息
│   ├── TestHeaderTwo.msg              #定义Header消息
│   ├── TestTimeArray.msg              #定义Time数组消息
│   ├── TestUInt8FixedSizeArray16.msg  #定义Unit8[16]消息
│   └── TestUInt8.msg                  #定义Unit8[]消息
├── package.xml
├── setup.py                           #python安装脚本
├── src
│   └── rosbridge_library              #核心库
│       ├── capabilities               #功能包
│       │   ├── advertise.py           #执行话题的广播和取消
│       │   ├── advertise_service.py   #执行服务的广播
│       │   ├── call_service.py        #调用服务
│       │   ├── defragmentation.py     #对消息内容解析
│       │   ├── fragmentation.py       #对消息内容封装
│       │   ├── __init__.py            #声明为Python库
│       │   ├── publish.py             #发布话题
│       │   ├── service_response.py    #服务反馈处理
│       │   ├── subscribe.py           #订阅话题
│       │   └── unadvertise_service.py #取消服务广播
│       ├── capability.py
│       ├── __init__.py
│       ├── internal                  #内部功能实现
│       │   ├── exceptions.py         #异常处理
│       │   ├── __init__.py
│       │   ├── message_conversion.py #消息转换
│       │   ├── pngcompression.py     #图像压缩
│       │   ├── publishers.py         #跟踪使用特定发布者的客户端。提供用于发布消息和注册使用这个发布者的客户端的API
│       │   ├── ros_loader.py         #ros相关核心类导入
│       │   ├── services.py           #为特定的服务创建服务调用者,使用start()开启独立线程,或在线程中使用run()函数。
│       │   ├── subscribers.py        #管理和与ROS订阅服务器对象接口.单个订阅者在多个客户端之间共享
│       │   ├── subscription_modifiers.py #位于来自订阅的传入消息和传出消息之间发布方法,提供限制/缓冲功能.当参数改变时,处理程序可以转换到不同的类型的处理程序
│       │   └── topics.py             #发布者和订阅者共同的代码和异常处理
│       ├── protocol.py               #单个客户端与ROS交互的接口.
│       ├── rosbridge_protocol.py     #继承protocol协议,初始化rosbridge功能列表
│       └── util
│           └── __init__.py
├── srv                               #服务定义
│   ├── AddTwoInts.srv                #
│   ├── SendBytes.srv                 #发送内容定义
│   ├── TestArrayRequest.srv
│   ├── TestEmpty.srv
│   ├── TestMultipleRequestFields.srv
│   ├── TestMultipleResponseFields.srv
│   ├── TestNestedService.srv
│   ├── TestRequestAndResponse.srv
│   ├── TestRequestOnly.srv
│   └── TestResponseOnly.srv
└── test                              #相关测试,包括核心功能,扩展功能,内部执行├── capabilities│   ├── __init__.py│   ├── test_advertise.py│   ├── test_call_service.py│   ├── test_capabilities.test│   ├── test_publish.py│   └── test_subscribe.py├── experimental│   ├── complex_srv+tcp│   │   ├── test_non-ros_service_client_complex-srv.py│   │   └── test_non-ros_service_server_complex-srv.py│   └── fragmentation+srv+tcp│       ├── test_non-ros_service_client_fragmented.py│       └── test_non-ros_service_server_fragmented.py├── __init__.py├── internal│   ├── __init__.py│   ├── publishers│   │   ├── __init__.py│   │   ├── test_multi_publisher.py│   │   ├── test_multi_unregistering.py│   │   ├── test_publisher_consistency_listener.py│   │   └── test_publisher_manager.py│   ├── subscribers│   │   ├── __init__.py│   │   ├── test_multi_subscriber.py│   │   ├── test_subscriber_manager.py│   │   └── test_subscription_modifiers.py│   ├── test_compression.py│   ├── test_internal.test│   ├── test_message_conversion.py│   ├── test_ros_loader.py│   └── test_services.py└── test_all.test
重要文件说明:

rosbridge_library/src/protocol.py

  • 单个客户端与ROS交互的接口.
  • 协议实例的生命周期如下:
    • 处理从客户端传入的消息
    • 发送处理后的消息到客户端
    • 客户端完成清除相关资源

rosbridge_library/test

  • python的单元测试目录
  • http://wiki.ros.org/unittest
  • http://wiki.ros.org/rostest

rosapi\color{red}{rosapi}rosapi

说明:

介绍rosapi各文件及功能

代码目录结构:
├── CHANGELOG.rst
├── CMakeLists.txt
├── msg
│   └── TypeDef.msg         #消息类型定义
├── package.xml
├── scripts                 #脚本
│   └── rosapi_node         #初始化服务和参数
├── setup.py
├── src
│   └── rosapi              #API具体实现
│       ├── __init__.py
│       ├── objectutils.py
│       ├── params.py
│       └── proxy.py
└── srv                     #定义各种服务├── DeleteParam.srv├── GetActionServers.srv├── GetParamNames.srv├── GetParam.srv├── GetTime.srv├── HasParam.srv├── MessageDetails.srv├── NodeDetails.srv├── Nodes.srv├── Publishers.srv├── SearchParam.srv├── ServiceHost.srv├── ServiceNode.srv├── ServiceProviders.srv├── ServiceRequestDetails.srv├── ServiceResponseDetails.srv├── ServicesForType.srv├── Services.srv├── ServiceType.srv├── SetParam.srv├── Subscribers.srv├── TopicsForType.srv├── Topics.srv└── TopicType.srv
重要文件说明:

scripts/rosapi_node

  • 初始化服务
  • 服务包含:
rospy.Service('/rosapi/topics', Topics, get_topics)
rospy.Service('/rosapi/topics_for_type', TopicsForType, get_topics_for_type)
rospy.Service('/rosapi/services', Services, get_services)
rospy.Service('/rosapi/services_for_type', ServicesForType, get_services_for_type)
rospy.Service('/rosapi/nodes', Nodes, get_nodes)
rospy.Service('/rosapi/node_details', NodeDetails, get_node_details)
rospy.Service('/rosapi/action_servers', GetActionServers, get_action_servers)
rospy.Service('/rosapi/topic_type', TopicType, get_topic_type)
rospy.Service('/rosapi/service_type', ServiceType, get_service_type)
rospy.Service('/rosapi/publishers', Publishers, get_publishers)
rospy.Service('/rosapi/subscribers', Subscribers, get_subscribers)
rospy.Service('/rosapi/service_providers', ServiceProviders, get_service_providers)
rospy.Service('/rosapi/service_node', ServiceNode, get_service_node)
rospy.Service('/rosapi/service_host', ServiceHost, get_service_host)
rospy.Service('/rosapi/message_details', MessageDetails, get_message_details)
rospy.Service('/rosapi/service_request_details', ServiceRequestDetails, get_service_request_details)
rospy.Service('/rosapi/service_response_details', ServiceResponseDetails, get_service_response_details)
rospy.Service('/rosapi/set_param', SetParam, set_param)
rospy.Service('/rosapi/get_param', GetParam, get_param)
rospy.Service('/rosapi/has_param', HasParam, has_param)
rospy.Service('/rosapi/search_param', SearchParam, search_param)
rospy.Service('/rosapi/delete_param', DeleteParam, delete_param)
rospy.Service('/rosapi/get_param_names', GetParamNames, get_param_names)
rospy.Service('/rosapi/get_time', GetTime, get_time)
节点说明:
  • /rosapi/Topics,返回所有发布的话题列表
  • /rosapi/topics_for_type,返回指定类型的所有发布的话题列表
  • /rosapi/services, 返回所有发布的服务列表
  • /rosapi/services_for_type,返回指定类型的所有发布的服务列表
  • /rosapi/nodes,返回所有已经注册的节点列表
  • /rosapi/node_details,返回某节点详情
  • /rosapi/action_servers,返回action服务列表
  • /rosapi/topic_type,通过话题名获取相应的消息类型
  • /rosapi/service_type,通过服务名获取相应的消息类型
  • /rosapi/publishers,提供话题名获取发布此话题的节点名列表
  • /rosapi/subscribers,提供话题名获取接受此话题的节点名列表
  • /rosapi/service_providers,提供话题名返回广播此服务类型的节点名列表
  • /rosapi/service_node,提供服务名,返回提供此服务的节点名
  • /rosapi/service_host,提供服务名,返回提供此服务的主机名
  • /rosapi/message_details,提供消息类型名,返回类型的TypeDef
  • /rosapi/service_request_details,提供服务类型名,返回消息请求的服务类型的TypeDef
  • /rosapi/service_response_details,提供服务类型名,返回消息反馈的服务类型的TypeDef
  • /rosapi/set_param,设置参数
  • /rosapi/get_param,获取参数
  • /rosapi/has_param,判断参数是否存在
  • /rosapi/search_param,检索参数
  • /rosapi/delete_param,删除参数
  • /rosapi/get_param_names,获取参数名
  • /rosapi/get_time,获取服务器时间

ROSBridge的工作原理和使用

源码目录ros_library下的RosbridgeProtocol类(在RosbridgeProtocol.py里)继承自Protocol类(在Protocol.py里),主要定义了Rosbridge支持哪些功能调用:

rosbridge_capabilities = [CallService, Advertise, Publish, Subscribe, Defragment, AdvertiseService, ServiceResponse, UnadvertiseService]

在初始化里创建并添加这些功能调用对应的handler类的实例:

for capability_class in self.rosbridge_capabilities:self.add_capability(capability_class)

add_capability()是在Protocol类里实现的:

def add_capability(self, capability_class):self.capabilities.append(capability_class(self))

上面的每个capability都继承自Capability类,并且在__init__(self,protocol)函数里调用protocol.register_operation()把自己的处理函数作为opcode对应的handker注册到protocol的operations[]里去,例如CallService类(在capabilities/call_service.py里)的__init__():

def __init__(self, protocol):Capability.__init__(self, protocol)    protocol.register_operation("call_service", self.call_service)

Protocol类的register_operation():

def register_operation(self, opcode, handler):self.operations[opcode] = handler

opcode具体有哪些可能的值以及示例,可参见 https://github.com/RobotWebTools/rosbridge_suite/blob/groovy-devel/ROSBRIDGE_PROTOCOL.md里第3节内容。

Protocol类的deserialize()把JSON/BSON格式数据解析到dict里,serialize()则是相反,把dict形式的数据序列化成JSON/BSON格式的数据,incoming()则是调用deserialize()把buffer里收到的JSON/BSON格式数据解析到msg里,并根据msg里的op值调用对应的hanlder来处理这个调用:

def incoming(self, message_string=""):msg = self.deserialize(self.buffer)op = msg["op"]self.operations[op](msg)

这里的handler调用rosbridge_library/inernal下的功能实现包装类的对应的方法来调用rospy (ROS的python版的Client API)的API来调用ROS的功能,以CallService类的call_service()方法为例:

def call_service(self, message):ServiceCaller(trim_servicename(service), args, s_cb, e_cb).start()

ServiceCaller是rosbridge_library/inernal/services.py里定义的线程类(继承自threading.Thread类),ServiceCaller的run()方法:

def run(self):self.success(call_service(self.service, self.args))        def call_service(service, args=None):service = resolve_name(service)...proxy = ServiceProxy(service, service_class)response = proxy.call(inst)...

同时rosbridge_server下的launch目录里有三个启动文件rosbridge_tcp.launch、rosbridge_udp.launch和rosbridge_websocket.launch供执行启动TCP server或UDP Server或WebSocket Server使用,他们执行的分别是scripts目录下的rosbridge_tcp.py、rosbridge_udp.py、rosbridge_websocket.py这个三个python文件(由.launch文件里的node定义中的type指定),这三个python文件分别启动对应的Server并把src/rosbridge_server目录下的tcp_handler.py、udp_handler.py、websocket_handler.py里分别定义的RosbridgeTcpSocket、RosbridgeUdpSocket、RosbridgeWebSocket三个类分别用作对应通讯方式的handler,对连接的建立/关闭、数据的收/发进行处理。

关于上面的TCP/UDP/Websocket三种通讯协议的实现该选用哪种好,我觉得这个需要根据你的系统的具体通讯需求来做选择,只需要短连接、可靠、单向、一对一(或者少量一对多)传输数据的话选用TCP即可,只需要单向、非可靠、一对多(一对一当然可以啦)传输数据的话选用UDP就行,对于要求频繁双向传输数据、尤其需要最好保持长连接的通讯需求,当然使用WebSocket是最好的选择。

机器人系统与外部系统之间的通讯一般都需要双向收发数据,并且经常需要保持长连接,对于这种需求,如果采用传统的TCP/UDP通讯来实现显然麻烦,双方都需要实现有Server和Client,并且需要维持两个连接来实现双向收发,因此采用WebSocket通讯是比较合理的。

启动Rosbridge的WebSocket Server需执行:

roslaunch rosbridge_server rosbridge_websocket.launch

前面说过,执行上面的launch文件会执行rosbridge_websocket.py启动一个WebSocket Server(这个Server是基于python的tornado的,默认端口是9090,可以在rosbridge_websocket.launch配置: )并且把websocket_handler.py里定义的RosbridgeWebSocket注册为handler处理连接的建立/关闭、数据的收/发等事件。RosbridgeWebSocket类继承自tornado.websocket.WebSocketHandler(在/usr/lib/python2.7/dist-packages/tornado/websocket.py里),它重新定义了几个主要方法用于上述事件的处理:

def open(self):self.protocol = RosbridgeProtocol(cls.client_id_seed, parameters=parameters)
...def on_close(self):
...def on_message(self, message):
...self.protocol.incoming(message)
...def send_message(self, message):
...

上面最重要的方法就是on_message(),它调用Protocol的incoming()以解析收到的JSON/BSON数据并根据op值调用对应的rosbridge_library/capbilities里的Capability子类的方法,进而调用ROS的功能API。

从上面可以看到,RosBridge WebSocket Server启动后在端口9090监听,外部系统可使用WebSocket Client创建一个WebSocket连接连到它上面,并且给它发送遵循rosbridge v2.0 Protocol Specification的JSON/BSON格式的数据,它就会对请求数据进行解析并调用对应的ROS API实现对机器人的控制,比如下面的数据是向/cmd_vel_mux/input/teleop主题发布一个twist消息控制机器人沿X轴方向向前移动一下:

{"op":"publish","id":"1","topic":"/cmd_vel_mux/input/teleop","msg":{"linear": {"x":1.0,"y": 0.0,"z": 0.0},"angular": {"x": 0.0,"y": 0.0,"z": 0.0}}}

当机器人有数据需要向外部系统发送时,使用同一WebSocket连接向外部系统主动发送数据。

ROSBridge简介以及理解使用相关推荐

  1. DL之DNN优化技术:神经网络算法简介之GD/SGD算法(BP的梯度下降算法)的简介、理解、代码实现、SGD缺点及改进(Momentum/NAG/Ada系列/RMSProp)之详细攻略

    DL之DNN优化技术:神经网络算法简介之GD/SGD算法(BP的梯度下降算法)的简介.理解.代码实现.SGD缺点及改进(Momentum/NAG/Ada系列/RMSProp)之详细攻略 目录 GD算法 ...

  2. BlockChain:《Blockchain Gate》听课笔记——区块链的共识机制—简介、理解、畅谈

    BlockChain:<Blockchain Gate>听课笔记--区块链的共识机制-简介.理解.畅谈 以下资源为各种渠道的网络收集和个人总结 目录 区块链--比特币中的共识机制 现阶段区 ...

  3. Java虚拟机JVM简介与理解(三)

    Java虚拟机JVM简介与理解(三) 问题背景 PC程序计数器 虚拟机栈 本地方法栈 堆 元空间 方法区 运行时常量池 直接内存 Lyric: 彻底把我囚禁在你的呼吸 问题背景 Java虚拟机JVM简 ...

  4. Interview之AI:人工智能领域岗位求职面试—人工智能算法工程师知识框架及课程大纲(AI基础之数学基础/数据结构与算法/编程学习基础、ML算法简介、DL算法简介)来理解技术交互流程

    Interview之AI:人工智能领域岗位求职面试-人工智能算法工程师知识框架及课程大纲(AI基础之数学基础/数据结构与算法/编程学习基础.ML算法简介.DL算法简介)来理解技术交互流程 目录 一.A ...

  5. 【转载】SOA 服务架构之简介及理解

    [转载]SOA 服务架构之简介及理解 自:https://blog.csdn.net/lch_2016/article/details/81062351 扩展阅读: SOA架构和微服务架构的区别:(推 ...

  6. 【元宇宙】元宇宙(metaverse)的简介(多角度理解与探讨)、发展历史、现状与未来

    High&NewTech:元宇宙(metaverse)的简介(多角度理解与探讨).发展历史.现状与未来 导读:博主曾在去年,2020年9月份撰写了一篇文章<AGI:走向通用人工智能的[哲 ...

  7. Java虚拟机JVM简介与理解(一)

    Java虚拟机JVM简介与理解(一) 问题背景 JVM(Java Virtual Machine) Java虚拟机JVM简介与理解(二) Lyric: 擦干是否就看不见你 问题背景 Java虚拟机JV ...

  8. Serverlet简介及理解

    Serverlet简介: Servlet(Server Applet),全称Java Servlet,未有中文译文.是用Java编写的服务器端程序.其主要功能在于交互式地浏览和修改数据,生成动态Web ...

  9. 物联网专业课程简介及理解

    写在前面:大家好,我是草莓橙须圆.毕业之前在CSDN和微信公众号活跃 欢迎关注我的公众号:[草莓橙须圆] 微信公众号主要就是更新大学生或者考研党的日常 CSDN主要就是学习过程中总结的笔记,以及编程分 ...

  10. SOA学习笔记001---SOA 服务架构之简介及理解

    SOA 英文: Service-Oriented Architecture,面向服务的架构. 是一种面向通用集成服务的.松耦合的架构实现方式,是web时代服务发展的产物: 使用"分层&quo ...

最新文章

  1. 为什么信不过AI看病?数据集小、可靠性差,AI医疗任重道远
  2. 判断整数小数_《除数是整数的小数除法》教学设计
  3. java找出两个字符串中所有共同的子串_【Java笔记】
  4. 设计模式:结构型模式总结
  5. 动态修改属性设置 easyUI
  6. mysql缺少函数_Sqlserver的窗口函数的精彩应用之数据差距与数据岛-答案篇
  7. 基于 HTML5 的 WebGL 3D 档案馆可视化管理系统
  8. ubuntu 文件管理器死机
  9. ACM模板——差分约束
  10. linux基本命令与终端操作、linux命令英文全称解释、ls clear cd pwd cat touch cp rm rmdir mkdir mv file find grep sudo su
  11. 《python自动化》学习笔记:正则表达式基础知识
  12. mybatis ${}使用注意事项
  13. 大数据笔记(三十一)——SparkStreaming详细介绍,开发spark程序
  14. 【多商户招商自营多元化功能】
  15. 如何删除电脑上的$RECYCLE.BIN文件夹
  16. 收集欢太积分可参与丰富的用户活动,还有丰厚的福利可以领取~
  17. cropper.js 实现HTML5 裁剪上传头像
  18. 网站推荐:archimy.com 在线函数图象绘制
  19. 2015西交C语言在线作业,西交19秋《程序设计基础(高起专)》在线作业
  20. gravity mysql_gravity 使用操作。

热门文章

  1. 31页智慧文旅云服务平台建设方案【附下载】
  2. Emacs键盘练习方法
  3. c语言奖学金评定系统课设报告,C语言编程奖学金评定系统太原理工大学.pdf
  4. mount –o remount,rw /
  5. HLG 1506 屠夫和狙击手【判断点在线段上+线段与圆相交】
  6. 基于html5的城市公交查询系统,本科毕业论文 城市公交查询系统
  7. jzoj1794 保镖排队 (树形dp)
  8. 计算机程序是指为解决某一问题,在计算机中为解决某一特定问题二设计的指令程序是...
  9. 万能DOS启动盘制作全攻略(转)
  10. WPF Resource资源