C++

ROS2 learning

"let us learn ROS2"

Posted by HZY on October 2, 2025
节点
1
2
3
4
5
ros2 run <pkg_name> <exe_name>
ros2 node list
ros2 node info <node_name>
ros2 run <pkg_name> <exe_name> --ros-args --remap __node:=my_turtle  #重命名
ros2 run example_parameters_rclcpp parameters_basic --ros-args -p rcl_log_revel:10 #设置参数
功能包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
sudo apt install ros-<version>-pkg-name  #安装获取
#上面这样操作会直接放进去系统目录,不需要手动source

create       Create a new ROS2 package
executables  Output a list of package specific executables
list         Output a list of available packages
prefix       Output the prefix path of a package
xml          Output the XML of the package manifest or a specific tag

ros2 pkg create <pkg-name> --build-type  {cmake,ament_cmake,maent_python} --dependencies <依赖的名字>
ros2 pkg execultables
ros2 pkg list # 列出所有包的名字
ros2 pkg prefix <pkg-name>
ros2 pkg xml 
Colcon
1
2
3
4
5
6
7
8
9
colcon build
source install/setup.bash
ros2 run
colcon build --packages-select YOUR_PKG_NAME  #只编译一个包
colcon build --packages-select YOUR_PNG_NAME --cmake-args -DBUILD_TESTING=0 #不编译测试单元
colcon test   #运行编译的包的测试
colcon build --symlink-install   #允许通过更改src下的部分文件来更改install 
colcon build --cmake-args -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 
ln -s build/compile_commands.json .
rclcpp & rclpy
1
2
3
4
5
6
7
8
ros2 pkg create example_cpp --build-type ament_cmake --dependencies rclcpp
# 需要学会如何写CMakeLists

colcon build 
source install/setup.bash
ros2 run <pkg-name>

# 这里只是简单的做了两个实例。
colcon
1
2
3
# 这里面应该是有很多知识的,不过,这里不说,后期补上


节点发现与多机通信
1
2
3
4
5
6
#linux 上 0-101 215-232可以安全使用
这里有一个域ID和UDP端口计算器的东西,我其实还灭有理解是怎么进行互相转换的

ZeroMQ 
PyZMQ
FastDDS
话题与服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 话题与接口

# GUI工具
rqt_graph

ros2 topic -h
ros2 topic list
ros2 topic list -t   #-t 表示查看消息类型,默认不显示
ros2 topic echo <topic_name>  #打印实时话题内容
ros2 topic info <topic_name>  #查看话题信息
ros2 interface show  <msg_type>   #查看消息类型
ros2 topic pub <topic_name> <msg_type> arg  #会一直loop发送arg


Publisher
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "rclcpp/init_options.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/publisher.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/timer.hpp"
#include "rclcpp/utilities.hpp"
#include <chrono>
#include <memory>
#include "std_msgs/msg/detail/string__struct.hpp"
#include "std_msgs/msg/string.hpp"
class TopicPublisher01: public rclcpp::Node
{
public: 
    TopicPublisher01(std::string name):Node(name){
        RCLCPP_INFO(this->get_logger(),"我是%s",name.c_str());
        command_publisher_ = this->create_publisher<std_msgs::msg::String>("command",10);
        timer_ = this->create_wall_timer(std::chrono::milliseconds(500),std::bind(&TopicPublisher01::timer_callback,this));

    }
private:
    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr command_publisher_;
    rclcpp::TimerBase::SharedPtr timer_;
    void timer_callback(){
        std_msgs::msg::String message;
        message.data = "forward";
        RCLCPP_INFO(this->get_logger(),"Publishing:'%s'",message.data.c_str());
        command_publisher_->publish(message);
    }
};

int main(int argc,char **argv){
    rclcpp::init(argc, argv);
    auto node = std::make_shared<TopicPublisher01>("topic_publisher_01");
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}
Subscribe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include "rclcpp/rclcpp.hpp"
#include <functional>
#include <memory>
#include <rclcpp/utilities.hpp>
#include "std_msgs/msg/string.hpp"


class TopicSubscribe01: public rclcpp::Node{
public:
    TopicSubscribe01(std::string name):Node(name){
        RCLCPP_INFO(this->get_logger(),"大家好,我是%s",name.c_str());
        command_subscribe_ = this->create_subscription<std_msgs::msg::String>("command" , 10, std::bind(&TopicSubscribe01::command_callback,this,std::placeholders::_1));

    }
private:
    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr command_subscribe_;
    void command_callback(const std_msgs::msg::String::SharedPtr msg){
        double speed = 0.0f;
        if(msg->data=="forward"){
            speed = 0.2f;
        }
        RCLCPP_INFO(this->get_logger(),"get[%s]指令,发送speed%f",msg->data.c_str(),speed);
    }

};


int main(int argc , char **argv){
    rclcpp::init(argc, argv);
    auto node = std::make_shared<TopicSubscribe01>("topic_subscribe_01");
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0 ;
}
服务通信
1
2
3
4
5
ros2 service list
ros2 service call <service_name> <impl_type> <params>  #调用服务
ros2 service type <service_name>  #查看接口类型
ros2 service find <impl_type>  #通过接口查找服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# serveice_client
#include "rclcpp/logging.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/rclcpp.hpp"
#include <chrono>
#include <example_interfaces/srv/detail/add_two_ints__struct.hpp>
#include <memory>
#include <rclcpp/client.hpp>
#include <rclcpp/utilities.hpp>
#include "example_interfaces/srv/add_two_ints.hpp"

class ServiceClient01: public rclcpp::Node{
public:
    ServiceClient01(std::string name):rclcpp::Node(name){
        RCLCPP_INFO(this->get_logger(),"%s节点已经启动",name.c_str());
        client_ = this->create_client<example_interfaces::srv::AddTwoInts>("add_");
    }
    void send_request(int a,int b){
        RCLCPP_INFO(this->get_logger(),"计算%d+%d",a,b);
        while(!client_->wait_for_service(std::chrono::seconds(1))){
            if(!rclcpp::ok()){
                RCLCPP_ERROR(this->get_logger(),"等待服务的过程被打断");
                return;
            }
            RCLCPP_INFO(this->get_logger(),"等待服务上线中");
        }
        auto request = std::make_shared<example_interfaces::srv::AddTwoInts_Request>();
        request->a = a;
        request->b = b;

        client_->async_send_request(request,std::bind(&ServiceClient01::result_callback_,this,std::placeholders::_1));
    }
    
private:
    rclcpp::Client<example_interfaces::srv::AddTwoInts>:: SharedPtr client_;
    void result_callback_(
        rclcpp::Client<example_interfaces::srv::AddTwoInts> ::SharedFuture result_future
    ){
        auto response = result_future.get();
        RCLCPP_INFO(this->get_logger(),"计算结果: %ld",response->sum);
    }
};

int main(int argc,char **argv){
    rclcpp::init(argc, argv);
    auto node = std::make_shared<ServiceClient01>("Service_client_01");
    node->send_request(5, 6);
    rclcpp::spin(node);
    rclcpp::shutdown();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#service_server
#include "rclcpp/rclcpp.hpp"
#include <example_interfaces/srv/detail/add_two_ints__struct.hpp>
#include <functional>
#include <memory>
#include <rclcpp/context.hpp>
#include <rclcpp/init_options.hpp>
#include <rclcpp/logging.hpp>
#include <rclcpp/node.hpp>
#include <rclcpp/service.hpp>
#include "example_interfaces/srv/add_two_ints.hpp"

class ServiceServer01: public rclcpp::Node{
public:
    ServiceServer01(std::string name):rclcpp::Node(name){
        RCLCPP_INFO(this->get_logger(),"%s节点已经启动",name.c_str());
        add_ints_server_ = 
                this->create_service<example_interfaces::srv::AddTwoInts>("add_", std::bind(&ServiceServer01::handle_add_two_ints,this,std::placeholders::_1,std::placeholders::_2 ));
    }
private:
    rclcpp::Service<example_interfaces::srv::AddTwoInts> :: SharedPtr add_ints_server_;
    void handle_add_two_ints(
        const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request,
         std::shared_ptr<example_interfaces::srv::AddTwoInts::Response> response){
            RCLCPP_INFO(this->get_logger(),"收到a:%ld b: %ld",request->a,request->b);
            response->sum = request->a + request->b;
        }
};
int main(int argc,char **argv){
    rclcpp::init(argc,argv);
    auto node = std::make_shared<ServiceServer01>("service_server_01");
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0 ;
}

接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ros2 interface package sensor_msgs      #查看某一个接口包下所有的接口

msg   #话题接口
srv   #服务接口
action   #动作接口

#接口数据类型

#基础类
bool
byte
char 
float32,float64
int8,uint8
int16,uint16
int32,uint32
int64,uint64
string
#包装类
uint32 id
string image_name
sensor_msgs/Image

底层存在一个转换过程,把上面的接口文件转换为头文件,然后就可以导入了

ros2 pkg create <pkg_name> --build-type ament_cmake --dependencies rosidl_default_generators geometry_msgs

ros2 interface list 
ros2 interface show std_msgs/msg/String


留个坑,FastDDS跳过了
参数控制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#开环控制  与  闭环控制

#参数
bool bool[]
int64 int64[]
float64  float64[]
string  string[]
byte[]

ros2 param list
ros2 param describe <node_name> <param_name>
ros2 param get <node_name> <param_name>
ros2 param set <node_name> <param_name>
ros2 param dump <node_name>
ros2 param dump <node_name> > ./name.yaml
ros2 param load <node_name> > ./name.yaml
ros2 run <package_name> <executable_name> --ros-args --params-file <file_name>

#日志
RCLCPP_DEBUG(this->get_logger(), "我是DEBUG级别的日志,我被打印出来了!");
RCLCPP_INFO(this->get_logger(), "我是INFO级别的日志,我被打印出来了!");
RCLCPP_WARN(this->get_logger(), "我是WARN级别的日志,我被打印出来了!");
RCLCPP_ERROR(this->get_logger(), "我是ERROR级别的日志,我被打印出来了!");
RCLCPP_FATAL(this->get_logger(), "我是FATAL级别的日志,我被打印出来了!");

this->get_logger().set_level(log_level);

Action

Action = 3 Service + 2 Topic

1
2
3
ros2 action list -t
ros2 action info <action_name>
ros2 action send_goal <action_name> <type> <data>  [--feedback]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#rosbag2
ros2 run demo_nodes_cpp talker
rso2 bag record /topic_name
ros2 bag record topic-name1  topic-name2
ros2 bag record -a #记录所有话题
ros2 bag record -o file-name topic-name

ros2 bag info bag-file
ros2 bag play xxx.db3 [-r 10]  [-l] #10倍速  单曲循环
ros2 topic echo /topic_name



#gazebo
gazebo /opt/ros/humble/share/gazebo_plugins/worlds/gazebo_ros_diff_drive_demo.world