前言
目前相关介绍ROS的参考书、教材、技术文档主要介绍ROS的代码,对代码的讲解、以及代码对应的ROS实现数据通信和控制功能对应的原理基本处于忽略状态,这使得开发者在使用ROS进行开发的过程中,只能靠自己摸索,缺乏系统的、整体对ROS功能实现的认识,造成功能开发主要通过模仿代码的方式,没有形成正向开发,即使自己有了好的功能构思之后,也难以自己完整实现。
ROS2提供了丰富的客户端库(ROS Client Library),开发者主要也是通过RCL实现相关ROS功能的。开发者只有完全掌握ROS的RCL才能对代码对应的功能实现原理进行理解,对ROS开发的代码进行完整的掌握,从而形成基于ROS的正向开发能力。ROS的RCL包含太多API,开发者不可能对每个API都清楚原理、功能和使用方式,这时就需要依靠ROS的官方文档。开源也是ROS的优势之一,这也为开发者完整理解RCL的API通过了十分可靠的渠道。
在本文档中,通过ROS2的话题(topic)通信的publisher和subscriber代码,说明在ROS开发中使用到的API在官方文档和源码,使读者能够清楚这些API的来历、代码拓扑位置、功能以及接口。通过这个例子,读者可以明白如何通过ROS的官网和源码了解RCL的API,使得不再局限于模仿例程,具备自主查找RCL的API,从而获得正向开发能力。
实例与代码解构
publisher代码解析
在本文中使用ROS官网中提供的topic的publisher例程作为例子
https://docs.ros.org/en/foxy/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Publisher-And-Subscriber.html
代码如下:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MinimalPublisher(Node):
def __init__(self):
super().__init__('minimal_publisher')
self.publisher_ = self.create_publisher(String, 'topic', 10)
timer_period = 0.5 # seconds
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0
def timer_callback(self):
msg = String()
msg.data = 'Hello World: %d' % self.i
self.publisher_.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)
self.i += 1
def main(args=None):
rclpy.init(args=args)
minimal_publisher = MinimalPublisher()
rclpy.spin(minimal_publisher)
# Destroy the node explicitly
# (optional - otherwise it will be done automatically
# when the garbage collector destroys the node object)
minimal_publisher.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
下面进行代码说明。
代码1:
从ROS官网上给出的packlist可以看出,rclpy实际上ROS提供的许多个包当中的其中之一,rclpy并不是ROS客户端库的全部,当然rclpy是ROS客户端库当中最重要的一个包。此外从python的编译结构来说,rclpy属于python中的包(package),整个这个网页上列出的包的集合才能叫做ROS的客户端库(RCL)。
(网页地址: https://index.ros.org/?search_packages=true#foxy)
代码2:
(网页地址: https://github.com/ros2/rclpy/tree/rolling/rclpy/rclpy)
从gihub上ROS2提供的RCL源码列表这里可以看出,rclpy.node是rclpy包中的node模块。
打开node模块的代码,可以看到代码中定义了Node类,所以这句代码的含义就是导入rclpy包中node模块中的Node类。
(网页地址: https://github.com/ros2/rclpy/blob/rolling/rclpy/rclpy/node.py)
当然,Node类是node.py模块中最重要的类,基本的操作都集中在这里了,所以ros的开发离不开使用这个类。
代码3:
(网页地址: https://index.ros.org/?search_packages=true#foxy)
通过上图,可以看出std_msgs是ROS中提供的一个包,主要用于标准信息的定义。而在这里导入的是string消息。
另外还需要说明的是,这个包里都是*.msg文件,在Python中是可以调用这种文件的。
(网页地址:
https://github.com/ros2/common_interfaces/blob/rolling/std_msgs/msg/String.msg)
可以看到在这里定义了一个data变量,类型是string型。
代码4:
这里使用的create_publisher函数是定义rclpy包中node模块中的Node类中,因为代码2导入了该类,所以这里可以使用这个函数。在这里从create_publisher函数的源码中摘出跟这个函数返回值有关的代码。
解释1:
def create_publisher(
self,
msg_type: Type[MsgT],
topic: str,
qos_profile: Union[QoSProfile, int],
*,
callback_group: Optional[CallbackGroup] =