前言
在学习了ROS 2官方教程之后,我决定以自导自演的方式,给自己出题来实践所学知识,以加深对ROS 2的各个概念和使用方式的理解。我将把我的学习过程记录在博客中,并将代码放在我的GitHub仓库中https://github.com/YuAndWang/ROS2_Case(当然博客中也会贴上代码),后面有新的案例将会放到对应的章节之后,供大家参考和学习。
欢迎━(`∀´)ノ亻! 大家一起出题,一起探讨!希望我的实践过程对你理解ROS 2有所帮助。如果你有任何问题或建议,欢迎提出!谢谢~~~
10.节点node
节点是ROS 2中最基本的通信单元。
10.1案例1:object_recognition_node
我想实现使用OpenCV库进行图像识别并显示识别结果。它加载一张图片,对其进行颜色识别,然后在图像中绘制识别结果的轮廓并显示出来。
实现过程如下:
建立功能包
打开一个新的终端,进入到我的工作空间目录,并且应该在 src 目录中创建包,而不是在工作空间的根目录中创建包。因此,进入到 my_ws/src
,并运行包创建命令:
cd my_ws/src
ros2 pkg create --build-type ament_python object_recognition_node_py
节点 object_recognition.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@作者: 王仰旭
@说明: 使用OpenCV进行图像识别并显示识别结果的节点代码, 无发布消息
"""
import rclpy
from rclpy.node import Node
import cv2
import numpy as np # Python数值计算库
lower_red = np.array([0, 90, 128])
upper_red = np.array([180, 255, 255])
def object_detect(image):
hsv_img = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 图像从BGR颜色模型转换为HSV模型
mask_red = cv2.inRange(hsv_img, lower_red, upper_red) # 图像二值化
cv2.imshow("mask_red", mask_red)
contours, hierarchy = cv2.findContours(mask_red, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) # 图像中轮廓检测
for cnt in contours: # 去除轮廓面积太小的噪声
if cnt.shape[0] < 150:
continue
(x, y, w, h) = cv2.boundingRect(cnt)
cv2.drawContours(image, [cnt], -1, (0, 0, 255), 2)
cv2.circle(image, (int(x+w/2), int(y+h/2)), 5, (0, 255, 0), -1)
cv2.imshow("object", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
def main(args=None):
rclpy.init(args=args)
node = Node("object_recognition_node")
node.get_logger().info("Start Imread...")
# 因编译后可执行文件在install中,不与图片同文件夹,只能用绝对路径,或把照片复制过去
image = cv2.imread("/home/wang/my_ws/src/object_recognition_node_py/object_recognition_node_py/apple.jpg")
object_detect(image)
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
代码解释说明:
该节点使用OpenCV库进行图像识别并显示识别结果。它加载一张图片,对其进行颜色识别,然后在图像中绘制识别结果的轮廓并显示出来。
在object_detect
函数中,图像首先被转换为HSV颜色模型,然后通过阈值操作将感兴趣的颜色区域提取出来。接着使用轮廓检测函数cv2.findContours
对二值化图像中的轮廓进行检测。然后,根据轮廓的面积大小过滤掉噪声,并在原图像中绘制出识别结果的轮廓和圆心。
在main
函数中,我们初始化ROS 2 Python接口,并创建了一个节点对象。然后,使用OpenCV的imread
函数加载一张图片,传递给object_detect
函数进行识别和绘制。最后,使用rclpy.spin
函数循环等待ROS 2退出,然后销毁节点对象并关闭ROS 2 Python接口。
请注意,由于编译后的可执行文件位于install
目录中,与图片不在同一个文件夹中,所以代码中使用了绝对路径来加载图片。在运用时需要根据实际情况修改图片路径。
配置package.xml文件
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>object_recognition_node_py</name>
<version>0.0.0</version>
<description>object recognition using rclpy</description>
<maintainer email="wangyx6432@gmail.com">wang</maintainer>
<license>BSD</license>
<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>
<export>
<build_type>ament_python</build_type>
</export>
</package>
配置setup.py文件
记得这里需要在setup.py
文件中添加入口点(entry points),以便能够通过命令行运行你的节点。
from setuptools import setup
package_name = 'object_recognition_node_py'
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']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='wang',
maintainer_email='wangyx6432@gmail.com',
description='object recognition using rclpy',
license='BSD',
tests_require=['pytest'],
entry_points={
'console_scripts': [
'object_recognition = object_recognition_node_py.object_recognition:main',
],
},
)
检查setup.cfg文件
setup.cfg
文件用于配置ROS 2的包安装和开发时的相关设置。检查一下是否正确配置了安装和开发时的脚本目录。这里会告诉setuptools把编译后的可执行文件放在lib中,因为运行时ros2 run命令将会在那里寻找它们。
[develop]
script_dir=$base/lib/object_recognition_node_py
[install]
install_scripts=$base/lib/object_recognition_node_py
编译
cd my_ws/
colcon build
运行
打开新终端,刷新环境
source ~/my_ws/install/setup.bash
ros2 run object_recognition_node_py object_recognition