实施步骤
- 插入摄像头
- 使用命令查询摄像头端口号
ls /dev/video*
- 编写launch文件
<launch>
<node name="usb_cam" pkg="usb_cam" type="usb_cam_node" output="screen">
<param name="video_device" value="/dev/video0" />
<param name="image_width" value="640" />
<param name="image_height" value="480" />
<param name="pixel_format" value="mjpeg" />
<param name="camera_frame_id" value="usb_cam" />
</node>
</launch>
- 需要更改:
将端口号“/dev/video”改为自己摄像头所在的设备号
“mjpeg”是图像输出格式,需要更具实际情况修改,利用如下命令查看当前设备输出的图像格式详情。
v4l2-ctl --list-formats-ext -d /dev/video0 //更改为自己的设备
可见输出格式为"yuyv”(大小写无所谓),更改launch文件的相关位置。
- 运行launch文件,观察输出值
运行正常,无错误。
- 观察显示图像
rqt_image_view
注意:如果使用ssh连接,图像界面无法显示,原因vscode,ssh均没有显示图像的插件。
此时会发现图像特别卡顿,因此提出以下缓解图像卡顿的方案。
- 缓解图像延迟高的问题
- 调整摄像头参数
修改“start_camera.launch”文件
<launch>
<node name="usb_cam" pkg="usb_cam" type="usb_cam_node" output="screen">
<param name="video_device" value="/dev/video0" />
<param name="image_width" value="320" /> <!-- 尝试降低分辨率 -->
<param name="image_height" value="240" />
<param name="pixel_format" value="yuyv" />
<param name="camera_frame_id" value="usb_cam" />
<param name="framerate" value="15" /> <!-- 尝试降低帧率 -->
<param name="io_method" value="mmap" />
<param name="buffer_size" value="4" /> <!-- 增加缓冲区大小 -->
</node>
</launch>
-
优化USB带宽和CPU资源
将摄像头接口接入USB 3.0端口,关闭后台不必要的进程,以释放CPU资源 -
使用多线程处理图像
#!/usr/bin/env python #添加解释器
import rospy #ros和python通讯接口
from sensor_msgs.msg import Image #用于传输图像数据的消息类型
from cv_bridge import CvBridge, CvBridgeError #将ros图像转化为OpenCV图像格式的工具
import cv2 #OpenCV库,用于处理和显示图像库
import threading #Python标准库,用于支持多线程编程
class ImageSubscriber:
def __init__(self):
self.bridge = CvBridge() #创建CvBridge对象,用于ROS图像和OpenCV图像的转化
self.image_sub = rospy.Subscriber("/usb_cam/image_raw", Image, self.image_callback) #订阅来自ROS摄像头的图像消息
self.lock = threading.Lock() # 创建线程锁,用于确保多线程操作的数据安全性
self.cv_image = None # 存储最新的OpenCV格式图像数据
self.display_thread = threading.Thread(target=self.display_image) # 创建用于显示图像的线程
self.display_thread.start() # 启动显示图像的线程
def image_callback(self, msg):
try:
with self.lock:
self.cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8") # 将接收到的ROS图像消息转换为OpenCV的BGR格式图像
except CvBridgeError as e:
rospy.logerr("CvBridge Error: {0}".format(e)) # 如果转换出错,则记录错误日志
def display_image(self):
while not rospy.is_shutdown(): # 当ROS节点未关闭时执行循环
if self.cv_image is not None: # 如果有新的图像数据可用
with self.lock:
cv2.imshow("Camera Image", self.cv_image) # 在窗口中显示摄像头图像
cv2.waitKey(1) # 等待1毫秒,允许窗口处理事件和刷新显示
def main():
rospy.init_node('image_subscriber', anonymous=True) # 初始化ROS节点,节点名称为'image_subscriber',匿名节点
image_subscriber = ImageSubscriber() # 创建ImageSubscriber类的实例
rospy.spin() # 进入ROS的主循环,等待关闭节点的信号
if __name__ == '__main__':
main() # 如果作为主程序运行,则调用main函数开始执行
- 将两个文件添加到一个launch文件中去
返回之前创建的文件
<launch>
<node name="usb_cam" pkg="usb_cam" type="usb_cam_node" output="screen">
<param name="video_device" value="/dev/video0" />
<param name="image_width" value="320" />
<param name="image_height" value="240" />
<param name="pixel_format" value="yuyv" />
<param name="camera_frame_id" value="usb_cam" />
<param name="framerate" value="15" />
<param name="io_method" value="mmap" />
<param name="buffer_size" value="4" /> <!-- 增加缓冲区大小 -->
</node>
<!-- 加载python文件 -->
<node pkg="your_package" type="your_python.py" name="your_python_node" output="screen"/>
</launch>
注:别忘了给python文件赋权
cd (你pyhon存在的位置)
sudo chmod 777 *py
运行launch文件即可观测到图像。
over!!!!