“快速入门ROS2与C++”的实战计划

背景

结合"有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开发完全可行。

相关推荐
一灯架构12 小时前
90%的人答错!一文带你彻底搞懂ArrayList
java·后端
踏着七彩祥云的小丑12 小时前
pytest——Mark标记
开发语言·python·pytest
Dream of maid12 小时前
Python12(网络编程)
开发语言·网络·php
W230357657312 小时前
经典算法:最长上升子序列(LIS)深度解析 C++ 实现
开发语言·c++·算法
.Ashy.12 小时前
2026.4.11 蓝桥杯软件类C/C++ G组山东省赛 小记
c语言·c++·蓝桥杯
Y40900112 小时前
【多线程】线程安全(1)
java·开发语言·jvm
不爱吃炸鸡柳13 小时前
Python入门第一课:零基础认识Python + 环境搭建 + 基础语法精讲
开发语言·python
布局呆星13 小时前
SpringBoot 基础入门
java·spring boot·spring
minji...13 小时前
Linux 线程同步与互斥(三) 生产者消费者模型,基于阻塞队列的生产者消费者模型的代码实现
linux·运维·服务器·开发语言·网络·c++·算法
Dxy123931021613 小时前
Python基于BERT的上下文纠错详解
开发语言·python·bert