返回目录

ROS2-第一个节点和功能包

ROS2

1、节点学习

节点可视作一个单独的模块化功能(比如一个节点负责控制车轮转动、一个节点负责定位等)。

节点和节点间有四种通信方式:

  • 话题(topics)
  • 服务(services)
  • 动作(Action)
  • 参数(parameters)

启动一个节点

# 启动包package_name中的可执行文件executable_name
ros2 run <package_name> <executable_name>

ros2 run turtlesim turtlesim_node

其中package在某工作空间(文件夹)内,一个工作空间下可以有多个功能包,一个功能包可以有多个节点存在

查看节点列表

ros2 node list

查看节点信息

# 查看节点node_name的信息
ros2 node info <node_name>

2、创建第一个节点

新建一个文件夹和python文件(如ROS2/first_node.py),输入以下代码:

# !/usr/bin/env python3
# 导入rclpy库
import rclpy
from rclpy.node import Node
# 调用初始化函数
rclpy.init()
# 创建节点“first_node”并循环运行
rclpy.spin(Node("first_node"))

新建两个终端(A、B),终端A运行first_node.py

python3 first_node.py

终端B运行命令查看当前ROS2系统中的节点

ros2 node list

可看到成功创建了一个名为first_node的节点

first_node

3、创建第一个包

  1. 创建一个名字叫做 my_package 的功能包
# 创建一个名为my_package的功能包使用ament编译依赖rclpy库
ros2 pkg create my_package --build-type ament_python --dependencies rclpy

first_package

当前目录下自动生成了一个名为my_package的功能包文件夹

  1. 在my_package/my_package/目录下创建一个python文件(如second_node.py),并输入以下代码:
import rclpy
from rclpy.node import Node
def main(args=None):
    """
    ros2运行该节点的入口函数
    编写ROS2节点的一般步骤
    1. 导入库文件
    2. 初始化客户端库
    3. 新建节点对象
    4. spin循环节点
    5. 关闭客户端库
    """
    rclpy.init(args=args) # 初始化rclpy
    node = Node("node_02") # 新建一个节点
    node.get_logger().info("大家好,我是node_02.") # 输出日志信息
    rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)
    rclpy.shutdown() # 关闭rclpy
  1. 然后声明该节点:在my_package/setup.py文件中修改entry_points入口参数:
entry_points={
        'console_scripts': [
            "node2 = my_package.second_node:main"
        ],
    },

其中 node2即为 executable_namemy_package.second_node:main为该节点的入口函数路径(即my_package/my_package/second_node.py文件中的main函数)

  1. 在工作空间(第一层my_package/)下编译功能包
colcon build

colcon是ROS2推荐的构建工具,通过调用CMake或Python的setuptools等工具进行构建,支持多包构建和依赖管理

build_package

  1. 编译完成后,source安装目录下的setup.bash文件以加载环境
source install/setup.bash
  1. 运行程序
ros2 run my_package node2

可看到终端输出了日志信息

run_package

  1. 面向对象编程方式创建节点

节点的概念很适合面向对象编程,我们可以将节点封装成一个类,继承自Node类,并在类中定义节点的功能和行为

my_package/my_package/third_node.py

import rclpy
from rclpy.node import Node

class Node03(Node):
    """
    创建一个名为Node03的节点类,继承自Node类
    初始化时输出一句日志信息
    """
    def __init__(self,name):
        super().__init__(name) # 初始化父类Node
        self.get_logger().info(f"大家好,我是{name}.") # 输出日志信息

def main(args=None):
    rclpy.init(args=args) # 初始化rclpy
    node = Node03("node_03") # 新建一个节点对象,传入节点名称参数
    rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)
    rclpy.shutdown() # 关闭rclpy,正常无法到达该语句

声明该节点

entry_points={
        'console_scripts': [
            "node2 = my_package.second_node:main",
            "node3 = my_package.third_node:main"
        ],
    },

按上述步骤编译运行

OOP