ROS2学习记录(5)-通信接口

通信接口的主要目的就是传输数据,为了高效的建立连接,并且准确包装和解析传输的数据内容,话题、服务等机制也就诞生了,他们传输的数据,都要符合通信接口的标准定义这些接口看上去像是给我们加了一些约束,但却是ROS系统的精髓所在

接口可以让程序之间的依赖降低,便于我们使用别人的代码,也方便别人使用我们的代码,这就是ROS的核心目标,减少重复造轮子。

ROS有三种常用的通信机制,分别是话题、服务、动作,通过每一种通信种定义的接口,各种节点才能有机的联系到一起。为了保证每一个节点可以使用不同语言编程,ROS将这些接口的设计做成了和语言无关的。

话题通信接口的定义使用的是.msg文件,由于是单向传输,只需要描述传输的每一帧数据是什么就行,比如在传输两个32位的整型数,x、y,我们可以用来传输二维坐标的数值。

服务通信接口的定义使用的是.srv文件,包含请求和应答两部分定义,通过中间的“—”区分,比如之前加法求和功能,请求数据是两个64位整型数a和b,“—”后的应答是求和的结果sum。

动作是另外一种通信机制,用来描述机器人的一个运动过程,使用.action文件定义,比如我们让小海龟转90度,一边转一边周期反馈当前的状态,此时接口的定义分成了三个部分,分别是动作的目标,比如是开始运动,运动的结果,最终旋转的90度是否完成,还有一个周期反馈,比如每隔1s反馈一下当前转到第10度、20度还是30度了,让我们知道运动的进度。

一个.srv的例子如下(消息类型名称必须以大写字母开头,即几个消息类型文件名的首字母都必须是大写字母):

bool get      # 获取目标位置的指令
---
int32 x       # 目标的X坐标
int32 y       # 目标的Y坐标

编译时会根据不同语言扩展成对应语言的实现结构,所有内容会包括在一个大的结构体内,这里的“—”前后又会被编译为两个小的结构体(request和response),作为大结构体的组成部分。然后需要对该.srv文件所在文件夹进行c++功能包的编译(.msg和.action也一样要用cmake编译),得到c++功能包的配置文件“CMakeLists.txt”(即便python代码,这一步也需要用c++方式编译通信接口文件),打开并配置“CMakeLists.txt”文件中的rosidl_generate_interfaces,形如:

rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/ObjectPosition.msg"
  "srv/AddTwoInts.srv"
  "srv/GetObjectPosition.srv"
  "action/MoveCircle.action"
 )

其中每行填的参数是需要编译的通信接口文件的地址,以“CMakeLists.txt”文件所在目录为根目录进行查找。

在执行colcon编译时,会将通信接口文件编译到install文件下对应位置。在以下地址会分别生成一份c和c++的库文件(get_object_position.h和get_object_position.hpp):

工作空间/install/learning_interface/include/learning_interface/learning_interface/srv

在以下地址则生成python的库文件(_get_object_position.py和_get_object_position_s.c):

工作空间/install/learning_interface/local/lib/python3.10/dist-packages/learning_interface/srv

在python程序内调用接口时,只需要如导入一般的工具包一样,按地址去导入该结构体(类)即可像使用普通结构体(类)一样去使用了。形如以下语句,“learning_interface.srv”即表示以项目根目录为当前目录,“./learning_interface/srv”文件夹内的“GetObjectPosition”类(实际上肯定是在install文件夹里面找到的,只是这样说更好判断目录层级结构):

from learning_interface.srv import GetObjectPosition    # 自定义的服务接口

在server服务器端创建服务器对象的时候就可以直接指定消息类型为“GetObjectPosition”类了:


# 创建服务器对象(接口类型、服务名、服务器回调函数)
self.srv = self.create_service(GetObjectPosition, 
                   'get_target_position',
                   self.object_position_callback)    

收到客户端请求后调用回调函数时,接受到的是一整个完整的“GetObjectPosition”类,对于server类型的通信接口,需要拆成request和response来处理(即前文所说两个小结构体)。顾名思义,request部分就是客户端传递来的内容,而修改并返回response内容,就是设定返回给客户端的内容。一个server类的回调成员函数形如:

    def object_position_callback(self, request, response):       # 创建回调函数,执行收到请求后对数据的处理
        if request.get == True:
            response.x = self.objectX                            # 目标物体的XY坐标
            response.y = self.objectY
            self.get_logger().info('Object position\nx: %d y: %d' %
                                   (response.x, response.y))     # 输出日志信息,提示已经反馈
        else:
            response.x = 0
            response.y = 0
            self.get_logger().info('Invalid command')            # 输出日志信息,提示已经反馈
        return response

在client客户端,也是类似的处理,导入类:

from learning_interface.srv import GetObjectPosition    # 自定义的服务接口

并用于创建连接:

# 创建服务客户端对象(服务接口类型,服务名)
self.client = self.create_client(GetObjectPosition, 'get_target_position')

设置变量存放request:

self.request = GetObjectPosition.Request()

设置request的参数并通过建立的client连接发送给服务器端:

    def send_request(self):
        self.request.get = True
        self.future = self.client.call_async(self.request)

最后通过检测self.future,适时获取response:


if node.future.done():
    response = node.future.result()

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇