ROS实验报告一

ROS实验一记录

实验一要求

实现一个复杂的话题(topics)通信,(若无法实现要求一,可使用本地图片)。实验报告需提交PDF,文件命名方式:学号+专业姓名+实验1。提交日期/方式:10.25号通过机房电脑系统提交。

要求一:需实现Ubuntu调用笔记本摄像头。

要求二:需实时对拍摄得的图片进行图像处理(灰度化,边缘检测,方式不限)。

要求三:提交的报告需附关键功能代码,以及处理前后的图片,并阐述清楚如何使用话题通信传输图片。

要求四:需通过实验分析话题通信是否存在数据丢失,队列参数的影响。

1、创建工作空间以及功能包

2、创建并编写源码文件

(1)在发布者节点中,先实现对于Ubuntu中笔记本摄像头的调用,然后将读取的图片转为ROS的图像消息

在订阅者节点中,直接展示ROS的图像信息

(2)在订阅者节点中,先实现对ROS图像消息的接收,并转为OpenCV图像,然后对于得到的图像分别调用灰度化处理函数、边缘检测函数实现作业要求

灰度化处理

这里需要明确灰度化函数的常见处理手法,参考这篇博客:

https://zhuanlan.zhihu.com/p/658406188

这里我选择使用cv中自带的函数实现灰度化,效果如下:

边缘检测

参考这篇教程:

https://blog.csdn.net/G_redsky/article/details/136357836

方案1,使用Canny边缘检测

方案2,使用Sobel算子检测,Sobel算子通过计算图像的梯度来检测边缘

方案3:使用Laplacian算子实现边缘检测,Laplacian算子是一种二阶导数算子,用于强调图像中的快速变化区域

3、配置编译文件

4、编译

编译时遇到报错:

查找相关链接:

https://github.com/macs3-project/MACS/issues/49

解决方案如下:

将setup.py中的相关代码注释

然后又出现新的报错:

查找相关链接:

https://blog.csdn.net/2302_76761277/article/details/140596436

解决方案如下:

报错原因是setuptools版本问题,安装70.0.0指定版本即可

编译成功:

5、运行话题

(1)发布者话题

(2)订阅者话题

6、ROS使用话题通信传输图片原理阐释

ROS 的话题通信是一种发布 / 订阅模式的通信机制,一个节点可以发布特定主题的消息,而其他节点可以订阅该主题以接收这些消息。

对于传输图片来说,,在ROS中有专门的图像消息类型来表示图像数据,在代码中,使用到的是sensor_msgs/Image,首先需要使用cv_bridge将ROS与OpenCV图像进行互相转换,然后利用创建的Image类型的节点发布图像信息,以此来实现图像传输功能

对于订阅者节点来说,当订阅者接收到图像消息时,回调函数会被触发。在回调函数中,使用cv_bridge将 ROS 图像消息转换为 OpenCV 图像格式,然后可以使用 OpenCV 的函数对图像进行显示或处理。

7、分析话题通信是否存在数据丢失,以及队列参数的影响。

在ROS中,我们可以使用 ROS 的日志记录功能或自定义的日志文件来记录数据。检查记录的数据,看是否存在消息丢失的情况。如果订阅者接收到的消息数量与发布者发送的消息数量不一致,那么可能存在数据丢失。

同时在ROS中,话题通信的队列参数决定了订阅者可以缓存的未处理消息的数量,我们可以设置不同的队列参数值,例如较小的值如 1、5、10,以及较大的值如 50、100 等,分别比较不同队列参数下的数据丢失情况。理论上应该观察到较小队列参数时更容易出现数据丢失,而较大队列参数能够减少数据丢失的可能性。

发布者的消息队列与订阅者的消息队列的不同之处:

(1)发布者的消息队列主要用于存储待发布的消息;

(2)订阅者的消息队列主要用于存储已经接收到但是还未被处理的消息

当发布者的发布频率为0.01,队列参数为1时,发现出现了多次通信数据的丢失,结果如下图,红色点为丢失的数据点:

当队列参数为3时,发现还是存在一些通信数据的丢失,但是数量少于参数为1的情况

当队列参数为5时,发现没有通信数据的丢失

通过上述的简单实验,发现队列参数的设置对于通信数据的丢失会产生一定的影响,当队列参数设置较小时,可能会出现通信数据的丢失。

同时,发现发布者的发布频率对于通信来说同样至关重要,当频率设置较小时(如0.01),发现会产生数据丢失,但是当频率设置较大时(如0.1),发现即使队列参数较小,也可能不会出现数据丢失。

综上,通过实验,我们发现发布频率以及队列参数对于通信数据是否丢失至关重要。

涉及到的代码如下

发布者代码 message_pub.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class PublisherNode(Node):
def __init__(self):
super().__init__('publisher_node')
self.publisher_ = self.create_publisher(String, 'my_topic', 10)
# 创建一个定时器,每.01秒钟触发一次回调
self.timer = self.create_timer(0.01, self.publish_message)
self.count = 0

def publish_message(self):
msg = String()
msg.data = str(self.count)
self.publisher_.publish(msg)
self.get_logger().info(f'Published: {self.count}')
self.count += 1

def main(args=None):
rclpy.init(args=args)
node = PublisherNode()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
node.destroy_node()
rclpy.shutdown()

订阅者代码 message_sub.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class SubscriberNode(Node):
def __init__(self):
super().__init__('subscriber_node')
self.subscription = self.create_subscription(
String,
'my_topic',
self.listener_callback,
10)
self.log_file = open('log.txt', 'a')

def listener_callback(self, msg):
self.get_logger().info(f'Received: {msg.data}')
self.log_file.write(f'{msg.data}\n')

def close_log_file(self):
self.log_file.close()

def main(args=None):
rclpy.init(args=args)
node = SubscriberNode()
rclpy.spin(node)
node.close_log_file()
node.destroy_node()
rclpy.shutdown()


ROS实验报告一
http://jrhu0048.github.io/2024/10/14/ros/ros-shi-yan-bao-gao-yi/
作者
JR.HU
发布于
2024年10月14日
更新于
2024年11月9日
许可协议