一个完整的ROS2视频采集节点的实现,使用OpenCV进行视频捕获并通过ROS2发布图像消息。
首先创建一个新的ROS2功能包(如果还没有):
bash
ros2 pkg create video_capture --build-type ament_python --dependencies rclpy sensor_msgs cv_bridge opencv-python
在video_capture/video_capture
目录下创建video_capture_node.py
文件:
python
#!/usr/bin/env python3 import rclpy from rclpy.node import Node from sensor_msgs.msg import Image from cv_bridge import CvBridge import cv2 class VideoCaptureNode(Node): def __init__(self): super().__init__('video_capture_node') # 声明参数 self.declare_parameter('video_source', 0) # 默认使用摄像头0 self.declare_parameter('frame_width', 640) self.declare_parameter('frame_height', 480) self.declare_parameter('fps', 30) self.declare_parameter('topic_name', 'video_frames') # 获取参数值 video_source = self.get_parameter('video_source').value frame_width = self.get_parameter('frame_width').value frame_height = self.get_parameter('frame_height').value fps = self.get_parameter('fps').value topic_name = self.get_parameter('topic_name').value # 初始化视频捕获 self.cap = cv2.VideoCapture(video_source) if not self.cap.isOpened(): self.get_logger().error(f"Cannot open video source {video_source}") raise RuntimeError(f"Cannot open video source {video_source}") # 设置摄像头参数 self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, frame_width) self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, frame_height) self.cap.set(cv2.CAP_PROP_FPS, fps) # 初始化CV桥 self.bridge = CvBridge() # 创建发布者 self.publisher = self.create_publisher(Image, topic_name, 10) # 创建定时器 timer_period = 1.0 / fps # 秒 self.timer = self.create_timer(timer_period, self.timer_callback) self.get_logger().info(f"Video capture node started. Publishing to '{topic_name}' at {fps} FPS") def timer_callback(self): ret, frame = self.cap.read() if ret: try: # 转换并发布图像消息 msg = self.bridge.cv2_to_imgmsg(frame, "bgr8") self.publisher.publish(msg) except Exception as e: self.get_logger().error(f"Error converting frame: {e}") else: self.get_logger().warning("Failed to capture frame") def destroy_node(self): self.cap.release() self.get_logger().info("Video capture released") super().destroy_node() def main(args=None): rclpy.init(args=args) try: node = VideoCaptureNode() rclpy.spin(node) except Exception as e: node.get_logger().error(f"Error in video capture node: {e}") finally: if 'node' in locals(): node.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()
在功能包中创建launch
目录,并添加video_capture.launch.py
文件:
python
from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ Node( package='video_capture', executable='video_capture_node', name='video_capture_node', parameters=[ {'video_source': 0}, {'frame_width': 640}, {'frame_height': 480}, {'fps': 30}, {'topic_name': 'video_frames'} ] ) ])
确保setup.py
包含正确的入口点:
python
from setuptools import setup package_name = 'video_capture' setup( name=package_name, version='0.0.0', packages=[package_name], data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), ('share/' + package_name + '/launch', ['launch/video_capture.launch.py']), ], install_requires=['setuptools'], zip_safe=True, maintainer='your_name', maintainer_email='[email protected]', description='ROS2 video capture node', license='Apache License 2.0', tests_require=['pytest'], entry_points={ 'console_scripts': [ 'video_capture_node = video_capture.video_capture_node:main', ], }, )
构建功能包:
bash
colcon build --packages-select video_capture source install/setup.bash
运行节点:
bash
ros2 launch video_capture video_capture.launch.py
或者直接运行:
bash
ros2 run video_capture video_capture_node
可以通过以下方式修改参数:
在启动文件中修改
通过命令行参数修改:
bash
ros2 run video_capture video_capture_node --ros-args -p video_source:=0 -p frame_width:=1280 -p frame_height:=720
可以使用image_view
节点查看发布的图像:
bash
ros2 run image_tools showimage --ros-args --remap image:=video_frames
确保已安装OpenCV和cv_bridge
根据实际摄像头调整video_source
参数(0通常为默认摄像头)
对于视频文件,将video_source
设置为文件路径
节点会自动释放摄像头资源当被关闭时
这个实现提供了基本的视频采集功能,可以根据需要进一步扩展,例如添加图像处理、保存视频等功能。