赞
踩
机器人是各种功能的综合体,每一项功能就像机器人的一个工作细胞,众多细胞通过一些机制连接到一起,成为了一个机器人整体。
在ROS中,我们给这些 “细胞”取了一个名字,那就是节点。
完整的机器人系统可能并不是一个物理上的整体,比如这样一个的机器人:
节点在机器人系统中的职责就是执行某些具体的任务,从计算机操作系统的角度来看,也叫做进程;
每个节点都是一个可以独立运行的可执行文件,比如执行某一个python程序,或者执行C++编译生成的结果,都算是运行了一个节点;
既然每个节点都是独立的执行文件,那自然就可以想到,得到这个执行文件的编程语言可以是不同的,比如C++、Python,乃至Java、Ruby等更多语言。
这些节点是功能各不相同的细胞,根据系统设计的不同,可能位于计算机A,也可能位于计算机B,还有可能运行在云端,这叫做分布式,也就是可以分布在不同的硬件载体上;
每一个节点都需要有唯一的命名,当我们想要去找到某一个节点的时候,或者想要查询某一个节点的状态时,可以通过节点的名称来做查询。
节点也可以比喻是一个一个的工人,分别完成不同的任务,他们有的在一线厂房工作,有的在后勤部门提供保障,他们互相可能并不认识,但却一起推动机器人这座“工厂”,完成更为复杂的任务。
ROS2中节点的实现当然是需要编写程序了,我们从Hello World例程开始,先来实现一个最为简单的节点,功能并不复杂,就是循环打印一个“Hello World”字符串到终端中。
ros2 run learning_node node_helloworld
代码解析:
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
import time
def main(args=None): # ROS2节点主入口main函数
rclpy.init(args=args) # ROS2 Python接口初始化 **固定编程方式**
node = Node("node_helloworld") # 创建ROS2节点对象并进行初始化 **要将类创建成对象才能进行使用**
while rclpy.ok(): # ROS2系统是否正常运行
node.get_logger().info("Hello World") # ROS2日志输出 类似print
time.sleep(0.5) # 休眠控制循环时间
node.destroy_node() # 销毁节点对象
rclpy.shutdown() # 关闭ROS2 Python接口
完成代码的编写后需要设置功能包的编译选项,让系统知道Python程序的入口,打开功能包的setup.py文件,加入如下入口点的配置:
entry_points={
'console_scripts': [
'node_helloworld = learning_node.node_helloworld:main',节点.代码文件名.main
],
编程接口初始化
创建节点并初始化
实现节点功能
销毁节点并关闭接口
所以在ROS2的开发中,我们更推荐大家使用面向对象的编程方式,比如刚才的代码就可以改成这样,虽然看上去复杂了一些,但是代码会具备更好的可读性和可移植性,调试起来也会更加方便。
ros2 run learning_node node_helloworld_class
代码解析:
import rclpy # ROS2 Python接口库 from rclpy.node import Node # ROS2 节点类 import time """ 创建一个HelloWorld节点, 初始化时输出“hello world”日志 """ 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) # 休眠控制循环时间 def main(args=None): # ROS2节点主入口main函数 rclpy.init(args=args) # ROS2 Python接口初始化 node = HelloWorldNode("node_helloworld_class") # 创建ROS2节点对象并进行初始化 rclpy.spin(node) # 循环等待ROS2退出 node.destroy_node() # 销毁节点对象 rclpy.shutdown() # 关闭ROS2 Python接口
完成代码的编写后需要设置功能包的编译选项,让系统知道Python程序的入口,打开功能包的setup.py文件,加入如下入口点的配置:
entry_points={
'console_scripts': [
'node_helloworld = learning_node.node_helloworld:main',
'node_helloworld_class = learning_node.node_helloworld_class:main',
],
运行一段代码之前要先进行编译,编译之后会把代码拷贝到install文件夹中,每次运行ros run 运行的都是install中的文件,不编译的话运行的就是旧代码。
编程接口初始化
创建节点并初始化
实现节点功能
销毁节点并关闭接口
没错,接下来我们就以机器视觉的任务为例,模拟实际机器人中节点的实现过程。
我们先从网上找到一张苹果的图片,通过编写一个节点来识别图片中的苹果。
首先要安装opencv
sudo apt install python3-opencv
使用这条指令大概率不能用,我是跟着古月居得课程走得,然后踩了很多坑,可以使用下面两行代码进行安装。
pip3 install numpy
pip3 install opencv-python
然后就可以运行例程啦:
ros2 run learning_node node_object #注意修改图片路径后重新编译
运行前需要将learning_node/node_object.py代码中的图片路径,修改为实际路径,修改后重新编译运行即可:
image = cv2.imread('/home/qcx/dev_ws/src/ros2_21_tutorials/learning_node/learning_node/apple.jpg')
例程运行成功后,会弹出一个可视化窗口,可以看到苹果被成功识别啦,一个绿色框会把苹果的轮廓勾勒出来,中间的绿点表示中心点。
代码解析:
import rclpy # ROS2 Python接口库 from rclpy.node import Node # ROS2 节点类 import cv2 # OpenCV图像处理库 import numpy as np # Python数值计算库 lower_red = np.array([0, 90, 128]) # 红色的HSV阈值下限 upper_red = np.array([180, 255, 255]) # 红色的HSV阈值上限 def object_detect(image): hsv_img = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 图像从BGR颜色模型转换为HSV模型 mask_red = cv2.inRange(hsv_img, lower_red, upper_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) # 得到苹果所在轮廓的左上角xy像素坐标及轮廓范围的宽和高 cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2)# 将苹果的轮廓勾勒出来 cv2.circle(image, (int(x+w/2), int(y+h/2)), 5, (0, 255, 0), -1)# 将苹果的图像中心点画出来 cv2.imshow("object", image) # 使用OpenCV显示处理后的图像效果 cv2.waitKey(0) cv2.destroyAllWindows() def main(args=None): # ROS2节点主入口main函数 rclpy.init(args=args) # ROS2 Python接口初始化 node = Node("node_object") # 创建ROS2节点对象并进行初始化 node.get_logger().info("ROS2节点示例:检测图片中的苹果") image = cv2.imread('/home/qcx/dev_ws/src/ros2_21_tutorials/learning_node/learning_node/apple.jpg') # 读取图像 object_detect(image) # 苹果检测 rclpy.spin(node) # 循环等待ROS2退出 node.destroy_node() # 销毁节点对象 rclpy.shutdown() # 关闭ROS2 Python接口
完成代码的编写后需要设置功能包的编译选项,让系统知道Python程序的入口,打开功能包的setup.py文件,加入如下入口点的配置:
entry_points={
'console_scripts': [
'node_helloworld = learning_node.node_helloworld:main',
'node_helloworld_class = learning_node.node_helloworld_class:main',
'node_object = learning_node.node_object:main',
],
调用摄像头识别
ros2 run learning_node node_object_webcam
如果是在虚拟机中操作,需要进行以下设置: 1. 把虚拟机设置为兼容USB3.1; 2. 在可移动设备中将摄像头连接至虚拟机。
我是调用的电脑的摄像头,效果还是可以的
相比之前的程序,这里最大的变化是修改了图片的来源,使用OpenCV中的VideoCapture()来驱动相机,并且周期read摄像头的信息,并进行识别。
import rclpy # ROS2 Python接口库 from rclpy.node import Node # ROS2 节点类 import cv2 # OpenCV图像处理库 import numpy as np # Python数值计算库 lower_red = np.array([0, 90, 128]) # 红色的HSV阈值下限 upper_red = np.array([180, 255, 255]) # 红色的HSV阈值上限 def object_detect(image): hsv_img = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 图像从BGR颜色模型转换为HSV模型 mask_red = cv2.inRange(hsv_img, lower_red, upper_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) # 得到苹果所在轮廓的左上角xy像素坐标及轮廓范围的宽和高 cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2) # 将苹果的轮廓勾勒出来 cv2.circle(image, (int(x+w/2), int(y+h/2)), 5, (0, 255, 0), -1) # 将苹果的图像中心点画出来 cv2.imshow("object", image) # 使用OpenCV显示处理后的图像效果 cv2.waitKey(50) def main(args=None): # ROS2节点主入口main函数 rclpy.init(args=args) # ROS2 Python接口初始化 node = Node("node_object_webcam") # 创建ROS2节点对象并进行初始化 node.get_logger().info("ROS2节点示例:检测图片中的苹果") cap = cv2.VideoCapture(0) while rclpy.ok(): ret, image = cap.read() # 读取一帧图像 if ret == True: object_detect(image) # 苹果检测 node.destroy_node() # 销毁节点对象 rclpy.shutdown() # 关闭ROS2 Python接口
ls /dev/video* #查看摄像头的型号
ros2 node list # 查看节点列表
ros2 node info <node_name> # 查看节点信息
在一个ROS机器人的系统中,节点并不是孤立的,他们之间会有很多种机制保持联系,下面就会介绍他们之间的联系。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。