最近写了一个无线网络环境下(比如WIFI)多机ROS通信的项目swarm_ros_bridge:
https://gitee.com/shu-peixuan/swarm_ros_bridge
A lightweight middle interface that enables specified ROS message transmission among swarm robots through socket communication
本项目基于ZeroMQ,用于取代现有ROS1和ROS2多机通信配置,能够灵活地将任意本机ROS话题发送到其他机器人,或者读取其他机器人的话题。
目录
一、ROS多机通信现状
1、ROS1 自带的组网通信
2、ROS2自带的组网通信
3、自己写TCP/UDP的socket通信
二、基于ZeroMQ的通信中间件开发
三、swarm_ros_bridge
一、ROS多机通信现状
集群ROS机器人通过无线网络(WIFI、带网口的数传)进行多机通信,常用的应用层传输方法有:
1、ROS1 自带的组网通信
通过设置ROS_MASTER_URI使得所有机器人都连接到某一个主机的ROS master上,共享所有的ROS话题,底层是TCP协议和xmlRPC集中式节点发现机制)。缺点:
- 设置繁琐:每个机器人都要在/etc/hosts里设置IP, ~/.bashrc里设置ROS_MASTER_URI, ROS_HOSTNAME。
- 不灵活:必须主机的roscore先启动,其他机器人的ROS节点后启动。
参考:
ROS/Technical Overview - ROS Wiki
ROS机器人操作系统底层原理及代码剖析_robinvista的博客-CSDN博客_ros源码分析
2、ROS2自带的组网通信
ROS2默认采用分布式的fast DDS通信架构。由于取消了ROS master中心节点,改用分布式的节点发现机制,ROS2的多机通信不需要设置主从机,设置简便了许多:
export ROS_DOMAIN_ID=5
保证同一局域网下的各个机器人的ROS_DOMAIN_ID相同即可。缺点:
- 不灵活:和ROS1一样,所有ROS话题都被传输,不能选择需要被传输的话题。
- 不可靠:fast DDS 默认采用UDP通信协议,无线通信时不如TCP可靠(因为DDS一般是为本机多个进程间的数据交换开发的,而不是多机无线通信场景)。
参考:
ROS2之DDS问题汇集_zhangrelay的博客-CSDN博客_failed to find a free participant index for domain
ROS2官方教程:ROS2中不同的DDS/RTPS vendors_P2Tree的博客-CSDN博客
ZMQ vs eProsima Fast RTPS
3、自己写TCP/UDP的socket通信
采用sys/socket.h等库,自己写TCP或者UDP的socket通信代码,将ROS消息转换为TCP数据流发送到指定的机器人。其中TCP要求建立两者连接后才能收发数据,UDP则只负责发送数据和读取数据,而不管对方是否在线或接收到。缺点:
- 代码复杂:直接操作socket套件字过于底层,代码工作量很大,你要为每一个连接创建一个socket套接字,并全程管理绑定、监听、连接、接收等。
- ”面向连接“而非”面向数据“:socket通信是面向连接的,而非ROS1/ROS2那样面向数据的,这意味着你需要为每两个机器人之间的通信都写一段连接的代码,不具有集群的扩展性。
- 启动顺序有限制:和ROS1一样,TCP协议要求服务器端先启动,客户端后启动。而且不具备断线重连的功能。
C++ Socket实现TCP与UDP网络编程_C 语言_脚本之家
为了避免重复造轮子,我调研了一些现有的把ros话题消息转换成TCP/UDP数据流的项目:
rosbridge_suite - ROS Wiki : Rosbridge provides a JSON API to ROS functionality for non-ROS programs.它主要是面向网页或者其他应用端和ros通信用,不是多机通信用。
rosserial - ROS Wiki :rosserial is a protocol for wrapping standard ROS serialized messages and multiplexing multiple topics and services over a character device such as a serial port or network socket. 它是读取串口的ROS包,也支持TCP端口读取,但是主要针对简单的读取一个固定TCP端口消息。
udp_com : 一个通用的以ROS形式读取和发送udp消息。提供了create_socket_service和send_service两个service用来创建接收套接字和发送消息,但是只能用他指定的ROS话题类型。
ros_udp_bridge : 用poco net库里的socket创建ROS读取和发送话题,但只是读取一个特定话题的简单项目。
综上,现在并没有可以好用的针对集群无线通信的ROS包。
二、基于ZeroMQ的通信中间件开发
其实ROS1和ROS2里的话题机制就是一种通信中间件,“通信中间件”是介于通信架构“传输层”和”应用层“之间的一层,将传输层的socket通信连接等设置封装成一些简单的API供应用层调用,从而使得应用开发人员不需要关注繁琐的TCP/UDP socket设置。
OSI 模型与TCP/IP、以太网、DDS - 知乎
通讯协议篇(底层TCP/UDP;上层MQTT、HTTP、CoAP、DDS、AMQP、JMS) | 码农家园
ROS1是自己搭建了一套xmlRPC集中式机制来建立节点之间的TCP连接,ROS2则是直接用了fast DDS中的分布式fast RTPS机制。如果我们不用ROS1和ROS2自带的中间件,就意味着我们需要自己写一个通信中间件,来实现集群机器人之间的通信连接。
好在还有一些其他的通信中间件可供我们使用,其中比较著名的就是ZeroMQ:
ZeroMQ | Socket API
ØMQ中文翻译文档_我不掉头发的博客-CSDN博客
zmqpp: zmqpp Namespace Reference
zeroMQ是一个主要用于TCP通信的中间件,基于C但也提供C++、python等封装。它将socket通信连接全部封装好,而留出一些”面向数据“的API接口供我们调用。
ZeroMQ提供的接口延用了socket的名字,比如socket::bind(),socket::connect(),socket::send(), socket::receive(),但是没有socket::listen()和socket::accept(),因为它提供的socket不是面向连接而是面向数据的,为要传输的每一个数据创建一个套接字即可,而不需要关心底层的socket连接问题。因此它不要求服务器先启动、客户端后启动,而是会自动连接、断线重连。
ZeroMQ提供的几种socket模式很像ROS,比如
Request-reply :类似于ROS的service。
Pub-sub : 类似于ROS的topic。
Pipeline :类似于ROS的topic,但是其push/pull的模式会阻塞发送端,不会丢弃发送的数据。
将zeroMQ用于ROS消息传输的项目也有一些,比如:
zmqros : 2015年的项目,过于陈旧,功能不完善。
ros_zeromq_tutorial : 只是一个简单的zeromq使用示例,并没有转化成ros话题。
综上,现在并没有可以好用的zeroMQ来传输ROS消息的项目。
三、swarm_ros_bridge
swarm_ros_bridge: A lightweight middle interface that enables specified ROS message transmission among swarm robots through socket communication
针对以上问题,我基于ZeroMQ开发了一个轻量化的ROS包,可以将任意ROS话题发送到其他机器人实现多机通信。只需要将你需要发送或接收的ROS话题信息写在ros_topics.yaml文件里。
核心工作:
利用ROS1自带的serialization对ROS话题消息进行序列化和反序列化,然后利用zeroMQ的PUB/SUB模式将消息发送,并为每个ROS接收话题建立一个接收线程。
与ROS1多机器人无线通信相比,它具有以下优点:
- 鲁棒:无需先启动基站ROS主站。支持每个机器人以随机顺序启动并自主连接。
- 灵活:您可以选择发送/接收 ROS 话题,而不是像 ROS1 那样传输所有话题。
- 易于使用:在一个配置文件中指定所有IP和ROS话题。
与ROS2 DDS通信相比,它具有以下优点:
- 轻量化:是一个订阅和发送远程ROS主题的小型ROS桥接节点,因此很容易与其他ROS1节点对接。
- 可靠:它使用基于TCP协议的zmq套接字通信,而ROS2基于DDS,其默认协议为UDP(无法实现)。事实上,DDS主要用于有线通信下的本机进程之间的数据交换,而不是远程无线通信。
未来改进:
- 动态RPC,包括动态节点发现、在线主题变更和地面站监控。
- 支持UDP协议,用于视频流等大量数据传输。