在ROS1中由主节点(master)负责其它从节点的通信,在同一局域网内通过设置主节点地址也可以实现多机通讯,但是这种多机通讯网络存在一个严重的问题,那就是所有从节点强依赖于主节点,一旦运行主节点的设备离线,整个网络就完全瘫痪了,在ROS2中取消了主节点,通讯系统是基于DDS(Data Distribution Service)实现的,具有实时性、嵌入式、分布式、支持多操作系统等特性,下文我们将简单介绍ROS2多机通讯的配置方式。

ROS2本身就是一个分布式通信框架,局域网内多台机器上的节点默认即可实现互相通信,而实际控制节点是否可以互相通信是通过域ID(ROS_DOMAIN_ID)来控制的,同一域内的ROS2节点之间可以自由发现和发送消息,而不同域内的ROS2节点之间则不能。所有ROS2节点默认使用域 ID 0,所以默认即可互相通信,关于域ID的设置,我们需要了解以下概念:

1)ROS2底层通讯机制基于DDS实现,而DDS是基于UDP/IP或者TCP/IP网络通信协议实现的;

2)无论是TCP还是UDP网络协议,在通讯时都需要指定一个网络端口;

3)网络端口是一个16位的无符号整数,也就是说网络端口最大就是65535;

4)ROS2节点发现机制是基于局域网组播实现的,一收一发需要两个端口,ROS2节点间通信是基于局域网单播实现的,一收一发又需要两个端口,组播端口域内节点共享,单播端口节点私有;

5)DDS协议约定以7400为起始端口,每个域默认占用250个端口,所以局域网内域的数量最多为(65535-7400)/250=232个,所以域ID取值范围为0-231;

6)DDS协议约定每个域端口段内,第1、2个端口是域内组播端口,第11、12个端口是域内第一个节点的单播端口,第12、13个端口是域内第二个节点的单播端口,以此类推,第239、240个端口是域内第120个节点的单播端口;

由以上叙述可以推断出以下结论:

1)ROS_DOMAIN_ID为0的域有以下设定:

  • 组播端口为7400,7401
  • 第1个节点单播端口是7410,7411
  • 第2个节点单播端口是7412,7413
  • ……
  • 第120个节点的单播端口是7648,7649
    2)ROS_DOMAIN_ID为1的域有以下设定:

  • 组播端口为7650,7651

  • 第1个节点单播端口是7660,7661
  • 第2个节点单播端口是7662,7663
  • ……
  • 第120个节点的单播端口是7898,7899

    由以上结论,我们可以发现,如果ID为0的域内有第121个节点,该节点单播端口将会与域1的组播端口冲突,所以我们在使用的过程中,要注意节点数量超过120的情况,如果节点数量超了,向上相邻的域就不可用了。

    除了相邻域的冲突问题,还有与系统设定冲突问题也需要注意,不同的操作系统默认会预留一些端口段做为临时端口使用(详细内容请参考官方文档),为了防止端口冲突,这些预留端口在ROS2中也需要避开,避开的结果就是在linux系统中可用域ID为0-101和215-232,在windows和macOS中可用域ID是0-166,为了多平台兼容通讯,我们一般域ID使用0-101,而101域后半段的端口被系统预留,所以101域节点数上限为54个。

在多机通讯需求中,如果只有一个组,我们可以默认使用域ID为0即可,如果要修改默认域ID,在linux终端执行以下命令(设定ROS_DOMAIN_ID为5):

$ export ROS_DOMAIN_ID=5

执行后,该终端内启动的节点被分配到ID为5的域内,如果该机器内所有节点都需要分配到同一个域内,则可以通过以下命令统一设定域ID:

$ echo "export ROS_DOMAIN_ID=5" >> ~/.bashrc

重启终端,所有终端内启动的节点都默认分配到ID为5的域内。

windows和macOS系统设定请参考官网说明

我们还利用官方demo来测试一下,开启3个终端,其中两个终端分别设定ROS_DOMAIN_ID为5和6,都启动listener节点,另1个终端设定ROS_DOMAIN_ID为5,启动talker节点:

图中可见,域ID相同的节点间可以互相通讯,ID不同的节点之间消息是不通的。