机器人是一种高度复杂的系统性实现,一个完整的机器人应用程序可能由若干功能模块组成,每个功能模块可能又包含若干功能点,在不同功能模块、不同功能点之间需要频繁的进行数据交互。比如以导航中的路径规划模块为例:
- 路径规划时就需要其他功能模块输入数据,并输出数据以被其他模块调用。
- 输入的数据有地图服务提供的地图数据、定位模块提供的机器人位姿数据、人机交互模块提供的目标点数据......。
- 输出的路径信息则被运动控制订阅或是回显在人机交互界面上。
那么这些相对独立的功能模块或功能点之间是如何实现数据交互的呢?在此,我们就需要介绍一下ROS2中的通信机制了。
本章概览
案例演示
案例1:话题通信示例——发布订阅简单的文本消息。
案例2:话题通信示例——发布自定义消息。
案例3:服务通信示例——求和。
案例4:动作通信示例——带有连续反馈的求和。
案例5:参数操作示例。
2.1 通信机制简介
在ROS2中通信方式虽然有多种,但是不同通信方式的组成要素都是类似的,比如:通信是双方或多方行为、通信时都需要将不同的通信对象关联、都有各自的模型、交互数据时也必然涉及到数据载体等等。本节将会介绍通信中涉及到的一些术语。
1.节点在通信时,不论采用何种方式,通信对象的构建都依赖于节点(Node),在ROS2中,一般情况下每个节点都对应某一单一的功能模块(例如:雷达驱动节点可能负责发布雷达消息,摄像头驱动节点可能负责发布图像消息)。一个完整的机器人系统可能由许多协同工作的节点组成,ROS2中的单个可执行文件(C++程序或Python程序)可以包含一个或多个节点。
2.话题话题(Topic)是一个纽带,具有相同话题的节点可以关联在一起,而这正是通信的前提。并且ROS2是跨语言的,有的节点可能是使用C++实现,有的节点可能是使用Python实现的,但是只要二者使用了相同的话题,就可以实现数据的交互。
3.通信模型不同的通信对象通过话题关联到一起之后,以何种方式实现通信呢?在ROS2中,常用的通信模型有四种:
1.话题通信:是一种单向通信模型,在通信双方中,发布方发布数据,订阅方订阅数据,数据流单向的由发布方传输到订阅方。
2.服务通信:是一种基于请求响应的通信模型,在通信双方中,客户端发送请求数据到服务端,服务端响应结果给客户端。
3.动作通信:是一种带有连续反馈的通信模型,在通信双方中,客户端发送请求数据到服务端,服务端响应结果给客户端,但是在服务端接收到请求到产生最终响应的过程中,会发送连续的反馈信息到客户端。
4.参数服务:是一种基于共享的通信模型,在通信双方中,服务端可以设置数据,而客户端可以连接服务端并操作服务端数据。
4.接口在通信过程中,需要传输数据,就必然涉及到数据载体,也即要以特定格式传输数据。在ROS2中,数据载体称之为接口(interfaces)。通信时使用的数据载体一般需要使用接口文件定义。常用的接口文件有三种:msg文件、srv文件与action文件。每种文件都可以按照一定格式定义特定数据类型的“变量”。
1.msg文件
msg文件是用于定义话题通信中数据载体的接口文件,一个典型的.msg文件示例如下。
在文件中声明了一些被传输的类似于C++变量的数据。
2.srv文件
srv文件是用于定义服务通信中数据载体的接口文件,一个典型的.srv文件示例如下。
文件中声明的数据被---分割为两部分,上半部分用于声明请求数据,下半部分用于声明响应数据。
3.action文件
action文件使用用于定义动作通信中数据载体的接口文件,一个典型的.action文件示例如下。
文件中声明的数据被---分割为三部分,上半部分用于声明请求数据,中间部分用于声明响应数据,下半部分用于声明连续反馈数据。
4.变量类型
不管是何种接口文件,在文件中每行声明的数据都由字段类型和字段名称组成,可以使用的字段类型有:
- int8, int16, int32, int64 (或者无符号类型: uint*)
- float32, float64
- string
- time, duration
- 其他msg文件
- 变长数组和定长数组
ROS中还有一种特殊类型:Header,标头包含时间戳和ROS2中常用的坐标帧信息。许多接口文件的第一行包含Header标头。
另外,需要说明的是:
准备工作1.请先创建工作空间ws01_plumbing,本章以及第3章代码部分内容存储在该工作空间下。
2.实际应用中一般建议创建专门的接口功能包定义接口文件,当前教程也遵循这一建议,预先创建教程所需使用的接口功能包(需要注意的是,目前为止无法在Python功能包中定义接口文件),终端下进入工作空间的src目录,执行如下命令:
该功能包将用于保存本章教程中自定义的接口文件。
2.2 话题通信
场景话题通信是ROS中使用频率最高的一种通信模式,话题通信是基于发布订阅模式的,也即:一个节点发布消息,另一个节点订阅该消息。话题通信的应用场景也极其广泛,比如如下场景:
在该场景中,就不止一次使用到了话题通信。
- 以激光雷达信息的采集处理为例,在ROS中有一个节点需要时时的发布当前雷达采集到的数据,导航模块中也有节点会订阅并解析雷达数据。
- 再以运动消息的发布为例,导航模块会综合多方面数据实时计算出运动控制信息并发布给底盘驱动模块,底盘驱动有一个节点订阅运动信息并将其转换成控制电机的脉冲信号。
以此类推,像雷达、摄像头、GPS.... 等等一些传感器数据的采集,也都是使用了话题通信,话题通信适用于不断更新的数据传输相关的应用场景。
概念话题通信是一种以发布订阅的方式实现不同节点之间数据传输的通信模型。数据发布对象称为发布方,数据订阅对象称之为订阅方,发布方和订阅方通过话题相关联,发布方将消息发布在话题上,订阅方则从该话题订阅消息,消息的流向是单向的。
话题通信的发布方与订阅方是一种多对多的关系,也即,同一话题下可以存在多个发布方,也可以存在多个订阅方,这意味着数据会出现交叉传输的情况,当然如果没有订阅方,数据传输也会出现丢失的情况。
作用话题通信一般应用于不断更新的、少逻辑处理的数据传输场景。关于消息接口关于消息接口的使用有多种方式:
- 在ROS2中通过std_msgs包封装了一些原生的数据类型,比如:String、Int8、Int16、Int32、Int64、Float32、Float64、Char、Bool、Empty.... 这些原生数据类型也可以作为话题通信的载体,不过这些数据一般只包含一个 data 字段,而std_msgs包中其他的接口文件也比较简单,结构的单一意味着功能上的局限性,当传输一些结构复杂的数据时,就显得力不从心了;
- 在ROS2中还预定义了许多标准话题消息接口,这在实际工作中有着广泛的应用,比如:sensor_msgs包中定义了许多关于传感器消息的接口(雷达、摄像头、点云......),geometry_msgs包中则定义了许多几何消息相关的接口(坐标点、坐标系、速度指令......);
- 如果上述接口文件都不能满足我们的需求,那么就可以自定义接口消息;
具体如何选型,大家可以根据具体情况具体分析。
2.2.1 案例以及案例分析
1.案例需求需求1:编写话题通信实现,发布方以某个频率发布一段文本,订阅方订阅消息,并输出在终端。
需求2:编写话题通信实现,发布方以某个频率发布自定义接口消息,订阅方订阅消息,并输出在终端。
2.案例分析在上述案例中,需要关注的要素有三个:
- 发布方;
- 订阅方;
- 消息载体。
案例1和案例2的主要区别在于消息载体,前者可以使用原生的数据类型,后者需要自定义接口消息。
3.流程简介案例2需要先自定义接口消息,除此之外的实现流程与案例1一致,主要步骤如下:
- 编写发布方实现;
- 编写订阅方实现;
- 编辑配置文件;
- 编译;
- 执行。
案例我们会采用C++和Python分别实现,二者都遵循上述实现流程。
4.准备工作终端下进入工作空间的src目录,调用如下两条命令分别创建C++功能包和Python功能包。
2.2.2 话题通信之原生消息(C++)
1.发布方实现功能包cpp01_topic的src目录下,新建C++文件demo01_talker_str.cpp,并编辑文件,输入如下内容:
2.订阅方实现功能包cpp01_topic的src目录下,新建C++文件demo02_listener_str.cpp,并编辑文件,输入如下内容:
3.编辑配置文件在C++功能包中,配置文件主要关注package.xml与CMakeLists.txt。
1.package.xml
在创建功能包时,所依赖的功能包已经自动配置了,配置内容如下:
需要说明的是<depend>base_interfaces_demo</depend>在本案例中不是必须的。
2.CMakeLists.txt
CMakeLists.txt中发布和订阅程序核心配置如下:
4.编译
终端中进入当前工作空间,编译功能包:
5.执行
当前工作空间下,启动两个终端,终端1执行发布程序,终端2执行订阅程序。
终端1输入如下指令:
终端2输入如下指令:
最终运行结果与案例1类似。
2.2.3 话题通信之原生消息(Python)
1.发布方实现功能包py01_topic的py01_topic目录下,新建Python文件demo01_talker_str_py.py,并编辑文件,输入如下内容:
2.订阅方实现功能包py01_topic的py01_topic目录下,新建Python文件demo02_listener_str_py.py,并编辑文件,输入如下内容:
3.编辑配置文件在Python功能包中,配置文件主要关注package.xml与setup.py。
1.package.xml
在创建功能包时,所依赖的功能包已经自动配置了,配置内容如下:
需要说明的是和上一节C++实现一样<depend>base_interfaces_demo</depend>在本案例中不是必须的。
2.setup.py
entry_points字段的console_scripts中添加如下内容:
4.编译终端中进入当前工作空间,编译功能包:
5.执行当前工作空间下,启动两个终端,终端1执行发布程序,终端2执行订阅程序。
终端1输入如下指令:
终端2输入如下指令:
最终运行结果与案例1类似。
2.2.4 话题通信自定义接口消息
自定义接口消息的流程与在功能包中编写可执行程序的流程类似,主要步骤如下:
- 创建并编辑 .msg文件;
- 编辑配置文件;
- 编译;
- 测试。
接下来,我们可以参考案例2编译一个msg文件,该文件中包含学生的姓名、年龄、身高等字段。
1.创建并编辑 .msg 文件
功能包base_interfaces_demo下新建 msg 文件夹,msg文件夹下新建Student.msg文件,文件中输入如下内容:
2.编辑配置文件
1.package.xml文件
在package.xml中需要添加一些依赖包,具体内容如下:
2.CMakeLists.txt文件
为了将.msg文件转换成对应的C++和Python代码,还需要在CMakeLists.txt中添加如下配置:
3.编译
终端中进入当前工作空间,编译功能包:
4.测试
编译完成之后,在工作空间下的install目录下将生成Student.msg文件对应的C++和Python文件,我们也可以在终端下进入工作空间,通过如下命令查看文件定义以及编译是否正常:
正常情况下,终端将会输出与Student.msg文件一致的内容。
2.2.5 话题通信之自定义消息(C++)
准备
1.发布方实现
功能包cpp01_topic的src目录下,新建C++文件demo01_talker_stu.cpp,并编辑文件,输入如下内容:
2.订阅方实现
功能包cpp01_topic的src目录下,新建C++文件demo04_listener_stu.cpp,并编辑文件,输入如下内容:
3.编辑配置文件
package.xml无需修改,CMakeLists.txt文件需要添加如下内容:
文件中install修改为如下内容:
4.编译
终端中进入当前工作空间,编译功能包:
5.执行
当前工作空间下,启动两个终端,终端1执行发布程序,终端2执行订阅程序。
终端1输入如下指令:
终端2输入如下指令:
最终运行结果与案例2类似。
2.2.6 话题通信之自定义消息(Python)
准备
1.发布方实现
功能包py01_topic的py01_topic目录下,新建Python文件demo03_talker_stu_py.py,并编辑文件,输入如下内容:
2.订阅方实现
功能包py01_topic的py01_topic目录下,新建Python文件demo04_listener_stu_py.py,并编辑文件,输入如下内容:
3.编辑配置文件
package.xml无需修改,需要修改setup.py文件,entry_points字段的console_scripts中修改为如下内容:
4.编译
终端中进入当前工作空间,编译功能包:
5.执行
当前工作空间下,启动两个终端,终端1执行发布程序,终端2执行订阅程序。
终端1输入如下指令:
终端2输入如下指令:
最终运行结果与案例2类似。
2.3 服务通信
场景
服务通信也是ROS中一种极其常用的通信模式,服务通信是基于请求响应模式的,是一种应答机制。也即:一个节点A向另一个节点B发送请求,B接收处理请求并产生响应结果返回给A。比如如下场景:
在上述场景中,就使用到了服务通信。
- 数据分析节点A需要向相机相关节点B发送图片存储请求,节点B处理请求,并返回处理结果。
与上述应用类似的,服务通信更适用于对实时性有要求、具有一定逻辑处理的应用场景。
概念
服务通信是以请求响应的方式实现不同节点之间数据传输的通信模式。发送请求数据的对象称为客户端,接收请求并发送响应的对象称之为服务端,同话题通信一样,客户端和服务端也通过话题相关联,不同的是服务通信的数据传输是双向交互式的。
服务通信中,服务端与客户端是一对多的关系,也即,同一服务话题下,存在多个客户端,每个客户端都可以向服务端发送请求。
作用
用于偶然的、对实时性有要求、有一定逻辑处理需求的数据传输场景。
2.3.1 案例以及案例分析
1.案例需求
需求:编写服务通信,客户端可以提交两个整数到服务端,服务端接收请求并解析两个整数求和,然后将结果响应回客户端。
2.案例分析
在上述案例中,需要关注的要素有三个:
- 客户端;
- 服务端;
- 消息载体。
3.流程简介
案例实现前需要先自定义服务接口,接口准备完毕后,服务实现主要步骤如下:
- 编写服务端实现;
- 编写客户端实现;
- 编辑配置文件;
- 编译;
- 执行。
案例我们会采用C++和Python分别实现,二者都遵循上述实现流程。
4.准备工作
终端下进入工作空间的src目录,调用如下两条命令分别创建C++功能包和Python功能包。
2.3.2 服务通信接口消息
定义服务接口消息与定义话题接口消息流程类似,主要步骤如下:
- 创建并编辑 .srv文件;
- 编辑配置文件;
- 编译;
- 测试。
接下来,我们可以参考案例编写一个srv文件,该文件中包含请求数据(两个整型字段)与响应数据(一个整型字段)。
1.创建并编辑 .srv 文件
功能包base_interfaces_demo下新建srv文件夹,srv文件夹下新建AddInts.srv文件,文件中输入如下内容:
2.编辑配置文件
1.package.xml 文件
srv文件与msg文件的包依赖一致,如果你是新建的功能包添加srv文件,那么直接参考定义msg文件时package.xml 配置即可。由于我们使用的是base_interfaces_demo该包已经为msg文件配置过了依赖包,所以package.xml不需要做修改。
2.CMakeLists.txt 文件
如果是新建的功能包,与之前定义msg文件同理,为了将.srv文件转换成对应的C++和Python代码,还需要在CMakeLists.txt中添加如下配置:
不过,我们当前使用的base_interfaces_demo包,那么你只需要修改rosidl_generate_interfaces函数即可,修改后的内容如下:
3.编译
终端中进入当前工作空间,编译功能包:
4.测试
编译完成之后,在工作空间下的 install 目录下将生成AddInts.srv文件对应的C++和Python文件,我们也可以在终端下进入工作空间,通过如下命令查看文件定义以及编译是否正常:
正常情况下,终端将会输出与AddInts.srv文件一致的内容。
2.3.3 服务通信(C++)
1.服务端实现
功能包cpp02_service的src目录下,新建C++文件demo01_server.cpp,并编辑文件,输入如下内容:
2.客户端实现
功能包cpp02_service的src目录下,新建C++文件demo02_client.cpp,并编辑文件,输入如下内容:
3.编辑配置文件
1.packages.xml
在创建功能包时,所依赖的功能包已经自动配置了,配置内容如下:
2.CMakeLists.txt
CMakeLists.txt 中服务端和客户端程序核心配置如下:
4.编译
终端中进入当前工作空间,编译功能包:
5.执行
当前工作空间下,启动两个终端,终端1执行服务端程序,终端2执行客户端程序。
终端1输入如下指令:
终端2输入如下指令:
最终运行结果与案例类似。
2.3.4 服务通信(Python)
1.服务端实现
功能包py02_service的py02_service目录下,新建Python文件demo01_server_py.py,并编辑文件,输入如下内容:
2.客户端实现
功能包py02_service的py02_service目录下,新建Python文件demo02_client_py.py,并编辑文件,输入如下内容:
3.编辑配置文件
1.package.xml
在创建功能包时,所依赖的功能包已经自动配置了,配置内容如下:
2.setup.py
entry_points字段的console_scripts中添加如下内容:
4.编译
终端中进入当前工作空间,编译功能包:
5.执行
当前工作空间下,启动两个终端,终端1执行服务端程序,终端2执行客户端程序。
终端1输入如下指令:
终端2输入如下指令:
最终运行结果与案例类似。
2.4 动作通信
场景
关于action通信,我们先从之前导航中的应用场景开始介绍,描述如下:
乍一看,这好像是服务通信实现,因为需求中要A发送目标,B执行并返回结果,这是一个典型的基于请求响应的应答模式,不过,如果只是使用基本的服务通信实现,存在一个问题:导航是一个过程,是耗时操作,如果使用服务通信,那么只有在导航结束时,才会产生响应结果,而在导航过程中,节点A是不会获取到任何反馈的,从而可能出现程序"假死"的现象,过程的不可控意味着不良的用户体验,以及逻辑处理的缺陷(比如:导航中止的需求无法实现)。更合理的方案应该是:导航过程中,可以连续反馈当前机器人状态信息,当导航终止时,再返回最终的执行结果。在ROS中,该实现策略称之为:action 通信。
概念
动作通信适用于长时间运行的任务。就结构而言动作通信由目标、反馈和结果三部分组成;就功能而言动作通信类似于服务通信,动作客户端可以发送请求到动作服务端,并接收动作服务端响应的最终结果,不过动作通信可以在请求响应过程中获取连续反馈,并且也可以向动作服务端发送任务取消请求;就底层实现而言动作通信是建立在话题通信和服务通信之上的,目标发送实现是对服务通信的封装,结果的获取也是对服务通信的封装,而连续反馈则是对话题通信的封装。
作用
一般适用于耗时的请求响应场景,用以获取连续的状态反馈。
2.4.1 案例以及案例分析
1.案例需求
需求:编写动作通信,动作客户端提交一个整型数据N,动作服务端接收请求数据并累加1-N之间的所有整数,将最终结果返回给动作客户端,且每累加一次都需要计算当前运算进度并反馈给动作客户端。
2.案例分析
在上述案例中,需要关注的要素有三个:
- 动作客户端;
- 动作服务端;
- 消息载体。
3.流程简介
案例实现前需要先自定义动作接口,接口准备完毕后,动作通信实现主要步骤如下:
- 编写动作服务端实现;
- 编写动作客户端实现;
- 编辑配置文件;
- 编译;
- 执行。
案例我们会采用C++和Python分别实现,二者都遵循上述实现流程。
4.准备工作
终端下进入工作空间的src目录,调用如下两条命令分别创建C++功能包和Python功能包。
2.4.2 动作通信接口消息
定义动作接口消息与定义话题或服务接口消息流程类似,主要步骤如下:
- 创建并编辑.action文件;
- 编辑配置文件;
- 编译;
- 测试。
接下来,我们可以参考案例编写一个action文件,该文件中包含请求数据(一个整型字段)、响应数据(一个整型字段)和连续反馈数据(一个浮点型字段)。
1.创建并编辑 .action 文件
功能包base_interfaces_demo下新建action文件夹,action文件夹下新建Progress.action文件,文件中输入如下内容:
2.编辑配置文件
1.package.xml
如果单独构建action功能包,需要在package.xml中需要添加一些依赖包,具体内容如下:
当前使用的是 base_interfaces_demo 功能包,已经为 msg 、srv 文件添加过了一些依赖,所以 package.xml 中添加如下内容即可:
2.CMakeLists.txt
如果是新建的功能包,与之前定义msg、srv文件同理,为了将.action文件转换成对应的C++和Python代码,还需要在CMakeLists.txt 中添加如下配置:
不过,我们当前使用的base_interfaces_demo包,那么只需要修改rosidl_generate_interfaces函数即可,修改后的内容如下:
3.编译
终端中进入当前工作空间,编译功能包:
4.测试
编译完成之后,在工作空间下的 install 目录下将生成Progress.action文件对应的C++和Python文件,我们也可以在终端下进入工作空间,通过如下命令查看文件定义以及编译是否正常:
正常情况下,终端将会输出与Progress.action文件一致的内容。
2.4.3 动作通信(C++)
1.动作服务端实现
功能包cpp03_action的src目录下,新建C++文件demo01_action_server.cpp,并编辑文件,输入如下内容:
2.动作客户端实现
功能包cpp03_action的src目录下,新建C++文件demo02_action_client.cpp,并编辑文件,输入如下内容:
3.编辑配置文件
1.packages.xml
在创建功能包时,所依赖的功能包已经自动配置了,配置内容如下:
2.CMakeLists.txt
CMakeLists.txt中服务端和客户端程序核心配置如下:
4.编译
终端中进入当前工作空间,编译功能包:
5.执行
当前工作空间下,启动两个终端,终端1执行动作服务端程序,终端2执行动作客户端程序。
终端1输入如下指令:
终端2输入如下指令:
最终运行结果与案例类似。
2.4.4 动作通信(Python)
1.动作服务端实现
功能包py03_action的py03_action目录下,新建Python文件demo01_action_server_py.py,并编辑文件,输入如下内容:
2.动作客户端实现
功能包py03_action的py03_action目录下,新建Python文件demo02_action_client_py.py,并编辑文件,输入如下内容:
3.编辑配置文件
1.package.xml
在创建功能包时,所依赖的功能包已经自动配置了,配置内容如下:
2.setup.py
entry_points字段的console_scripts中添加如下内容:
4.编译
终端中进入当前工作空间,编译功能包:
5.执行
当前工作空间下,启动两个终端,终端1执行动作服务端程序,终端2执行动作客户端程序。
终端1输入如下指令:
终端2输入如下指令:
最终运行结果与案例类似。
2.5 参数服务
场景
在机器人系统中不同的功能模块可能会使用到一些相同的数据,比如:
上述场景中,就可以使用参数服务实现,在一个节点下保存车辆尺寸数据,其他节点可以访问该节点并操作这些数据。
概念
参数服务是以共享的方式实现不同节点之间数据交互的一种通信模式。保存参数的节点称之为参数服务端,调用参数的节点称之为参数客户端。参数客户端与参数服务端的交互是基于请求响应的,且参数通信的实现本质上对服务通信的进一步封装。
作用
参数服务保存的数据类似于编程中“全局变量”的概念,可以在不同的节点之间共享数据。
2.5.1 案例以及案例分析
1.案例需求
需求:在参数服务端设置一些参数,参数客户端访问服务端并操作这些参数。
2.案例分析
在上述案例中,需要关注的要素有三个:
- 参数客户端;
- 参数服务端;
- 参数。
3.流程简介
案例实现前需要先了解ROS2中参数的相关API,无论是客户端还是服务端都会使用到参数,而参数服务案例实现主要步骤如下:
- 编写参数服务端实现;
- 编写参数客户端实现;
- 编辑配置文件;
- 编译;
- 执行。
案例我们会采用C++和Python分别实现,二者都遵循上述实现流程。
4.准备工作
终端下进入工作空间的src目录,调用如下两条命令分别创建C++功能包和Python功能包。
2.5.2 参数数据类型
在ROS2中,参数由键、值和描述符三部分组成,其中键是字符串类型,值可以是bool、int64、float64、string、byte[]、bool[]、int64[]、float64[]、string[]中的任一类型,描述符默认情况下为空,但是可以设置参数描述、参数数据类型、取值范围或其他约束等信息。
为了方便操作,参数被封装为了相关类,其中C++客户端对应的类是rclcpp::Parameter,Python客户端对应的类是rclpy.Parameter。借助于相关API,我们可以实现参数对象创建以及参数属性解析等操作。以下代码提供了参数相关API基本使用的示例。
C++示例:
Python示例:
关于参数具体的API使用,在后续案例中会有介绍。
2.5.3 参数服务(C++)
1.参数服务端
功能包cpp04_param的src目录下,新建C++文件demo01_param_server.cpp,并编辑文件,输入如下内容:
2.参数客户端
功能包cpp04_param的src目录下,新建C++文件demo02_param_client.cpp,并编辑文件,输入如下内容:
3.编辑配置文件
1.packages.xml
在创建功能包时,所依赖的功能包已经自动配置了,配置内容如下:
2.CMakeLists.txt
CMakeLists.txt中参数服务端和参数客户端程序核心配置如下:
4.编译
终端中进入当前工作空间,编译功能包:
5.执行
当前工作空间下,启动两个终端,终端1执行参数服务端程序,终端2执行参数客户端程序。
终端1输入如下指令:
终端2输入如下指令:
最终运行结果与案例类似。
2.5.4 参数服务(Python)
1.参数服务端
功能包py04_param的py04_param目录下,新建Python文件demo01_param_server_py.py,并编辑文件,输入如下内容:
2.参数客户端
ROS2的Python客户端暂时没有提供参数客户端专用的API,但是参数服务的底层是基于服务通信的,所以可以通过服务通信操作参数服务端的参数。
3.编辑配置文件
1.package.xml
在创建功能包时,所依赖的功能包已经自动配置了,配置内容如下:
2.setup.py
entry_points字段的console_scripts中添加如下内容:
4.编译
终端中进入当前工作空间,编译功能包:
5.执行
当前工作空间下,启动两个终端,终端1执行参数服务端程序,终端2执行参数客户端程序(使用2.5.3中的C++实现)。
终端1输入如下指令:
终端2输入如下指令:
最终运行结果与案例类似。
资料:
以服务通信方式操作参数服务端示例代码:
2.6 本章小结
本章主要介绍了ROS2中常用的四种通信机制:
- 话题通信;
- 服务通信;
- 动作通信;
- 参数服务。
无论何种通信机制,他们的实现框架都是类似的。比如:通信必然涉及到双方,双方需要通过“话题”关联,通信还都必然涉及到数据,一般可以通过接口文件来定义数据格式(参数服务是通过参数类封装数据)。
不同的通信机制其实现模型也存在明显差异。话题通信是基于广播的单向数据交互模式;服务通信是基于请求响应的问答式交数据互模式;动作通信则是在请求响应的过程中又包含连续反馈的数据交互模式;参数服务是基于服务通信的,可以在不同节点间实现数据共享。实现模型的差异也决定着他们有着不同的应用场景,大家可以根据自己的实际需求灵活选择。