ROS2入门不迷路:从零搭建环境到跑通最小Demo(逻辑+代码全解析)
标签:#ROS2 #机器人操作系统 #Humble #入门教程 #C++
前言
刚接触ROS2的新手,最怕的就是环境装半天装不好、代码跑不通不知道哪错了。本文从零开始,用国内一键脚本装环境,通过话题通信和服务通信两个最小Demo,把ROS2最核心的通信逻辑讲清楚。代码注释适中,适合想快速上手跑通的新手。
废话不多说,直接开干。
一、环境搭建
1.1 一键安装(推荐国内用户)
用鱼香ROS的一键脚本,省心省力:
wgethttp://fishros.com/install-Ofishros&&.fishros运行后选择安装ROS2 Humble Desktop,装完再跑一次脚本,配置 rosdep。
1.2 验证安装
ros2 doctor输出All checks passed就完事,环境没问题。
二、验证环境:跑通内置Demo
ROS2自带了示例节点,先跑一下确认环境没问题。
打开两个终端,分别执行:
# 终端1:发布消息ros2 run demo_nodes_cpp talker# 终端2:接收消息ros2 run demo_nodes_cpp listener终端2能持续收到终端1发的消息,说明通信链路通了,环境OK。
三、话题通信:自己写最小Demo
3.1 核心逻辑串一下
话题通信就是发布/订阅模式,类似广播电台:
- 发布端:创建节点 → 创建发布者(指定话题名)→ 循环发消息
- 订阅端:创建节点 → 创建订阅者(指定同一个话题名)→ 收到消息触发回调
- 两边话题名对得上,就能通
3.2 建包
mkdir-p~/ros2_ws/srccd~/ros2_ws/src ros2 pkg create demo --build-type ament_cmake--dependenciesrclcpp std_msgs3.3 发布端talker.cpp
在src/demo/src/下新建talker.cpp:
#include"rclcpp/rclcpp.hpp"#include"std_msgs/msg/string.hpp"usingnamespacestd::chrono_literals;intmain(intargc,char**argv){rclcpp::init(argc,argv);// 初始化ROS2autonode=rclcpp::Node::make_shared("talker");// 创建节点// 创建发布者,话题名"chatter",队列长度10autopub=node->create_publisher<std_msgs::msg::String>("chatter",10);std_msgs::msg::String msg;msg.data="hello";rclcpp::Raterate(1s);// 每秒发一次while(rclcpp::ok()){pub->publish(msg);// 发消息RCLCPP_INFO(node->get_logger(),"发了: %s",msg.data.c_str());rate.sleep();}rclcpp::shutdown();return0;}3.4 订阅端listener.cpp
在src/demo/src/下新建listener.cpp:
#include"rclcpp/rclcpp.hpp"#include"std_msgs/msg/string.hpp"intmain(intargc,char**argv){rclcpp::init(argc,argv);autonode=rclcpp::Node::make_shared("listener");// 订阅"chatter"话题,收到消息执行回调autosub=node->create_subscription<std_msgs::msg::String>("chatter",10,[](conststd_msgs::msg::String::SharedPtr msg){RCLCPP_INFO(rclcpp::get_logger("listener"),"收到: %s",msg->data.c_str());});rclcpp::spin(node);// 阻塞等待消息rclcpp::shutdown();return0;}3.5 修改CMakeLists.txt
在src/demo/CMakeLists.txt末尾添加:
add_executable(talker src/talker.cpp) ament_target_dependencies(talker rclcpp std_msgs) add_executable(listener src/listener.cpp) ament_target_dependencies(listener rclcpp std_msgs) install(TARGETS talker listener DESTINATION lib/${PROJECT_NAME} ) ament_package()3.6 编译运行
cd~/ros2_ws colcon build --packages-select demosourceinstall/setup.bash打开两个终端:
# 终端1ros2 run demo talker# 终端2ros2 run demo listener终端2持续打印收到: hello,通了。
四、服务通信:请求/响应模式
4.1 核心逻辑串一下
服务通信是一问一答模式,类似打电话:
- 服务端:创建节点 → 创建服务(指定服务名+回调函数)→ 阻塞等待请求
- 客户端:创建节点 → 创建客户端(指定同一个服务名)→ 构造请求 → 发送并等待结果
- 两边服务名对得上,客户端才能拿到返回值
4.2 建包
cd~/ros2_ws/src ros2 pkg create svc_demo --build-type ament_cmake--dependenciesrclcpp example_interfaces4.3 服务端server.cpp
在src/svc_demo/src/下新建server.cpp:
#include"rclcpp/rclcpp.hpp"#include"example_interfaces/srv/add_two_ints.hpp"// 回调函数:收到请求时执行,计算a+bvoidhandle(conststd::shared_ptr<example_interfaces::srv::AddTwoInts::Request>req,std::shared_ptr<example_interfaces::srv::AddTwoInts::Response>resp){resp->sum=req->a+req->b;RCLCPP_INFO(rclcpp::get_logger("server"),"%ld + %ld = %ld",req->a,req->b,resp->sum);}intmain(intargc,char**argv){rclcpp::init(argc,argv);autonode=rclcpp::Node::make_shared("server");// 创建服务,服务名"add_two_ints"autosrv=node->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints",handle);RCLCPP_INFO(rclcpp::get_logger("server"),"服务已启动");rclcpp::spin(node);// 阻塞等待请求rclcpp::shutdown();return0;}4.4 客户端client.cpp
在src/svc_demo/src/下新建client.cpp:
#include"rclcpp/rclcpp.hpp"#include"example_interfaces/srv/add_two_ints.hpp"intmain(intargc,char**argv){rclcpp::init(argc,argv);autonode=rclcpp::Node::make_shared("client");// 创建客户端,连接"add_two_ints"服务autoclient=node->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints");// 构造请求autoreq=std::make_shared<example_interfaces::srv::AddTwoInts::Request>();req->a=3;req->b=7;// 等服务端启动while(!client->wait_for_service(std::chrono::seconds(1))){RCLCPP_INFO(rclcpp::get_logger("client"),"等服务端...");}// 发请求并等待结果autoresult=client->async_send_request(req);if(rclcpp::spin_until_future_complete(node,result)==rclcpp::FutureReturnCode::SUCCESS){RCLCPP_INFO(rclcpp::get_logger("client"),"结果: %ld",result.get()->sum);}rclcpp::shutdown();return0;}4.5 修改CMakeLists.txt
在src/svc_demo/CMakeLists.txt末尾添加:
add_executable(server src/server.cpp) ament_target_dependencies(server rclcpp example_interfaces) add_executable(client src/client.cpp) ament_target_dependencies(client rclcpp example_interfaces) install(TARGETS server client DESTINATION lib/${PROJECT_NAME} ) ament_package()4.6 编译运行
cd~/ros2_ws colcon build --packages-select svc_demosourceinstall/setup.bash先跑服务端,再跑客户端:
# 终端1ros2 run svc_demo server# 终端2ros2 run svc_demo client服务端打印3 + 7 = 10,客户端打印结果: 10,通了。
五、总结
| 类型 | 模式 | 逻辑 | 适用场景 |
|---|---|---|---|
| 话题 | 发布/订阅 | 发布端一直发,订阅端一直收 | 传感器数据、状态广播 |
| 服务 | 请求/响应 | 客户端问,服务端答,一问一答 | 计算、查询、开关控制 |
两套通信搞明白,ROS2就算入门了。
常见问题
- colcon build 报错:确认执行了
source install/setup.bash - ros2 run 找不到节点:确认编译成功,包名和节点名正确
- 客户端等服务超时:确认服务名一致,服务端先启动