目录:
ROS通信
ROS中的多机器人通信
1.单个roscore和公共网络
2.群组/名称空间的使用
3.基于群组/名称空间的多机器人系统构建示例
多master概念简介
1.multimaster_fkie功能包简介
2.安装multimaster_fkie功能包
3.设置multimaster_fkie功能包
多机器人应用示例
ROS通信
下面介绍ROS中两个节点如何使用ROS话题相互通信。
图1.8展示了节点间通过话题进行通信的过程。如图1.8所示,有两个节点分别名为talker和listener。talker节点将名为Hello World的字符串消息发布到名为/talker的话题中,而listener节点订阅此话题。整个过程包含了三个阶段,在图中分别标记为(1)、(2)和(3),让我们看看每个阶段发生了什么:
(1):在运行ROS中的任何节点之前,我们首先启动master。启动后,它将等待其他节点。当talker节点(发布者)开始运行时,它将连接到master,并与master交换其所要发布话题的详细信息,包括话题名称、消息类型和发布节点URI。master的URI是一个全局值,所有节点都可以连接到它。master通过列表维护与其连接的发布者。每当发布者的详细信息发生更改时,列表将自动更新。
(2):当我们启动listener节点(订阅者)时,它将连接到master并交换节点的详细信息,例如要订阅的话题、其消息类型和节点URI。与发布者类似,master也维护一个订阅者列表。
(3):每当出现针对同一话题的订阅者和发布者时,master将进行订阅者和发布者URI的交换,帮助两个节点建立连接和交换数据。订阅者和发布者建立连接后,就不需要master的角色了。数据并不流经master,而是直接在相互连接的节点间交换消息。
ROS中的多机器人通信
ROS系统是一个分布式计算环境,它不仅可以在一台机器上运行多个节点,而且可以在多台相互通信的机器上运行,只要这些机器在同一个网络上。这一功能特性在机器人应用中十分有用,因为某些传感器需要复杂的机器进行支撑。
例如,如果我们有一个移动机器人通过其传感器(如超声波传感器和摄像头)感知环境,那么它可能需要一个简单的处理器,用来与超声波传感器所连接的微控制器进行串行通信。但是像摄像头这样的传感器可能需要更复杂的处理器来处理其信息。我们可以利用AWS或Google Cloud等云服务来处理摄像头数据,而不是使用高端计算硬件(通常成本高昂,有的体积庞大)。
这个系统所需要的就是一个良好的无线连接。超声波传感器节点可以在机器人上的简单计算机中运行,摄像头图像处理节点可以在高性能的云上运行,并通过无线通信与机器人的计算机通信(需要注意的是,摄像头节点将位于机器人的简单计算机上)。下面让我们学习如何用ROS在多个机器人或机器之间建立通信。
1.单个roscore和公共网络
在同一网络中建立不同机器之间通信的最简单方法是通过网络配置进行通信建立。让我们考虑图6.2所示的示例。
假设这个例子是一个工业4.0用例。机器人有一台计算机负责其控制和移动操作,机器人与服务器计算机共享其状态和运行状况,服务器计算机分析机器人的运行状况,并帮助预测事件或机器人本身可能发生的故障。机器人和服务器计算机都在同一个网络中。
为了让ROS理解它们并在它们之间进行通信,我们假设服务器计算机是主计算机(即master)。因此,roscore将在服务器计算机上运行,机器人上的计算机将向这个ROS master提供任何必要的话题信息。要实现这一点,我们需要为每个计算机分别设置主机名和IP,以帮助区分两者并帮助它们彼此通信。假设服务器计算机的IP为192.168.1.1,机器人上计算机的IP为192.168.1.2,roscore运行在服务器计算机上,机器人上的计算机连接到服务器计算机上,在每个计算机系统中设置以下环境变量。
在服务器计算机上,使用以下命令设置:
$ export ROS_MASTER_URI=http://192.168.1.1:11311 $ export ROS_IP=http://192.168.1.1
在机器人计算机上,使用以下命令设置:
$ export ROS_MASTER_URI=http://192.168.1.1:11311 $ export ROS_IP=http://192.168.1.2
那么,上述命令的作用是什么呢?实际上,通过上述命令,我们将ROS_MASTER_URI设置成了服务器计算机的IP,并且连接网络上的其他计算机(例如我们的机器人计算机),以便它们连接到特定的ROS master上。此外,为了帮助区分不同的计算机,我们通过ROS_IP环境变量为计算机设置显式名称。
Tips:也可以使用ROS_HOSTNAME来代替ROS_IP,参数值为在/etc/hosts下定义为条目的机器人名称。相应的参考示例网址为http://www.faqs.org/docs/securing/chap9sec95.html。可以将前面的环境变量条目直接复制到对应的bash文件中,以避免每次新打开一个终端时都需要重新调用相应变量值。
有时可能发生时间和话题同步的问题,可能还会看到一个关于未来外推的TF警告。这些通常是计算机系统时间不匹配的结果(即时间不同步)。
可以通过ntpdate工具来进行确认,安装命令为:
$ sudo apt install ntpdate
执行以下命令来测试其他计算机的时间:
$ ntpdate -q 192.168.1.2
如果存在不匹配的问题,则需要通过以下命令安装chrony来进行匹配处理:
$ sudo apt install chrony
可以通过编辑机器人计算机上的配置文件来获取服务器计算机上的时间,方法为通过以下命令来修改/etc/chrony/chrony.conf:
$ server 192.168.1.1 minpoll 0 maxpoll 5 maxdelay .05
Tips:可以从https://chrony.tuxfamily.org/manual.html了解更多信息。
公共网络问题
现在,我们知道了如何在同一网络中不同机器上的节点之间进行通信。但是,如果不同机器上的节点具有相同的话题名称,那该怎么办?考虑图6.3所示的示例。
对于一个移动机器人而言,move_base节点需要传感器和地图信息来通过cmd_vel命令给出轨迹点。如果我们计划在应用程序中使用另一个移动机器人,则由于两个机器人位于同一网络中,因此它们之间可能具有相同的通信话题,而这将导致通信冲突。两个机器人可能会尝试执行相同的命令并执行相同的操作,而不是单独执行任务。这是使用通用ROS网络的主要问题之一。机器人无法理解哪一个是自己的控制动作,因为它们在网络中具有相同的话题名称。我们将在下一节中学习如何克服这种情况。
2.群组/名称空间的使用
如果读者较为深入地学习过ROS在线教程,就会知道如何解决这个问题。让我们考虑以turtlesim为例来看待这个问题。使用以下命令启动turtlesim节点:
打开一个终端窗口,执行以下命令:
$ initros1 $ roscore
打开另一个终端窗口,执行以下命令:
$ initros1 $ rosrun turtlesim turtlesim_node
检查rostopic列表来查看cmd_vel以及turtle1的位姿信息。下面来通过以下命令在GUI下创建另一个turtle:
$ rosservice call /spawn 3.0 3.0 0.0 turtle2
执行上述命令将会发生什么情况呢?我们生成了一个新的turtle,并且具有相同的话题名称,但是添加了一个前缀/turtle2。这在ROS中称为名称空间技术,主要用于多机器人场景。现在,我们重新定义了图6.3中的示例,使其变成了图6.4所示的样子。
由图6.4可见,每个机器人都有自己的话题,分别以机器人名称作为前缀。机器人之间也可能有一些共同的话题,比如/map话题,这是因为两个机器人都在同一个环境中。在下一节中,我们将学习如何将这个名称空间技术用于我们在第3章中创建的机器人上。
3.基于群组/名称空间的多机器人系统构建示例
下面介绍如何以第3章中构建的移动机器人底座为基础,构建多机器人系统。可以从https://github.com/PacktPublishing/ROS-Robotics-Projects-SecondEdition/tree/master/chapter_3_ws/src/robot_description下载工作空间。将上述文件下载到一个新的工作空间并编译。通过以下命令启动机器人底座:
$ initros1 $ roslaunch robot_description base_gazebo_control.xacro.launch
读者将会在Gazebo中看到机器人底座模型,如图6.5所示。
现在,我们的目的是在Gazebo上“繁殖”另一个机器人,因此我们把机器人命名为robot1和robot2。在前面的base_gazebo_control.xacro.launch文件中,我们将加载了机器人和控制器配置的空Gazebo世界发送到ROS服务器并加载控制器节点。这里我们也需要这么做,但目标不止一个机器人。为此,我们将在名称空间群组标签下启动机器人。在加载机器人的URDF时,我们需要确保使用tf_prefix参数和<robot_name>前缀来区分不同的机器人变换。
最后,我们必须在加载控制器时使用ns参数,并且在启动控制器节点时使用--namespace参数来区分每个机器人的控制器。这些更改可以应用于robot1,如下所示:
<group ns="/robot1"> <param name="tf_prefix" value="robot1" /> <rosparam file="$(find robot_description) /config/control.yaml" command="load" ns="/robot1" /> <param name="/robot1/robot_description" command="$(find xacro)/xacro --
inorder $(find robot_description)/urdf/robot_base.urdf.xacro nsp:=robot1"/> <node name="urdf_spawner_1" pkg="gazebo_ros" type="spawn_model" args="-x -1.0 -y 0.0 -z 1.0 -unpause -urdf -model robot1 -param robot_description " respawn="false" output="screen"> </node> <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher_1"> <param name="publish_frequency" type="double" value="30.0" /> </node> <node name="robot1_controller_spawner" pkg="controller_manager" type="spawner" args="--namespace=/robot1 robot_base_joint_publisher robot_base_velocity_controller --shutdown-timeout 3"> </node> </group>
如果要启动两个机器人,则只需将上述代码块复制并粘贴两次,然后在第二个复制的代码块中将robot1替换为robot2。可以随心所欲地创建多个块。为了简单起见,我们将此代码块移动到另一个名为multiple_robot_base.launch的启动文件中。启动两个这样的机器人的完整代码可以在GitHub上找到(网址为https://github.com/PacktPublishing/ROS-Robotics-Projects-SecondEdition/blob/master/chapter_6_ws/src/robot_description/launch/multiple_robot_base.launch)。主启动文件位于GitHub上的robotbase_simulation.launch下,该文件启动Gazebo空世界和multiple_robot_base启动文件。
启动两个机器人后,窗口如图6.6所示。
rostopic列表如图6.7所示。
Tips:需要说明的是,上述示例仅为群组标签的简单应用演示,并且不是群组的唯一表示方法。读者可以尝试通过合适的变量和循环来创建自己的多机器人系统。
至此,我们使用名称空间构建了多机器人系统并且启动了该系统,下面介绍这种方法的局限性。
使用群组/名称空间存在的问题
虽然群组/名称空间的方法确实达到了在同一类型机器人之间通信的目的,但在使用这项技术时还存在一些局限性。例如,当我们的机器人加载了一些特性时,对它们进行设置可能会很有挑战性,因为在这些特性中,我们必须尝试为机器人附带的几乎所有启动文件提供名称空间。这一过程将会耗费大量时间,而且安装过程会很棘手。如果设置不当,则还可能会导致混乱,因为在出现问题时,系统不会提供任何诊断或异常提示。
假设读者计划购买一个机器人底座,如Husky或TurtleBot。要同时使用它们,需要为每个机器人设置封装文件(必需的名称空间启动文件)。我们选择使用某一型号的机器人底座的原因在于它们具备开箱即用的特性,我们希望不需要专门为自己的应用程序进行功能包设置。但是,我们最终需要在可用文件的基础上创建其他文件,这将需要更多的开发时间。此外,通过群组/名称空间的方法,rostopic列表将加载一个带有特定机器人名称前缀的复杂话题列表。如果只想控制机器人中选定的话题,并将其显示给主master,这时该怎么办?如果我们还需要知道机器人在网络中的连接状态,比如哪些处于连接状态、哪些处于断开状态呢?
对于上述问题,我们将在接下来给出解决方案。
多master概念简介
为了理解多master的概念,让我们考虑一个工业用例,如图6.8所示。
假设我们有类似移动机械臂的机器人(如我们在第3章中创建的工业移动机械臂)来装卸货物,并且至少有5个这样的机器人在进行该工作。另外,假设有一些机械臂与机器一起工作,用于操作应用,例如将材料装载到加工区,然后装载到传送带上,卸载产品以进行配送。最后,还有一个*系统用于监控所有这些机器人的任务和健康状况。对于这样的工业用例,将会有多个本地网络连接到一个公共网络(即*系统所在的位置)。
ROS中定义了相应的机制来帮助我们实现上述多机器人协作的需求,ROS提供了通用的工具用于在ROS子系统间进行通信。该工具为名为multimaster_fkie的功能包。
1.multimaster_fkie功能包简介
multimaster_fkie功能包包括两个主要的节点:
·master_discovery节点。
·master_sync节点。
master_discovery节点帮助我们检测网络中的其他ROS master,识别网络中的任何更改,并与其他ROS master共享这些更改。master_sync节点帮助其他ROS master将其话题和服务与本地ROS master同步。multimaster_fkie功能包能够有效地帮助同一网络中的ROS master只与同一网络共享必要的话题信息,并将其他丰富的话题信息保存在本地网络中。
下面我们将通过一些例子来帮助读者理解multimaster_fkie功能包的安装、设置和使用过程。
Tips:可以从http://wiki.ros.org/multimaster_fkie了解更多有关multimaster_fkie的信息。
2.安装multimaster_fkie功能包
我们通过源的方式安装multimaster_fkie功能包,步骤如下:
1)在系统中安装pip工具,命令如下:
$ sudo apt install python-pip
2)安装pip之后,将多master代码仓库复制到我们的工作空间中,并编译构建我们的功能包,命令如下:
$ cd chapter_6_ws/src $ git clone https://github.com/fkie/multimaster_fkie.git multimaster $ rosdep update $ rosdep install -i --as-root pip:false --reinstall --from-paths multimaster
运行上述命令后,读者将会遇到并接受几次依赖项安装提示,请确保接受了所有的依赖项安装请求,因为安装依赖项之后才能编译构建工作空间。
3)这里我们使用catkin_make_isolated命令构建工作空间,该命令将分别构建功能包,而不是将其构建为一个功能包,命令如下:
$ cd .. $ catkin_build_isolated
执行上述步骤后,我们就完成了功能包的安装,下面让我们体验一下该功能包的使用。
3.设置multimaster_fkie功能包
进行multimaster_fkie功能包设置的最佳方法是在两个系统中分别运行以下示例,主要包含三个步骤:
1)设置主机名和IP地址。
2)检查并启用多播功能。
3)设置检查与测试。
下面详细介绍每个步骤。
1.设置主机名和IP地址
假设我们有两个系统,分别命名为pc1和pc2,下面按照以下步骤进行系统设置:
1)在pc1上,进入/etc/hosts文件并做以下修改:
127.0.0.1 localhost 127.0.0.1 pc1 192.168.43.135 pc1 192.168.43.220 pc2
2)在pc2上,进入/etc/hosts文件并做以下修改:
127.0.0.1 localhost 127.0.0.1 pc1 192.168.43.135 pc1 192.168.43.220 pc2
由于上述文件位于系统文件夹下,因此对其修改需要sudo权限。
3)读者应当还记得,前面的示例中添加了ROS_MASTER_URI和ROS_IP。让我们对每台计算机使用各自的IP和ROS_MASTER_URI在各自的bash脚本中执行相同的操作,具体参考步骤4。
4)使用命令$sudo gedit~/.bashrc打开bash脚本文件,操作如下:
- 在pc1的bash脚本文件中使用如下代码:
export ROS_MASTER_URI=http://192.168.43.135 export ROS_IP=192.168.43.135
- 在pc2的bash脚本文件中使用如下代码:
export ROS_MASTER_URI=http://192.168.43.220 export ROS_IP=192.168.43.220
在此基础上,让我们检查并启用多播功能。
2.检查并启用多播功能
要在多个roscore之间进行同步处理,需要检查每台计算机上是否启用了多播功能。该功能在Ubuntu中通常被禁用。要检查它是否已启用,需要使用以下命令:
$ cat /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
如果该值为0,则表示启用了多播功能;如果值为1,则需要使用以下命令将该值重置为0:
$ sudo sh -c "echo 0 >/proc/sys/net/ipv4/icmp_echo_ignore_broadcasts"
启用后,使用以下命令检查多播IP地址:
$ netstat -g
标准的IP通常是220.0.0.x,因此在每台计算机中ping该IP以查看计算机之间是否正在进行通信。在本书的例子中,我们的多播IP是220.0.0.251,因此220.0.0.251是两台计算机中检查连接的ping地址:
$ ping 220.0.0.251
下面让我们对上述设置进行检查和测试。
3.设置检查与测试
在每个终端窗口中,分别启动roscore:
$ initros1 $ roscore
现在,转到相应的multimaster_fkie功能包文件夹,在每台计算机上运行以下命令:
$ rosrun fkie_master_discovery master_discovery _mcast_group:=220.0.0.251
在上述命令中,_mcast_group的数值是我们使用netsat命令获得的多播IP地址。
如果网络设置正确,则应看到master_discovery节点标识了每台计算机中的roscore,如图6.9所示。
现在,要在每台ROS master的话题之间进行同步,需要在每台计算机中运行master_sync节点。如我们所见,multimaster_fkie功能包已经设置好。让我们用一个示例来试着更好地理解这一点。
多机器人应用示例
让我们试着从一台PC上启动机器人模拟,并在另一台PC上用遥控器控制机器人。我们将使用在6.4.3节给出的示例中设置的机器人。假设前面的设置没有变化,让我们运行在一台PC上启动的多机器人,命令如下:
1)在pc1上,运行以下命令:
$ initros1 $ roslaunch robot_description robotbase_simulation.launch
2)打开新的终端窗口,启动master_discovery节点,命令如下:
$ initros1 $ source devel_isolated/setup.bash $ rosrun fkie_master_discovery master_discovery _mcast_group:=224.0.0.251
3)打开新的终端窗口,启动master_sync节点,命令如下:
$ initros1 $ source devel_isolated/setup.bash $ rosrun fkie_master_sync master_sync
现在,在pc2上运行必要的命令。我们假设已经在pc2的终端窗口中启动了roscore,下一步是在新的终端窗口中分别启动master_discovery节点和master_sync节点,具体命令见步骤4、5。
4)打开新的终端窗口,执行以下命令:
$ initros1 $ rosrun fkie_master_discovery master_discovery _mcast_group:=224.0.0.251
5)再次打开新的终端窗口,执行以下命令:
$ initros1 $ rosrun fkie_master_sync master_sync
进行了话题同步后,我们将会看到一个窗口,如图6.10所示。
6)执行$rostopic list命令,可以看到/robot1和/robot2的话题同步了。尝试使用以下带有适当话题名称的命令移动机器人。我们应该看到机器人在移动。
$ rosrun rqt_robot_steering rqt_robot_steering
模拟窗口中机器人运动的简单表示如图6.11所示。
如果需要选择特定话题进行同步,请查看master_sync.launch文件以获取必要的参数列表。可以通过使用ROS参数(rosparam)sync_topics指定所需的话题来完成此操作。