ros_tutorials 源码详细分析

ros_tutorials 源码详细分析

工作区路径:/home/cp/work2/ros2Learn/ros2_humble/src/ros/ros_tutorials
仓库:github.com/ros/ros_tutorials

ros_tutorials 是 ROS 官方入门教程集合,包含经典 turtlesim 仿真器及 ROS 1 时代的 C++/Python 教程。在 ROS 2 Humble 工作区中,只有 turtlesim 是 ament 包、会被实际编译roscpp_tutorialsrospy_tutorials 仍为 catkin/ROS 1 遗留代码,供参考,不参与 ROS 2 构建。


1. 仓库结构总览

1
2
3
4
5
ros_tutorials/
├── ros_tutorials/ # 元包(catkin metapackage,ROS 1)
├── turtlesim/ # ★ ROS 2 核心:Qt 仿真 + 自定义 msg/srv/action
├── roscpp_tutorials/ # ROS 1 C++ 教程(catkin,未移植)
└── rospy_tutorials/ # ROS 1 Python 教程(catkin,未移植)
构建系统 ROS 2 可编译 版本 作用
turtlesim ament_cmake 1.4.3 交互式小乌龟仿真,ROS 2 官方教程标配
roscpp_tutorials catkin 0.9.1 roscpp API 分步示例
rospy_tutorials catkin 0.9.1 rospy API 分步示例
ros_tutorials catkin metapackage 0.9.1 聚合上述三包

2. 在 ROS 2 生态中的角色

flowchart LR
  subgraph tutorials [ros_tutorials]
    TS[turtlesim_node\nQt GUI]
    TELEOP[turtle_teleop_key]
    DRAW[draw_square]
    MIMIC[mimic]
  end

  subgraph concepts [演示的 ROS 2 概念]
    TOPIC[Topic 发布/订阅]
    SRV[Service 请求/响应]
    ACT[Action 长时间任务]
    PARAM[Parameter 动态配置]
  end

  subgraph users [典型使用者]
    DOC[官方文档教程]
    LEARN[初学者实验]
    TEST[多节点/多命名空间测试]
  end

  TS --> TOPIC & SRV & ACT & PARAM
  TELEOP --> TOPIC & ACT
  DRAW --> TOPIC & SRV
  MIMIC --> TOPIC
  tutorials --> users

turtlesim 是 ROS 2 “Hello World” 级演示平台:比 demo_nodes_cpp 更直观,覆盖 topic、service、action、parameter 四类通信原语。


3. turtlesim — 架构设计

3.1 类层次

1
2
3
4
5
6
TurtleApp (QApplication + rclcpp::init)
└── TurtleFrame (QFrame, 500×500 画布)
├── QTimer 16ms → onUpdate() → spin_some + updateTurtles
├── 全局服务: spawn / kill / clear / reset
└── map<string, TurtlePtr> turtles_
└── Turtle (单只乌龟的 ROS 接口 + 运动学)
文件 职责
TurtleApp turtlesim.cpp 初始化 rclcpp + Qt 事件循环
TurtleFrame turtle_frame.cpp/h 画布、定时器、乌龟生命周期管理
Turtle turtle.cpp/h 单龟 ROS 接口、运动积分、绘制

3.2 Qt + rclcpp 融合模式

核心在 TurtleFrame::onUpdate()

1
2
3
4
5
6
7
8
9
10
11
12
void TurtleFrame::onUpdate()
{
if (!rclcpp::ok())
{
close();
return;
}

rclcpp::spin_some(nh_);

updateTurtles();
}
  • QTimer 16ms(约 60Hz)驱动 GUI 刷新
  • 每帧调用 rclcpp::spin_some 处理回调,避免阻塞 Qt 主线程
  • 这是 GUI 节点中 rclcpp 与 Qt 集成的经典模式

3.3 坐标系

  • 内部仿真:pos_ 以米为单位,Y 轴向下(屏幕坐标)
  • 对外 Pose.msg:Y 轴向上(y = canvas_height - pos_.y()
  • 角度 theta:弧度,逆时针为正

4. ROS 2 接口一览

4.1 节点级服务(/turtlesim 节点)

服务 类型 功能
/spawn turtlesim/srv/Spawn 创建新乌龟
/kill turtlesim/srv/Kill 删除指定乌龟
/clear std_srvs/Empty 清除轨迹
/reset std_srvs/Empty 重置为单龟初始状态

4.2 每只乌龟的接口(以 turtle1 为例)

类型 名称 消息/服务类型
订阅 /turtle1/cmd_vel geometry_msgs/Twist
发布 /turtle1/pose turtlesim/Pose
发布 /turtle1/color_sensor turtlesim/Color
服务 /turtle1/set_pen turtlesim/SetPen
服务 /turtle1/teleport_relative turtlesim/TeleportRelative
服务 /turtle1/teleport_absolute turtlesim/TeleportAbsolute
Action /turtle1/rotate_absolute turtlesim/RotateAbsolute

4.3 自定义消息/服务/Action

Pose.msg — 位姿 + 速度反馈:

1
2
float32 x, y, theta
float32 linear_velocity, angular_velocity

RotateAbsolute.action — ROS 2 Action 教程示例:

1
2
3
4
5
6
7
8
# Goal
float32 theta # 目标朝向(弧度)
---
# Result
float32 delta # 相对起始角位移
---
# Feedback
float32 remaining # 剩余转角

Spawn.srv — 可选名称,空则自动生成 turtle2turtle3


5. Turtle 类核心逻辑

5.1 构造:注册 ROS 接口

1
2
3
4
5
6
7
8
9
10
Turtle::Turtle(...)
{
rclcpp::QoS qos(rclcpp::KeepLast(7));
velocity_sub_ = nh_->create_subscription<geometry_msgs::msg::Twist>(
real_name + "/cmd_vel", qos, ...);
pose_pub_ = nh_->create_publisher<turtlesim::msg::Pose>(real_name + "/pose", qos);
...
rotate_absolute_action_server_ = rclcpp_action::create_server<...>(
nh, real_name + "/rotate_absolute", ...);
}

5.2 运动学更新(update

每帧 dt ≈ 0.016s 执行:

  1. Teleport 请求(相对/绝对瞬移,可画线)
  2. Action 旋转:向目标角 theta 以 ±1.0 rad/s 旋转,发布 feedback/result
  3. 速度超时:超过 1 秒无 cmd_vel 则速度归零
  4. 积分运动
1
2
3
4
5
6
orient_ = orient_ + ang_vel_ * dt;
orient_ = normalizeAngle(orient_);
pos_.rx() += std::cos(orient_) * lin_vel_x_ * dt
- std::sin(orient_) * lin_vel_y_ * dt;
pos_.ry() -= std::cos(orient_) * lin_vel_y_ * dt
+ std::sin(orient_) * lin_vel_x_ * dt;
  1. 边界 clamp — 撞墙警告并限制在画布内
  2. 发布 pose 和 color_sensor(读取轨迹图像像素 RGB)

5.3 Action 与 cmd_vel 互斥

收到 cmd_vel 时会 abort 正在执行的 rotate_absolute goal;收到新 rotation goal 也会 abort 前一个。体现 Action 与连续控制的分工。


6. TurtleFrame 管理逻辑

6.1 启动

  • 声明参数 background_r/g/b(0–255,默认蓝紫色 #4556ff
  • share/turtlesim/images/ 加载 9 种乌龟皮肤(ardent, foxy, humble 等发行版命名)
  • 默认 spawn 一只 turtle1 在画布中心
  • 订阅 /parameter_events 以响应背景色变更

6.2 乌龟命名

1
2
3
4
5
6
7
if (real_name.empty())
{
do {
ss << "turtle" << ++id_counter_;
real_name = ss.str();
} while (hasTurtle(real_name));
}

空名称自动生成;重名 spawn 返回失败。


7. 教程可执行文件

CMakeLists 构建 4 个目标:

可执行文件 源码 演示内容
turtlesim_node src/*.cpp 主仿真器
turtle_teleop_key teleop_turtle_key.cpp 键盘控制 + Action 客户端
draw_square draw_square.cpp 状态机画正方形
mimic mimic.cpp 订阅 pose 转发 cmd_vel

7.1 turtle_teleop_key

  • 原始终端模式读键盘(Unix termios / Windows ReadConsoleInput
  • 方向键 → 发布 Twistturtle1/cmd_vel
  • G/B/V/C/D/E/R/T → 发送 RotateAbsolute action goal
  • 独立线程 rclcpp::spin 处理 action 回调

7.2 draw_square

有限状态机:FORWARD → STOP_FORWARD → TURN → STOP_TURN → ...

  • 订阅 turtle1/pose 获取反馈
  • 发布 turtle1/cmd_vel 控制运动
  • 启动时调用 /reset 服务
  • 典型 闭环控制 入门示例

7.3 mimic

1
2
3
4
5
6
twist_pub_ = this->create_publisher<geometry_msgs::msg::Twist>("output/cmd_vel", 1);
pose_sub_ = this->create_subscription<turtlesim::msg::Pose>(
"input/pose", 1, ...);
// 将 input 龟的速度复制给 output 龟
twist.angular.z = pose->angular_velocity;
twist.linear.x = pose->linear_velocity;

配合 remapping 可实现「一只龟模仿另一只」:

1
2
3
ros2 run turtlesim mimic --ros-args \
-r input/pose:=/turtle1/pose \
-r output/cmd_vel:=/turtle2/cmd_vel

8. 多实例与 Launch

1
2
3
4
5
6
return LaunchDescription([
launch_ros.actions.Node(
namespace= "turtlesim1", package='turtlesim', executable='turtlesim_node', ...),
launch_ros.actions.Node(
namespace= "turtlesim2", package='turtlesim', executable='turtlesim_node', ...),
])

命名空间隔离后,话题变为 /turtlesim1/turtle1/cmd_vel/turtlesim2/turtle1/cmd_vel,演示 namespace 机制


9. 依赖关系

1
2
3
4
5
6
turtlesim
├── rclcpp / rclcpp_action
├── geometry_msgs / std_msgs / std_srvs
├── rosidl_default_generators # 自定义接口
├── Qt5 Widgets # GUI
└── ament_index_cpp # 查找 share/images

10. roscpp_tutorials(ROS 1 遗留)

构建系统:catkin + roscpp + rosconsole

按子目录组织的 C++ 教程,覆盖 ROS 1 API:

目录 主题
talker/ / listener/ 最基本 pub/sub
add_two_ints_* Service 客户端/服务端
parameters/ 参数服务器
timers/ Timer 回调
listener_*_spin 多种 spin 模式
notify_connect/ 连接/订阅通知
node_handle_namespaces/ 命名空间
time_api/sleep/ 时间 API

代码使用 #include "ros/ros.h",带 %Tag(...)% 标记供文档系统自动抽取。ROS 2 等价教程在 ros2/examples 和官方文档中,不在此包。


11. rospy_tutorials(ROS 1 遗留)

构建系统:catkin + rospy

按编号组织的 Python 教程:

目录 主题
001_talker_listener/ pub/sub 基础
002_headers/ 消息 header
003_listener_with_user_data/ 回调 userdata
004_listener_subscribe_notify/ 订阅通知
005_add_two_ints/ Service
006_parameters/ 参数
007_connection_header/ 连接头
008_on_shutdown/ 关闭钩子
009_advanced_publish/ 高级发布

含与 roscpp_tutorials 交叉测试的 launch 文件(C++ ↔ Python 互通)。同样未移植到 rclpy。


12. 典型使用流程

1
2
3
4
5
6
7
8
9
10
11
12
13
# 终端 1:启动仿真
ros2 run turtlesim turtlesim_node

# 终端 2:键盘控制
ros2 run turtlesim turtle_teleop_key

# 或:自动画正方形
ros2 run turtlesim draw_square

# 查看接口
ros2 topic list
ros2 service list
ros2 action list

常用 CLI 实验:

1
2
3
4
ros2 service call /spawn turtlesim/srv/Spawn "{x: 2.0, y: 2.0, theta: 0.0, name: ''}"
ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist \
"{linear: {x: 1.0}, angular: {z: 0.5}}"
ros2 param set /turtlesim background_r 200

13. 设计特点与局限

特点 说明
教学优先 API 覆盖全面,代码可读性高
Qt 集成 spin_some + QTimer 经典 GUI 模式
多龟支持 spawn/kill 动态管理
ROS 2 Action RotateAbsolute 是官方 action 教程载体
发行版彩蛋 乌龟皮肤命名对应 ROS 发行版
局限 说明
无物理仿真 简单运动学积分,非 Gazebo
2D 平面 仅 x/y/theta
ROS 1 教程未移植 roscpp/rospy tutorials 在 Humble 中不编译
单线程 spin_some 不适合高并发重计算
无 TF 不发布坐标变换(与真实机器人栈不同)

14. 推荐阅读顺序

  1. 快速体验:运行 turtlesim_node + turtle_teleop_key
  2. 主程序turtlesim.cppturtle_frame.cppturtle.cpp
  3. 接口定义msg/srv/action/
  4. 教程节点draw_square.cpp(闭环)→ mimic.cpp(remapping)→ teleop_turtle_key.cpp(action)
  5. 对比 ROS 1 教程roscpp_tutorials/talker/talker.cpp 与 ROS 2 demo_nodes_cpp 的差异
  6. Launchmultisim.launch.py 理解 namespace

15. 小结

ros_tutorials 仓库是 ROS 官方教程的历史集合:在 ROS 2 Humble 中,实际可用的是 turtlesim——一个 Qt + rclcpp 的小乌龟仿真器,完整演示 Topic、Service、Action、Parameter 四大通信机制,并附带键盘遥控、画正方形、mimic 等示例节点。roscpp_tutorialsrospy_tutorials 保留 ROS 1 catkin 代码,供 API 对比参考,但不参与 ROS 2 构建。

如果你希望,我可以把本文写入 ros2doc/ros/ros_tutorials 源码详细分析.md,或继续分析 draw_square 状态机与 pose 闭环控制的数学细节

文章互动

阅读 --

留言

0 条留言

正在加载留言…