跳转至

四、节点(node)

📌节点可理解为机器人身上的各个模块

1.Demo尝试

打开第一个终端

# 运行一个用c++构建的talker节点
ros2 run demo_nodes_cpp talker

打开另一个终端

# 运行一个用python构建的listener节点
ros2 run demo_nodes_py listener

python的listener节点即可收到来自cpp的talker节点的消息

这个例子同时也用到了“话题”功能,将在下节详细讲解

2.动手实现一个节点

本次用Python和C++两种语言来作演示,日后会以Python为主

(1)Python实现

创建软件包

cd ~/dev_ws/src

ros2 pkg create --build-type ament_python learning_node_py

当前的项目结构

上面的箭头所指文件夹是编写源代码的位置

下面的箭头所指文件是软件包的构建配置文件

cd learning_node_py/learning_node_py

# 创建代码文件,也可以直接在VScode里操作
touch hello_node.py

编写代码

import rclpy
from rclpy.node import Node
import time

def main(args=None):
    rclpy.init(args=args) # 初始化
    node = Node("node_hello_node") # 定义节点名称

    while rclpy.ok(): # 当节点没有问题时持续循环
        node.get_logger().info("Hello Node") # 输出到日志
        time.sleep(0.5) # 控制每个循环直接间隔0.5秒

    node.destroy_node() # 销毁节点
    rclpy.shutdown()

配置节点

在软件包的构建配置文件中添加编写的节点

格式:节点名=包名.代码文件名:函数名

构建软件包

cd ~/dev_ws

colcon build

source install/local_setup.bash

运行节点

ros2 run learning_node_py node_hello_node 

优化代码

我们可以把代码写成面向对象的形式,提升可读性方便调试

新建一个文件hello_class.py

import rclpy
from rclpy.node import Node
import time

class HelloClassNode(Node):
    def __init__(self, node_name):
        super().__init__(node_name)
        while rclpy.ok():
            self.get_logger().info("Hello Node")
            time.sleep(0.5)

def main(args=None):
    rclpy.init(args=args)
    node = HelloClassNode("node_hello_class")
    node.destroy_node()
    rclpy.shutdown()

同样地,将节点添加进配置文件,节点之间以逗号分隔

构建并运行,效果和刚才一样

(2)C++实现

创建软件包

cd ~/dev_ws/src

ros2 pkg create --build-type ament_cmake learning_node_cpp

当前的项目结构

上面的箭头所指文件夹是编写源代码的位置

下面的箭头所指文件是软件包的构建配置文件

cd learning_node_cpp/src

# 创建代码文件,也可以直接在VScode里操作
touch hello_node.cpp

编写代码

#include "rclcpp/rclcpp.hpp"

class HelloNode : public rclcpp::Node
{
    public:
        HelloNode()
        : Node("node_hello_node")
        {
            while (rclcpp::ok())
            {
                RCLCPP_INFO(this->get_logger(), "Hello World");
                sleep(1);
            }
        }
};

int main(int argc, char * argv[])
{
    rclcpp::init(argc, argv);
    rclcpp::spin(std::make_shared<HelloNode>());
    rclcpp::shutdown();

    return 0;

配置节点

构建软件包

cd ~/dev_ws

colcon build

source install/local_setup.bash

运行节点

ros2 run learning_node_cpp node_hello_node

3.进阶--实现人脸识别节点

(1)环境配置

sudo pip3 install opencv-python

(2)编写代码

import cv2
import rclpy
from rclpy.node import Node

class FaceDetectNode(Node):

    def __init__(self, node_name):
        super().__init__(node_name)
        self.face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
        self.cap = cv2.VideoCapture(0)

        while rclpy.ok():
            ret, frame = self.cap.read()
            # 镜像翻转
            frame = cv2.flip(frame, 1)
            if ret:
                quit = self.detect(frame)

                # 判断是否按下esc键
                if quit == 27:
                    self.cap.release()
                    cv2.destroyAllWindows()
                    break

    def detect(self, frame):
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = self.face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))

        # 框出人脸
        for (x, y, w, h) in faces:
            cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)

        cv2.imshow('Face Detection', frame)
        return cv2.waitKey(1) & 0xFF

def main(args=None):
    rclpy.init(args=args)
    node = FaceDetectNode("face_detect_node")
    node.destroy_node()
    rclpy.shutdown()