背景
结合"有C++基础但遗忘"和"需要快速应用于机器人项目"的背景,本计划采用最小必要知识+项目驱动的方式,让您在一周内恢复C++手感并掌握ROS2核心。
一、学习目标与时间分配(1周速成)

二、 C++ 快速复习清单(针对ROS2)
无需重学所有C++,只需聚焦ROS2代码中高频出现的特性:
1. 类与对象(最重要)
cpp
class RobotController : public rclcpp::Node { // 继承
public:
RobotController() : Node("robot_controller") { // 构造函数
// 初始化
}
private:
int count_; // 成员变量
};
2. 智能指针(ROS2中无处不在)
cpp
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("my_node");
auto timer = node->create_wall_timer(...); // auto自动类型推导
3. Lambda表达式(回调函数常用)
cpp
auto callback = [this](const std_msgs::msg::String::SharedPtr msg) -> void {
RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());
};
4. STL容器(常用vector, map)
cpp
std::vector<std::string> topics = {"cmd_vel", "odom"};
std::map<std::string, int> sensor_data;
5. CMake基础(编译必备)
cmake
find_package(rclcpp REQUIRED)
add_executable(my_node src/my_node.cpp)
ament_target_dependencies(my_node rclcpp std_msgs)
复习方法:直接打开一个ROS2 C++示例代码(如下文),对照上述清单查阅理解,比单纯看书更快。
三、 ROS2 极简核心概念(您需要知道的)
节点 (Node):一个可执行程序,如导航节点、感知节点。你的算法模块通常就是一个或多个节点。
话题 (Topic):异步通信的管道,用于持续发布/订阅数据流(如:机器人位置、摄像头图像)。
服务 (Service):同步请求-响应通信,用于执行一次性命令(如:请求路径规划、查询状态)。
消息 (Message):话题或服务中传递的数据结构(.msg或.srv文件定义)。
工作空间 (Workspace) 与 包 (Package):ROS2代码的组织方式。
四、 手把手实战:从零创建您的第一个ROS2节点
请严格按照以下步骤操作,这是最快的学习路径。
步骤1:环境设置(一次性)
bash
# 1. 安装ROS2(假设Ubuntu 22.04,使用Humble版本)
# 按照官方教程:https://docs.ros.org/en/humble/Installation.html
# 2. 创建并进入工作空间
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws
# 3. 每次新开终端,source环境
source /opt/ros/humble/setup.bash # 请根据您的ROS2版本调整
步骤2:创建包和节点(核心)
bash
# 1. 进入src目录,创建C++包
cd ~/ros2_ws/src
ros2 pkg create my_first_robot_pkg --build-type ament_cmake --dependencies rclcpp std_msgs
# 2. 创建C++源文件
cd my_first_robot_pkg/src
touch robot_publisher.cpp robot_subscriber.cpp
步骤3:编写发布者节点 (robot_publisher.cpp)
将以下代码复制进去,重点看注释:
cpp
// 1. 引入头文件(您提供的部分)
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
#include <chrono>
#include <string> // 可选,但处理字符串时常用
// 2. 使用命名空间简化代码(高效实践)
using namespace std::chrono_literals; // 允许使用 `500ms` 这样的字面量
using std::placeholders::_1; // 用于 std::bind 占位符
// 3. 定义节点类(面向对象,封装相关功能)
class RobotStatusPublisher : public rclcpp::Node
{
public:
// 3.1 构造函数:初始化节点、发布者和定时器
RobotStatusPublisher() : Node("robot_status_publisher"), count_(0)
{
// 创建发布者:发布到 "robot_status" 话题,队列大小为10(缓存最新10条消息)
publisher_ = this->create_publisher<std_msgs::msg::String>("robot_status", 10);
// 创建定时器:每1000ms触发一次 timer_callback 函数
timer_ = this->create_wall_timer(
1000ms,
std::bind(&RobotStatusPublisher::timer_callback, this)
);
// 初始化日志
RCLCPP_INFO(this->get_logger(), "Robot Status Publisher 节点已启动,正在发布状态...");
}
private:
// 3.2 定时器回调函数(核心业务逻辑)
void timer_callback()
{
// 创建消息实例
auto message = std_msgs::msg::String();
// 填充消息数据
message.data = "Robot Status #" + std::to_string(count_++) + ": 系统正常,电池电量 85%";
// 发布消息
publisher_->publish(message);
// 记录日志(使用ROS2的日志宏,可分级:DEBUG, INFO, WARN, ERROR, FATAL)
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
}
// 3.3 类的成员变量(私有,保护数据)
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
rclcpp::TimerBase::SharedPtr timer_;
size_t count_; // 内部计数器
};
// 4. 主函数
int main(int argc, char * argv[])
{
// 4.1 初始化ROS2 C++客户端库
rclcpp::init(argc, argv);
// 4.2 创建节点实例(使用智能指针管理内存,避免泄漏)
auto node = std::make_shared<RobotStatusPublisher>();
// 4.3 保持节点运行,等待回调(阻塞,直到收到关闭信号,如Ctrl+C)
rclcpp::spin(node);
// 4.4 关闭ROS2,清理资源
rclcpp::shutdown();
return 0;
}
步骤4:编写订阅者节点 (robot_subscriber.cpp)
cpp
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class RobotSubscriber : public rclcpp::Node {
public:
RobotSubscriber() : Node("robot_subscriber") {
// 1. 创建订阅者,监听"robot_status"话题
subscription_ = this->create_subscription<std_msgs::msg::String>(
"robot_status",
10,
// 2. 使用Lambda表达式定义回调函数
[this](const std_msgs::msg::String::SharedPtr msg) -> void {
RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());
}
);
}
private:
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
int main(int argc, char* argv[]) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<RobotSubscriber>());
rclcpp::shutdown();
return 0;
}
步骤5:编译与运行
cpp
# 1. 修改CMakeLists.txt(包内的)
# 在 my_first_robot_pkg/CMakeLists.txt 中,在 find_package 后添加:
add_executable(robot_publisher src/robot_publisher.cpp)
ament_target_dependencies(robot_publisher rclcpp std_msgs)
add_executable(robot_subscriber src/robot_subscriber.cpp)
ament_target_dependencies(robot_subscriber rclcpp std_msgs)
# 以及(通常已存在):
install(TARGETS robot_publisher robot_subscriber
DESTINATION lib/${PROJECT_NAME})
# 2. 编译整个工作空间
cd ~/ros2_ws
colcon build --packages-select my_first_robot_pkg
# 3. 运行(开三个终端)
# 终端1:运行发布者
source install/setup.bash
ros2 run my_first_robot_pkg robot_publisher
# 终端2:运行订阅者
source install/setup.bash
ros2 run my_first_robot_pkg robot_subscriber
# 终端3:查看话题列表(可选)
ros2 topic list
ros2 topic echo /robot_status
五、 下一步:应用到的"xiaohushi"项目
定义自定义消息:为导诊任务创建消息类型(如 PatientQuery.msg, NavigationGoal.srv)。
集成您的算法:将您的Python算法模块封装为C++节点,或通过ROS2的进程间通信调用。
学习关键工具:
bash
ros2 node list # 查看所有运行中的节点
ros2 topic info /xxx # 查看话题详情
ros2 service call # 手动调用服务
ros2 bag record # 录制数据包,用于算法调试
总结:不要陷入C++细节或ROS2所有功能。目标驱动:先让一个发布者和订阅者跑起来,然后思考如何将您的导诊算法模块改造成一个ROS2节点。遇到具体问题(如:如何定义自定义消息、如何与现有Python代码交互)时,再针对性搜索解决。您有扎实的工程基础,一周内上手ROS2开发完全可行。