文章目录
- 一、节点
-
- 1.节点概念
- 2.节点的核心代码
- 3.创建节点流程
- 二、话题
-
- 1.主题概念
- 2.主题的核心代码
- 3.创建主题流程
- 三、服务
-
- 1.服务理念
- 2.服务核心代码
- 3.创建服务流程
- 总结
一、节点
1.节点概念
实现机器人的各种功能,如用摄像头获取外部环境信息、用电机驱动轮子前进等。
特点是:
- 执行具体任务;
- 每个节点独立运行的可执行文件;
- 节点编程语言可以不同;
- 节点可以位于硬件或云上;
- 节点是唯一命名的,便于查询节点的状态等。
2.节点的核心代码
""" 创建一个HelloWorld节点, 节点功能输出节点功能输出HelloWorld”日志 节点实现效果:终端每隔0.5s输出一句“HelloWorld” """ class HelloWorldNode(Node): def __init__(self, name): super().__init__(name) # ROS2节点父类初始化 while rclpy.ok(): # ROS2系统是否正常运行 self.get_logger().info("Hello World") # ROS2日志输出 time.sleep(0.5) # 休眠控制循环时间
3.创建节点流程
- 编程接口初始化
- 创建节点并初始化
- 实现节点功能
- 销毁节点并关闭接口
二、话题
1.主题概念
节点是机器人实现各种功能的桥梁,但这些功能并非独立,可以通过主题构建节点之间的数据传输。,从一个节点到另一个节点,发送数据,接收数据。如果出版商发布主题名称并将数据发送到主题,订阅者可以通过主题查看发布内容。
主题通信的另一个特点是,出版商发布数据后,不知道订阅者什么时候能收到,只要发送,适合一些周期性数据,如传感器数据、运动控制指令等。
如上图所示,为出版商和订阅者创建两个节点。出版商发布主题名称并将数据发送到主题,订阅者可以通过主题查看发布内容。
如上所示,一个发布者发布的数据,可以同时被不同的订阅者获得,即一对多模型。
2.主题的核心代码
""" 创建出版商节点 """ class PublisherNode(Node): def __init__(self, name): super().__init__(name) # ROS2节点父类初始化 self.pub = self.create_publisher(String
,
"chatter"
,
10
)
# 创建发布者对象(消息类型、话题名、队列长度) self
.timer
= self
.create_timer
(
0.5
, self
.timer_callback
)
# 创建一个定时器(单位为秒的周期,定时执行的回调函数)
def
timer_callback
(self
)
:
# 创建定时器周期执行的回调函数 msg
= String
(
)
# 创建一个String类型的消息对象 msg
.data
=
'Hello World'
# 填充消息对象中的消息数据 self
.pub
.publish
(msg
)
# 发布话题消息 self
.get_logger
(
)
.info
(
'Publishing: "%s"'
% msg
.data
)
# 输出日志信息,提示已经完成话题发布
""" 创建一个订阅者节点 """
class SubscriberNode(Node):
def __init__(self, name):
super().__init__(name) # ROS2节点父类初始化
self.sub = self.create_subscription(\
String, "chatter", self.listener_callback, 10) # 创建订阅者对象(消息类型、话题名、订阅者回调函数、队列长度)
def listener_callback(self, msg): # 创建回调函数,执行收到话题消息后对数据的处理
self.get_logger().info('I heard: "%s"' % msg.data) # 输出日志信息,提示订阅收到的话题消息
3.创建话题流程
发布者端 | 订阅者端 |
---|---|
1. 编程接口初始化 | 1. 编程接口初始化 |
2. 创建节点并初始化 | 2. 创建节点并初始化 |
3. 创建发布者对象 | 3. 创建订阅者对象 |
4. 创建并填充话题消息 | 4. 回调函数处理话题数据 |
5. 发布话题消息 | 5. 销毁节点并关闭接口 |
6. 销毁节点并关闭接口 |
三、服务
1.服务的概念
ROS另一种常用的通信方法是服务,可以实现你问我答的同步通信效果,适合同步性要求更高的数据,比如获取机器视觉识别到的目标位置。
如上图所示,创建两个节点分别为服务端和客户端,客户端在需要某些数据的时候,针对某个具体的服务,发送请求信息,服务器端收到请求之后,就会进行处理并反馈应答信息,即为一问一答的形式。
如上图所示为一对多通信。不同的客户端可以向同一个服务端发送请求并获得想要的数据。
2.服务的核心代码
class adderServer(Node):
def __init__(self, name):
super().__init__(name) # ROS2节点父类初始化
self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.adder_callback) # 创建服务器对象(接口类型、服务名、服务器回调函数)
def adder_callback(self, request, response): # 创建回调函数,执行收到请求后对数据的处理
response.sum = request.a + request.b # 完成加法求和计算,将结果放到反馈的数据中
self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b)) # 输出日志信息,提示已经完成加法求和计算
return response # 反馈应答信息
class adderClient(Node):
def __init__(self, name):
super().__init__(name) # ROS2节点父类初始化
self.client = self.create_client(AddTwoInts, 'add_two_ints') # 创建服务客户端对象(服务接口类型,服务名)
while not self.client.wait_for_service(timeout_sec=1.0): # 循环等待服务器端成功启动
self.get_logger().info('service not available, waiting again...')
self.request = AddTwoInts.Request() # 创建服务请求的数据对象
def send_request(self): # 创建一个发送服务请求的函数
self.request.a = int(sys.argv[1])
self.request.b = int(sys.argv[2])
self.future = self.client.call_async(self.request) # 异步方式发送服务请求
3.创建服务流程
服务端 | 客户端 |
---|---|
1. 编程接口初始化 | 1. 编程接口初始化 |
2. 创建节点并初始化 | 2. 创建节点并初始化 |
3. 创建服务器端对象 | 3. 创建客户端对象 |
4. 通过回调函数处进行服务 | 4. 创建并发送请求数据 |
5. 向客户端反馈应答结果 | 5. 等待服务器端应答数据 |
6. 销毁节点并关闭接口 | 6. 销毁节点并关闭接口 |
总结
话题和服务是ROS中最为常用的两种数据通信方法,前者适合传感器、控制指令等周期性、单向传输的数据,后者适合一问一答,同步性要求更高的数据。