ROS

Robot Operating System 机器人操作系统框架,涵盖 ROS/ROS2 开发、工具链使用、包管理与系统集成实践。

Ubuntu 24.04 安装 ROS 2 Jazzy 完整指南

ROS 2 Jazzy

什么是 ROS 2?

ROS 2(Robot Operating System 2)是 ROS 的下一代版本,是一个开源的机器人操作系统框架。ROS 2 专为现代机器人应用设计,提供了分布式计算、实时性能、多平台支持和更好的安全性等特性。

ROS 2 的主要特点

  • 分布式架构:支持多机器人和多计算机之间的通信
  • 实时性能:提供实时通信和调度能力
  • 跨平台支持:支持 Linux、Windows 和 macOS
  • 多种编程语言:支持 C++、Python、Java 等
  • 模块化设计:通过节点(Node)和话题(Topic)实现松耦合的通信
  • 丰富的工具链:提供命令行工具、可视化工具(rqt)和调试工具

ROS 2 Jazzy 是 ROS 2 的一个长期支持(LTS)版本,支持 Ubuntu Noble 24.04 的 amd64 和 arm64 架构。在网络通畅的情况下,安装较为顺利,未发现明显问题。

1. 系统环境准备

1.1 设置 Locale

设置系统 locale 为 UTF-8 编码,确保 ROS 2 正常运行:

# 检查当前 locale
locale

# 如果不是 UTF-8,先安装 locales
sudo apt update && sudo apt install locales

# 生成 en_US.UTF-8 locale
sudo locale-gen en_US en_US.UTF-8

# 更新系统 locale
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8

# 设置当前会话的 locale
export LANG=en_US.UTF-8

# 再次检查 locale 确认设置成功
locale

1.2 添加 ROS 2 APT 源

确保启用 Ubuntu Universe 仓库,并添加 ROS 2 的 APT 源:

# 安装软件属性管理工具
sudo apt install software-properties-common

# 启用 Universe 仓库
sudo add-apt-repository universe

# 安装 curl(如果尚未安装)
sudo apt update && sudo apt install curl -y

# 获取最新版本的 ROS APT 源包
export ROS_APT_SOURCE_VERSION=$(curl -s https://api.github.com/repos/ros-infrastructure/ros-apt-source/releases/latest | grep -F "tag_name" | awk -F\" '{print $4}')

# 下载 ROS 2 APT 源 deb 包
curl -L -o /tmp/ros2-apt-source.deb "https://github.com/ros-infrastructure/ros-apt-source/releases/download/${ROS_APT_SOURCE_VERSION}/ros2-apt-source_${ROS_APT_SOURCE_VERSION}.$(. /etc/os-release && echo ${UBUNTU_CODENAME:-${VERSION_CODENAME}})_all.deb"

# 安装 APT 源包
sudo dpkg -i /tmp/ros2-apt-source.deb

1.3 安装开发工具

# 更新包列表并安装 ROS 开发工具
sudo apt update && sudo apt install ros-dev-tools

2. 安装 ROS 2

2.1 安装 ROS 2 Desktop

# 更新系统包
sudo apt update
sudo apt upgrade

# 安装 ROS 2 Jazzy Desktop(包含可视化工具)
sudo apt install ros-jazzy-desktop

2.2 设置环境变量

# 临时设置当前会话的环境变量
source /opt/ros/jazzy/setup.bash

3. 测试 FastDDS 通信

FastDDS 是 ROS 2 的默认通信中间件。通过以下步骤测试安装是否成功:

  1. 在第一个终端中启动 talker 节点
ros2 run demo_nodes_cpp talker
  1. 在第二个终端中启动 listener 节点
# 先设置环境变量
source /opt/ros/jazzy/setup.bash

# 运行 listener
ros2 run demo_nodes_py listener

如果两个终端都能正常打印消息,说明安装成功:

FastDDS 测试

4. 配置 Shell 启动脚本

ROS 2 的 shell 工作区概念允许在同一台电脑上同时安装多个不同版本的 ROS,通过启动脚本来切换版本。如果不加载安装文件,您将无法访问 ROS 2 命令,也无法查找或使用 ROS 2 软件包。

4.1 添加到 ~/.bashrc

# 编辑 ~/.bashrc 文件(使用您喜欢的编辑器,如 nano、vim 或 subl)
nano ~/.bashrc

# 或者使用 Sublime Text
subl ~/.bashrc

在文件末尾添加以下内容:

source /opt/ros/jazzy/setup.bash

4.2 使配置生效

# 重新加载配置
source ~/.bashrc

4.3 验证配置

打开一个新的命令行窗口,直接输入 ros2,如果显示如下内容,说明配置成功:

ROS 2 初始化

5. 使用 Turtlesim

Turtlesim 是一个轻量级的 ROS 2 学习模拟器。它以最基本的层面演示了 ROS 2 的功能,让您了解以后使用真实机器人或机器人模拟器时会遇到的问题。

5.1 安装 Turtlesim

sudo apt update
sudo apt install ros-jazzy-turtlesim

5.2 验证安装

ros2 pkg executables turtlesim

如果显示以下内容,说明安装成功:

turtlesim draw_square
turtlesim mimic
turtlesim turtle_teleop_key
turtlesim turtlesim_node

5.3 运行 Turtlesim

  1. 启动 Turtlesim 节点
ros2 run turtlesim turtlesim_node
  1. 在另一个终端中启动键盘控制节点
ros2 run turtlesim turtle_teleop_key

保持 turtle_teleop_key 的窗口处于激活状态,通过方向键可以控制乌龟移动。此时乌龟指代的是无人机的移动和控制方式。

Turtlesim 键盘控制

6. 安装和使用 rqt

rqt 是 ROS 2 的图形用户界面 (GUI) 工具。rqt 中的所有操作都可以在命令行中完成,但 rqt 提供了一种更友好的方式来操作 ROS 2 元素。

6.1 安装 rqt

sudo apt update
sudo apt install '~nros-jazzy-rqt*'

6.2 运行 rqt

rqt

6.3 使用 rqt 调用服务

在 Turtlesim 运行时,可以通过 rqt 调用服务:

  1. 从下拉菜单选择 PluginsServicesService Caller
  2. 选择服务 /spawn
  3. 在此处可以直接调整生成位置(x、y 坐标)、实例名称等参数
  4. 点击 Call 按钮

rqt 服务调用器

如果服务调用成功,您应该会看到一只新的海龟(同样是随机设计的)在您输入的 x 和 y 坐标处生成。

调用 spawn 服务

6.4 控制新创建的海龟实例

如果要控制新创建的实例 turtle2,可以在新的终端中执行:

ros2 run turtlesim turtle_teleop_key --ros-args --remap turtle1/cmd_vel:=turtle2/cmd_vel

然后在这个终端控制即可。

如果您刷新 rqt 中的服务列表,您还会看到除了 /turtle1/... 之外,现在还有与新海龟相关的服务 /turtle2/...


参考文档

理解 ROS 2 的 node 和 topic

1. 理解 node

node 是 ROS 2 实现模块化的基本组件。ROS 中的每个 node 都应负责单一的模块化功能,例如控制车轮电机或发布来自激光测距仪的传感器数据。每个 node 都可以通过 topic、服务、动作或参数与其他 node 发送和接收数据。

一个完整的机器人系统由许多协同工作的 node 组成。在 ROS 2 中,一个可执行文件(C++ 程序、Python 程序等)可以包含一个或多个 node。

ROS 2 node 交互

上图展示了两个 ROS 2 node 是如何交互的。

1.1 ROS 2 启动命令

使用以下命令启动 node:

ros2 run <package_name> <executable_name>

例如:

ros2 run demo_nodes_cpp talker

其中 demo_nodes_cpp 是包名字,talker 是可执行文件名。

1.2 查看 node 列表

node 名称可以使用以下命令查找:

ros2 node list

ROS 2 node 列表

可以看到 /talker 已经显示出来了。

1.3 node 名称重映射(Remapping)

通过 --remap 参数可以重映射 node 名称:

ros2 run turtlesim turtlesim_node --ros-args --remap __node:=my_turtle

上述命令中 --remap __node:=my_turtle 将 node 名称定义为 my_turtle,通过 ros2 node list 应该也可以看到这个新建的实例 /my_turtle

1.4 查看 node 信息

使用以下命令查看 node 的详细信息:

ros2 node info <node_name>

例如:

ros2 node info /talker

注意要加斜杠。

ROS 2 node 信息

2. 理解 topic

在上个章节的图片中,我们已经可以看到,publisher node 通过 topic 将信息发送给 subscriber 的过程,只要一个 node 订阅了 topic,就可以收到对应的消息。

ROS 2 将复杂的系统分解为许多模块化 node。topic 是 ROS 图的重要元素,充当 node 交换消息的总线。

单发布者单订阅者

一个 node 可以将数据发布到任意数量的 topic,并同时订阅任意数量的 topic。

多发布者多订阅者

topic 是在 node 之间以及系统不同部分之间移动数据的主要方式之一。

2.1 使用 rqt_graph 检查通信状态

通过 rqt_graph 可以可视化检查当前 ROS 2 系统的通信状态:

  1. 打开第一个终端,启动 talker node:
ros2 run demo_nodes_cpp talker
  1. 打开第二个终端,启动 listener node:
ros2 run demo_nodes_cpp listener
  1. 使用以下命令打开 rqt_graph:
ros2 run rqt_graph rqt_graph

可以看到 talker 和 listener 通过 /chatter 这个 topic 建立通信。node 正在向 topic 发布数据,并且该 node 订阅了该 topic 以接收数据。

rqt_graph 的突出显示功能在检查具有许多 node 和 topic 以多种不同方式连接的更复杂的系统时非常有用。

rqt_graph 可视化

2.2 查看 topic 列表

在新终端中运行以下命令将返回系统中当前活动的所有 topic 的列表:

ros2 topic list

重要:使用 -t 参数可以在括号中附加 topic 类型:

ros2 topic list -t

输出示例:

/chatter [std_msgs/msg/String]
/parameter_events [rcl_interfaces/msg/ParameterEvent]
/rosout [rcl_interfaces/msg/Log]

topic 类型是本文档的重要内容,后续对 topic 的命令行应用都基于类型进行。

2.3 查看 topic 信息

topic 不必只是一对一的交流;它们可以是一对多、多对一或多对多。通过以下命令来查看当前订阅数量:

ros2 topic info /chatter

返回示例:

Type: std_msgs/msg/String
Publisher count: 1
Subscription count: 1

2.4 查看 topic 数据

使用以下命令查看正在发布的 topic 数据:

ros2 topic echo <topic_name>

例如:

ros2 topic echo /chatter

注意 topic 名称前要加斜杠。

ROS 2 topic echo

现在返回 rqt_graph 并取消选中 “debug” 框,可以见到新增的订阅 /_ros2cli_100752,也就是刚才我们通过命令行命令 echo 创建的 node。

rqt_graph 取消 debug

2.5 查看接口/数据结构

在前面运行过了 ros2 topic list -t 后,得知了 /chatter 的接口为 [std_msgs/msg/String]

运行以下命令查看接口定义:

ros2 interface show std_msgs/msg/String

返回:

# This was originally provided as an example message.
# It is deprecated as of Foxy
# It is recommended to create your own semantically meaningful message.
# However if you would like to continue using this please use the equivalent in example_msgs.

string data

可以得知为字符串数据结构,字段为 data

2.6 发布 topic 消息

得知消息结构后,通过以下命令可以直接从终端发送命令数据到 topic 中:

ros2 topic pub <topic_name> <msg_type> '<args>'

<args> 是要传递给 topic 的实际数据,采用正确的数据结构。如上 interface 为 string data 时,data 就是构建 YAML 字符串的 key。

如下几种方式都可以发布:

  1. 构建 YAML 字符串发布
ros2 topic pub /chatter std_msgs/msg/String "{data: 'Hello from manual pub.'}"

可以看到 subscriber node 同时收到了两个 node 的信息。

手动发布信息

rqt_graph 手动发布

  1. 发布空数据
ros2 topic pub /chatter std_msgs/msg/String

因为很少会使用到手动 pub 消息,其他两种自动构建数据结构并发布的方式暂时不考虑。

消息的时间戳

当发布带时间戳的消息时,pub 有两种方法可以自动填充当前时间。对于带有 std_msgs/msg/Header 的消息,可以将 header 字段设置为 auto 来填充 stamp 字段。

ros2 topic pub /chatter std_msgs/msg/String "{header: \"auto\", data: 'Hello from manual pub.'}"

此时会报错,因为 std_msgs/msg/String 类型没有 header 字段。

2.7 查询 topic 发布频率

使用以下命令来得知对应 topic 的发布频率:

ros2 topic hz <topic>

例如:

ros2 topic hz /chatter

在检测后会返回:

average rate: 1.000 
min: 1.000s max: 1.000s std dev: 0.00021s window: 3

2.8 查询 topic 带宽

使用以下命令查询 topic 的带宽使用情况:

ros2 topic bw <topic>

例如:

ros2 topic bw /chatter

输出示例:

Subscribed to [/chatter]
49 B/s from 2 messages
Message size mean: 28 B min: 28 B max: 28 B
39 B/s from 3 messages
Message size mean: 28 B min: 28 B max: 28 B

返回带宽利用率和发布到 topic 的消息数量。

2.9 查询指定类型的 topic

列出给定类型的可用 topic 列表:

ros2 topic find <topic_type>

根据前文可以得知,topic_typeros2 topic list -t 返回的括号中的内容,例如 std_msgs/msg/String

执行:

ros2 topic find std_msgs/msg/String

输出:

/chatter

3. 总结

node 通过 topic 发布信息,允许任意数量的其他 node 订阅和访问该信息。笔记中使用 rqt_graph 和命令行工具检查了 topic 上多个 node 之间的连接。由此,可以初步理解数据如何在 ROS 2 系统中移动。


4. 参考文档

理解 ROS 2 的 Services, Params 和 Actions

1. 理解 services

services 是 ROS 图中节点通信的另一种方法。services 基于调用和响应模型,而不是主题的pub-sub模型。虽然主题允许节点订阅数据流并获取持续更新,但 services 仅在 client 专门调用时才提供数据。

节点可以使用 ROS 2 中的 services 进行通信。与主题(一种单向通信模式,其中节点发布可供一个或多个订阅者使用的信息)不同,services 是一种请求/响应模式,其中 client 向提供 services node发出请求,services 处理该请求并生成响应。

单 services client

多 services clients

1.1 查看 ROS 2 当前 services

通过 ros2 service list 返回系统中当前活动的所有 services 的列表。

在两个终端内分别运行 subscriber 和 publisher node:

ros2 run demo_nodes_cpp talker
ros2 run demo_nodes_cpp listener

执行 ros2 service list,返回:

$ ros2 service list
/listener/describe_parameters
/listener/get_parameter_types
/listener/get_parameters
/listener/get_type_description
/listener/list_parameters
/listener/set_parameters
/listener/set_parameters_atomically
/rqt_gui_py_node_103317/describe_parameters
/rqt_gui_py_node_103317/get_parameter_types
/rqt_gui_py_node_103317/get_parameters
/rqt_gui_py_node_103317/get_type_description
/rqt_gui_py_node_103317/list_parameters
/rqt_gui_py_node_103317/set_parameters
/rqt_gui_py_node_103317/set_parameters_atomically
/talker/describe_parameters
/talker/get_parameter_types
/talker/get_parameters
/talker/get_type_description
/talker/list_parameters
/talker/set_parameters
/talker/set_parameters_atomically

可以观察到节点中有相同名称的多个服务,ROS 2 的大部分节点都有这些基础设施服务。

1.2 查看 ROS 2 services 类型

服务具有描述服务的请求和响应数据的结构的类型。服务类型的定义与主题类型类似,不同之处在于服务类型有两部分:一个用于请求的消息,另一个用于响应。

查看 talker 的 services 类型:

ros2 service type /talker/set_parameters

返回:

rcl_interfaces/srv/SetParameters

也可以通过在 services 列表中增加 -t 参数来直接显示所有当前 services 对应的类型:

ros2 service list -t

返回:

/listener/describe_parameters [rcl_interfaces/srv/DescribeParameters]
/listener/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
/listener/get_parameters [rcl_interfaces/srv/GetParameters]
/listener/get_type_description [type_description_interfaces/srv/GetTypeDescription]
/listener/list_parameters [rcl_interfaces/srv/ListParameters]
/listener/set_parameters [rcl_interfaces/srv/SetParameters]
/listener/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]
/rqt_gui_py_node_103317/describe_parameters [rcl_interfaces/srv/DescribeParameters]
/rqt_gui_py_node_103317/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
/rqt_gui_py_node_103317/get_parameters [rcl_interfaces/srv/GetParameters]
/rqt_gui_py_node_103317/get_type_description [type_description_interfaces/srv/GetTypeDescription]
/rqt_gui_py_node_103317/list_parameters [rcl_interfaces/srv/ListParameters]
/rqt_gui_py_node_103317/set_parameters [rcl_interfaces/srv/SetParameters]
/rqt_gui_py_node_103317/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]
/talker/describe_parameters [rcl_interfaces/srv/DescribeParameters]
/talker/get_parameter_types [rcl_interfaces/srv/GetParameterTypes]
/talker/get_parameters [rcl_interfaces/srv/GetParameters]
/talker/get_type_description [type_description_interfaces/srv/GetTypeDescription]
/talker/list_parameters [rcl_interfaces/srv/ListParameters]
/talker/set_parameters [rcl_interfaces/srv/SetParameters]
/talker/set_parameters_atomically [rcl_interfaces/srv/SetParametersAtomically]

1.3 查看 ROS 2 services 信息

ros2 service info <service_name>

返回 services 类型以及 services clients 和服务器的计数。

ros2 service info /talker/set_parameters

返回:

Type: rcl_interfaces/srv/SetParameters
Clients count: 0
Services count: 1

1.4 查询指定类型的 services

ros2 service find <type_name>

例如:

ros2 service find rcl_interfaces/srv/DescribeParameters

返回:

/listener/describe_parameters
/rqt_gui_py_node_103317/describe_parameters
/talker/describe_parameters

1.5 查看 services 的接口/协议

与 topic 的接口查询一样,只是查询主体换成了services 类型。例如:

ros2 interface show rcl_interfaces/srv/DescribeParameters

返回:

# A list of parameters of which to get the descriptor.
string[] names

---
# A list of the descriptors of all parameters requested in the same order
# as they were requested. This list has the same length as the list of
# parameters requested.
ParameterDescriptor[] descriptors
    string name
    uint8 type
    string description
    #
    string additional_constraints
    bool read_only false
    bool dynamic_typing false
    #
    FloatingPointRange[<=1] floating_point_range
        float64 from_value
        float64 to_value
        #
        #
        #
        #
        float64 step
    IntegerRange[<=1] integer_range
        int64 from_value
        int64 to_value
        #
        #
        #
        uint64 step

--- 分隔符上面是请求结构,即调用 services 需要输入的参数,下面是响应结构,即 services 返回的数据结构。注意:同一个 services 类型使用相同的数据结构/协议。

1.6 ROS 2 services 调用

从上文已经得知了调用 services 所需的数据结构,现在可以通过以下命令来调用 services:

ros2 service call <service_name> <service_type> <arguments>

这里尝试调用没有参数的 services:

ros2 service call /talker/list_parameters rcl_interfaces/srv/ListParameters

返回:

waiting for service to become available...
requester: making request: rcl_interfaces.srv.ListParameters_Request(prefixes=[], depth=0)

response:
rcl_interfaces.srv.ListParameters_Response(result=rcl_interfaces.msg.ListParametersResult(names=['qos_overrides./parameter_events.publisher.depth', 'qos_overrides./parameter_events.publisher.durability', 'qos_overrides./parameter_events.publisher.history', 'qos_overrides./parameter_events.publisher.reliability', 'start_type_description_service', 'use_sim_time'], prefixes=['qos_overrides./parameter_events.publisher']))

列出了当前节点拥有的参数。

1.7 ROS 2 services echo

查看 services clients 和 services 服务器之间的数据通信,使用命令 echo 对应的 services:

ros2 service echo <service_name | service_type> <arguments>

echo service_name 或者 service_type 都可以。

ros2 service echo 依赖于 services clients 和 services 服务器的 services 自省功能,该功能默认是禁用的。要启用它,用户必须在创建 services clients 或服务器后调用 configure_introspection

启动 services 自省演示:

ros2 launch demo_nodes_cpp introspect_services_launch.py

然后打开一个新的终端,启用 services 自省:

ros2 param set /introspection_service service_configure_introspection contents
ros2 param set /introspection_client client_configure_introspection contents

在新终端内,继续执行:

ros2 service echo --flow-style /add_two_ints

可以看到 introspection_clientintrospection_service 的通信情况,REQUEST_SENTREQUEST_RECEIVEDRESPONSE_SENTRESPONSE_RECEIVED 都被展示出来了:

---
info:
  event_type: REQUEST_SENT
  stamp:
    sec: 1762498810
    nanosec: 268090535
  client_gid: [1, 15, 178, 36, 79, 84, 235, 99, 0, 0, 0, 0, 0, 0, 21, 3]
  sequence_number: 387
  request: [{a: 2, b: 3}]
  response: []
---
info:
  event_type: REQUEST_RECEIVED
  stamp:
    sec: 1762498810
    nanosec: 268466526
  client_gid: [1, 15, 178, 36, 79, 84, 235, 99, 0, 0, 0, 0, 0, 0, 20, 4]
  sequence_number: 387
  request: [{a: 2, b: 3}]
  response: []
---
info:
  event_type: RESPONSE_SENT
  stamp:
    sec: 1762498810
    nanosec: 268538042
  client_gid: [1, 15, 178, 36, 79, 84, 235, 99, 0, 0, 0, 0, 0, 0, 20, 4]
  sequence_number: 387
  request: []
  response: [{sum: 5}]
---
info:
  event_type: RESPONSE_RECEIVED
  stamp:
    sec: 1762498810
    nanosec: 268637789
  client_gid: [1, 15, 178, 36, 79, 84, 235, 99, 0, 0, 0, 0, 0, 0, 21, 3]
  sequence_number: 387
  request: []
  response: [{sum: 5}]
---

2. 理解参数

参数就是 node 的配置,node 将参数存储为不同的数据类型,ROS 2 每个 node 都维护自己的参数。

节点使用参数来定义其默认配置值。您可以从命令行获取和设置参数值。您还可以将参数设置保存到文件中,以便在将来的会话中重新加载它们。

2.1 查看 ROS 2 的参数列表

启动 subscriber 和 publisher node:

ros2 run demo_nodes_cpp talker
ros2 run demo_nodes_cpp listener

查看参数列表:

ros2 param list

返回示例:

/introspection_client:
  client_configure_introspection
  qos_overrides./parameter_events.publisher.depth
  qos_overrides./parameter_events.publisher.durability
  qos_overrides./parameter_events.publisher.history
  qos_overrides./parameter_events.publisher.reliability
  start_type_description_service
  use_sim_time
/introspection_service:
  qos_overrides./parameter_events.publisher.depth
  qos_overrides./parameter_events.publisher.durability
  qos_overrides./parameter_events.publisher.history
  qos_overrides./parameter_events.publisher.reliability
  service_configure_introspection
  start_type_description_service
  use_sim_time
/listener:
  start_type_description_service
  use_sim_time
/talker:
  qos_overrides./parameter_events.publisher.depth
  qos_overrides./parameter_events.publisher.durability
  qos_overrides./parameter_events.publisher.history
  qos_overrides./parameter_events.publisher.reliability
  start_type_description_service
  use_sim_time

可以看到节点的 namespace 和其参数,注意:每个 node 都有 use_sim_time

2.2 查看参数类型

ros2 param get <node_name> <parameter_name>

返回类型和当前值。查看 start_type_description_service 的当前值和类型:

ros2 param get /listener start_type_description_service

返回:

Boolean value is: True

2.3 修改参数

ros2 param set <node_name> <parameter_name> <value>

尝试修改 listener 为 false:

ros2 param set /listener start_type_description_service False

返回:

Setting parameter failed: Trying to set a read-only parameter: start_type_description_service.

传参成功了,但是因为这个参数是只读的,所以无法修改。

2.4 导出 ROS 2 参数

ros2 param dump <node_name>

运行:

ros2 param dump /talker

返回:

/talker:
  ros__parameters:
    qos_overrides:
      /parameter_events:
        publisher:
          depth: 1000
          durability: volatile
          history: keep_last
          reliability: reliable
    start_type_description_service: true
    use_sim_time: false

默认将在命令行打印,也可以通过以下命令指定输出文件到当前终端的工作目录:

ros2 param dump /talker > talker.yaml

2.5 加载 ROS 2 参数

使用命令加载参数文件到运行中的 node:

ros2 param load <node_name> <parameter_file>

例如:

ros2 param load /talker talker.yaml

返回:

Set parameter qos_overrides./parameter_events.publisher.depth failed: parameter 'qos_overrides./parameter_events.publisher.depth' cannot be set because it is read-only
Set parameter qos_overrides./parameter_events.publisher.durability failed: parameter 'qos_overrides./parameter_events.publisher.durability' cannot be set because it is read-only
Set parameter qos_overrides./parameter_events.publisher.history failed: parameter 'qos_overrides./parameter_events.publisher.history' cannot be set because it is read-only
Set parameter qos_overrides./parameter_events.publisher.reliability failed: parameter 'qos_overrides./parameter_events.publisher.reliability' cannot be set because it is read-only
Set parameter start_type_description_service failed: parameter 'start_type_description_service' cannot be set because it is read-only
Set parameter use_sim_time successful

可以看到,所有的参数都被尝试设置了,仅 use_sim_time 这个非 read-only 的参数覆写成功了。只读参数只能在启动时修改,而不能在启动后修改,这就是为什么 “qos_overrides” 参数会出现一些警告。

2.6 node 启动时加载参数

ros2 run demo_nodes_cpp talker --ros-args --params-file talker.yaml

命令行不会有额外打印信息,但是 read-only 的参数此时会生效。

3. 理解 action

动作(Actions)是 ROS 2 中的通信类型之一,用于长时间运行的任务。它们由三个部分组成:目标(goal)、反馈(feedback)和结果(result)。

action 基于主题和 services 构建。它们的功能类似于 services,但 action 可以被取消。它们还提供稳定的反馈,这与返回单个响应的 services 不同。

单 action client

如图所示,action 使用 client-server 模型,与 pub sub 模型类似。action client node 将信息发送到 action server node,然后 server node 处理并返回结果。

仔细看图,client 先发一个 goal request 到 server,得到 server 的 response 后,client 发送 result request 到 server,此时 server 通过 feedback topic 与 client 保持连接,同步状态等,直到处理完成后,通过 result response 返回处理后的信息给 client。这个架构比仅用 topic 或者 services 都要复杂,但是强大、更加现代化,对复杂系统兼容性强,易于管理。

3.1 使用 action

打开两个终端,分别运行:

ros2 run turtlesim turtlesim_node
ros2 run turtlesim turtle_teleop_key

启动控制 node 后,看到提示信息:Use g|b|v|c|d|e|r|t keys to rotate to absolute orientations. 'f' to cancel a rotation.

其中 g|b|v|c|d|e|r|t 围绕键盘的 f 按键形成一个圆圈,按下对应方向的按键即命令乌龟转向对应的方向,比如按 t,是让乌龟朝向右上方。

按下 t 后,node 窗口会打印:

[INFO] [1762503823.706663289] [turtlesim]: Rotation goal completed successfully

如果在转向的过程中按下另一个方向,会打印:

[WARN] [1762503902.170788364] [turtlesim]: Rotation goal received before a previous goal finished. Aborting previous goal.

该 action 服务器选择中止第一个目标,因为它有了一个新目标。它可以选择其他目标,例如拒绝新目标或在第一个目标完成后执行第二个目标。

通过 ros2 node info /turtlesim 可以发现返回值中存在:

Service Clients:

Action Servers:
    /turtle1/rotate_absolute: turtlesim/action/RotateAbsolute
Action Clients:

可以得知这是基于 action 实现的复杂功能,而不是每个使用了 action 的 node 就天然具备的功能。

3.2 查看 ROS 2 action 列表

ros2 action list

返回:

/turtle1/rotate_absolute

和其他的 list 命令一样,可以通过 -t 来查看 action 的类型:

ros2 action list -t

返回:

/turtle1/rotate_absolute [turtlesim/action/RotateAbsolute]

3.3 查看 ROS 2 action 类型

ros2 action type <action>

例如:

ros2 action type /turtle1/rotate_absolute

返回:

turtlesim/action/RotateAbsolute

3.4 查看 ROS 2 action 信息

ros2 action info <action>

例如:

ros2 action info /turtle1/rotate_absolute

返回:

Action: /turtle1/rotate_absolute
Action clients: 1
    /teleop_turtle
Action servers: 1
    /turtlesim

可以看到 action clients 和 servers 都直接打印出来了。

3.5 查看 ROS 2 action 的接口

ros2 interface show <action_type>

例如:

ros2 interface show turtlesim/action/RotateAbsolute

返回:

# The desired heading in radians
float32 theta
---
# The angular displacement in radians to the starting position
float32 delta
---
# The remaining rotation in radians
float32 remaining

第一部分(第一个 --- 上方)是 goal 的结构,第二部分(第一个 --- 和第二个 --- 之间)是 result 的结构,最后一部分(第二个 --- 下方)是 feedback 的结构,如上图所示。

3.6 ROS 2 action 发送 goal

ros2 action send_goal <action_name> <action_type> <values>

<values> 需要是 YAML 格式。在终端输入:

ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: -1.57}" --feedback

可以看到海龟开始旋转。返回:

Waiting for an action server to become available...
Sending goal:
   theta: -1.57

Goal accepted with ID: e6092c831f994afda92f0086f220da27

Feedback:
  remaining: -3.1268222332000732

Feedback:
  remaining: -3.1108222007751465

...

Result:
  delta: 3.1200008392333984

Goal finished with status: SUCCEEDED

Feedback 展示的是剩余的弧度,直到完成。action client 通过 send goal 到 action server 来实现对海龟的旋转。

4. 总结

本文介绍了 ROS 2 中三种重要的通信和配置机制:

  1. 服务(Services):基于请求/响应模型的通信方式,适用于需要即时响应的操作。服务允许客户端向服务器发送请求并接收响应,与主题的单向通信不同,服务提供了双向通信能力。

  2. 参数(Parameters):节点的配置值,用于定义节点的默认行为。参数可以在运行时查询和修改(非只读参数),也可以保存到文件中以便在将来的会话中重新加载。只读参数只能在节点启动时设置。

  3. 动作(Actions):用于长时间运行任务的通信机制,由目标、反馈和结果三部分组成。动作基于主题和服务构建,提供了可取消的任务执行和定期反馈功能,非常适合需要长时间运行且需要进度更新的任务,如机器人导航。

机器人系统可能会使用 action 进行导航。action 目标可以告诉机器人前往某个位置。当机器人导航到该位置时,它可以沿途发送更新(即反馈),然后在到达目的地后发送最终结果消息。

通过理解这三种机制,可以更好地设计和实现 ROS 2 机器人系统,选择合适的通信方式来处理不同的任务需求。


参考文档