ROS2- 构建-topic发布者和订阅者-08

RCLCPP实现topic操作

RCLCPP为Node类提供了丰富的API接口,其中就包括创建话题发布者和创建话题订阅者。

控制节点+被控节点

控制节点创建一个话题发布者,发布控制命令(command)话题,接口类型为字符串(string),控制接点通过发布者发布控制命令(前进、后退、左转、右转、停止)
被控节点创建一个订阅者,订阅控制命令,收到控制命令后根据命令内容打印对应速度出来。

创建chapt3_ws工作空间、example_topic_rclcpp功能包和topic_publisher_01.cpp
mkdir -p chapt3/chapt3_ws/src
cd chapt3/chapt3_ws/src
ros2 pkg create example_topic_rclcpp --build-type ament_cmake --dependencies rclcpp
touch example_topic_rclcpp/src/topic_publisher_01.cpp

└── src
└── example_topic_rclcpp
├── CMakeLists.txt
├── include
│ └── example_topic_rclcpp
├── package.xml
└── src
└── topic_publisher_01.cpp

#include "rclcpp/rclcpp.hpp"

class TopicPublisher01 : public rclcpp::Node
{
public:
    // 构造函数,有一个参数为节点名称
    TopicPublisher01(std::string name) : Node(name)
    {
        RCLCPP_INFO(this->get_logger(), "%s节点已经启动.", name.c_str());
    }

private:
    // 声明节点
};

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;
}

修改CMakeLists.txt

add_executable(topic_publisher_01 src/topic_publisher_01.cpp)
ament_target_dependencies(topic_publisher_01 rclcpp)

install(TARGETS
  topic_publisher_01
  DESTINATION lib/${PROJECT_NAME}
)

cd chapt3/chapt3_ws/
colcon build --packages-select example_topic_rclcpp
source install/setup.bash
ros2 run example_topic_rclcpp topic_publisher_01

发布者的创建

参考官网:https://docs.ros2.org/latest/api/rclcpp/
create_publisher 需要传入消息类型(msgT)、话题名称(topic_name)和 服务指令(qos)

消息的interface

消息接口是ROS2通信时必须的一部分,通过消息接口ROS2才能完成消息的序列化和反序列化。
ROS2定义好了常用的消息接口,并生成了C++和Python的依赖文件,可以直接在程序中进行导入。

ament_cmake 类型功能包导入消息接口分为三步

在CMakeLists.txt中导入,具体是先find_packages再ament_target_dependencies。

find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(topic_publisher_01 src/topic_publisher_01.cpp)
ament_target_dependencies(topic_publisher_01 rclcpp std_msgs)

在./src/example_topic_rclcpp/package.xml中导入,具体是添加depend标签并将消息接口写入。
<buildtool_depend>ament_cmake</buildtool_depend>

rclcpp
std_msgs

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
在代码中导入,C++中是#include"消息功能包/xxx/xxx.hpp"。

整体代码如下:

#include "rclcpp/rclcpp.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);
        // 创建定时器,500ms为周期,定时发布
        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_;

    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);
    }
    // 声名定时器指针
    rclcpp::TimerBase::SharedPtr timer_;

};

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;
}

ros2 interface show std_msgs/msg/String
看到其内部包含了一个string data,ROS2会将消息文件转换成一个类,并把其中的定义转换成类的成员函数。

cd chapt3/chapt3_ws/
colcon build --packages-select example_topic_rclcpp # colcon这个命令一定要注意运行的路径是在workspace路径下
source install/setup.bash
ros2 run example_topic_rclcpp topic_publisher_01

另一个窗口:
查看列表
ros2 topic list
输出内容
ros2 topic echo /command

编写订阅者

cd chapt3_ws/src/example_topic_rclcpp
touch src/topic_subscribe_01.cpp

#include "rclcpp/rclcpp.hpp"

class TopicSubscribe01 : public rclcpp::Node
{
public:
    // 构造函数,有一个参数为节点名称
    TopicSubscribe01(std::string name) : Node(name)
    {
        RCLCPP_INFO(this->get_logger(), "大家好,我是%s.", name.c_str());
    }

private:
    // 声明节点
};

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;
}

CMakeLists.txt

add_executable(topic_subscribe_01 src/topic_subscribe_01.cpp)
ament_target_dependencies(topic_subscribe_01 rclcpp)

install(TARGETS
topic_subscribe_01
  DESTINATION lib/${PROJECT_NAME}
)

cd chapt3/chapt3_ws/
colcon build --packages-select example_topic_rclcpp
source install/setup.bash
ros2 run example_topic_rclcpp topic_subscribe_01


root@ubuntu-16:~/stephen/chapt3/chapt3_ws# colcon build --packages-select example_topic_rclcpp
source install/setup.bash
ros2 run example_topic_rclcpp topic_subscribe_01
Starting >>> example_topic_rclcpp
Finished <<< example_topic_rclcpp [4.44s]

Summary: 1 package finished [4.73s]
[INFO] [1749469572.895619578] [topic_subscribe_01]: 大家好,我是topic_subscribe_01.

上面只有订阅者节点 并无功能
create_subscription函数需要实现
编写代码


#include "rclcpp/rclcpp.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(), "收到[%s]指令,发送速度 %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;
}

CMakeLists.txt添加下std_msgs依赖

ament_target_dependencies(topic_subscribe_01 rclcpp std_msgs) # 知识修改这一行 末尾增加std_msgs (参考topic_publisher_01)

packages.xml就不需要了,同一个功能包,已经添加了

colcon build --packages-select example_topic_rclcpp
source install/setup.bash
ros2 run example_topic_rclcpp topic_subscribe_01

另一窗口启动发布者
cd chapt3/chapt3_ws/
source install/setup.bash
ros2 run example_topic_rclcpp topic_publisher_01

效果

sub:


root@ubuntu-16:~/stephen/chapt3/chapt3_ws# colcon build --packages-select example_topic_rclcpp
source install/setup.bash
ros2 run example_topic_rclcpp topic_subscribe_01
Starting >>> example_topic_rclcpp
Finished <<< example_topic_rclcpp [9.52s]

Summary: 1 package finished [9.81s]
[INFO] [1749471011.393608017] [topic_subscribe_01]: 大家好,我是topic_subscribe_01.
[INFO] [1749471022.586113314] [topic_subscribe_01]: 收到[forward]指令,发送速度 0.200000
[INFO] [1749471023.586640002] [topic_subscribe_01]: 收到[forward]指令,发送速度 0.200000
[INFO] [1749471024.586656471] [topic_subscribe_01]: 收到[forward]指令,发送速度 0.200000
[INFO] [1749471025.586613935] [topic_subscribe_01]: 收到[forward]指令,发送速度 0.200000
[INFO] [1749471026.586633255] [topic_subscribe_01]: 收到[forward]指令,发送速度 0.200000
[INFO] [1749471027.586673598] [topic_subscribe_01]: 收到[forward]指令,发送速度 0.200000
[INFO] [1749471028.586600778] [topic_subscribe_01]: 收到[forward]指令,发送速度 0.200000
[INFO] [1749471029.586575787] [topic_subscribe_01]: 收到[forward]指令,发送速度 0.200000
[INFO] [1749471030.586675936] [topic_subscribe_01]: 收到[forward]指令,发送速度 0.200000
[INFO] [1749471031.586729370] [topic_subscribe_01]: 收到[forward]指令,发送速度 0.200000

pub:


root@ubuntu-16:~/stephen/chapt3/chapt3_ws# ros2 run example_topic_rclcpp topic_publisher_01
[INFO] [1749471093.112536733] [topic_publisher_01]: topic_publisher_01节点已经启动.
[INFO] [1749471093.614092743] [topic_publisher_01]: Publishing: 'forward'
[INFO] [1749471094.114084285] [topic_publisher_01]: Publishing: 'forward'
[INFO] [1749471094.614078421] [topic_publisher_01]: Publishing: 'forward'
[INFO] [1749471095.114072903] [topic_publisher_01]: Publishing: 'forward'
[INFO] [1749471095.614074947] [topic_publisher_01]: Publishing: 'forward'
[INFO] [1749471096.114058372] [topic_publisher_01]: Publishing: 'forward'
[INFO] [1749471096.614043448] [topic_publisher_01]: Publishing: 'forward'
[INFO] [1749471097.114018324] [topic_publisher_01]: Publishing: 'forward'
[INFO] [1749471097.614060707] [topic_publisher_01]: Publishing: 'forward'
[INFO] [1749471098.114006809] [topic_publisher_01]: Publishing: 'forward'
[INFO] [1749471098.614025468] [topic_publisher_01]: Publishing: 'forward'

4.python版

cd chapt3/chapt3_ws/src/
ros2 pkg create example_topic_rclpy --build-type ament_python --dependencies rclpy

cd example_topic_rclpy/example_topic_rclpy
touch topic_subscribe_02.py


import rclpy
from rclpy.node import Node
from std_msgs.msg import String


class NodeSubscribe02(Node):
    def __init__(self,name):
        super().__init__(name)
        self.get_logger().info("大家好,我是%s!" % name)
        # 创建订阅者
        self.command_subscribe_ = self.create_subscription(String,"command",self.command_callback,10)

    def command_callback(self,msg):
        speed = 0.0
        if msg.data=="backup":
            speed = -0.2
        self.get_logger().info(f'收到[{msg.data}]命令,发送速度{speed}')


def main(args=None):
    rclpy.init(args=args) # 初始化rclpy
    node = NodeSubscribe02("topic_subscribe_02")  # 新建一个节点
    rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)
    rclpy.shutdown() # 关闭rclpy

touch topic_publisher_02.py

import rclpy
from std_msgs.msg import String
from rclpy.node import Node


class NodePublisher02(Node):
    def __init__(self,name):
        super().__init__(name)
        self.get_logger().info("大家好,我是%s!" % name)
        self.command_publisher_ = self.create_publisher(String,"command", 10)
        self.timer = self.create_timer(0.5, self.timer_callback)

    def timer_callback(self):
        """
        定时器回调函数
        """
        msg = String()
        msg.data = 'backup'
        self.command_publisher_.publish(msg)
        self.get_logger().info(f'发布了指令:{msg.data}')    #打印一下发布的数据

def main(args=None):
    rclpy.init(args=args) # 初始化rclpy
    node = NodePublisher02("topic_publisher_02")  # 新建一个节点
    rclpy.spin(node) # 保持节点运行,检测是否收到退出指令(Ctrl+C)
    rclpy.shutdown() # 关闭rclpy

setup.py
修改 注意末尾的,
entry_points={
'console_scripts': [
"topic_publisher_02 = example_topic_rclpy.topic_publisher_02:main",
"topic_subscribe_02 = example_topic_rclpy.topic_subscribe_02:main"
],
},

编译
cd chapt3/chapt3_ws/
colcon build

测试
cd chapt3/chapt3_ws/
source install/setup.bash
ros2 run example_topic_rclpy topic_publisher_02

cd chapt3/chapt3_ws/
source install/setup.bash
ros2 run example_topic_rclpy topic_subscribe_02

效果


root@ubuntu-16:~/stephen/chapt3/chapt3_ws# source install/setup.bash
ros2 run example_topic_rclpy topic_publisher_02
[INFO] [1749471991.589694468] [topic_publisher_02]: 大家好,我是topic_publisher_02!
[INFO] [1749471992.092904438] [topic_publisher_02]: 发布了指令:backup
[INFO] [1749471992.592818231] [topic_publisher_02]: 发布了指令:backup
[INFO] [1749471993.092611300] [topic_publisher_02]: 发布了指令:backup
[INFO] [1749471993.592778126] [topic_publisher_02]: 发布了指令:backup
[INFO] [1749471994.092757608] [topic_publisher_02]: 发布了指令:backup
[INFO] [1749471994.592724685] [topic_publisher_02]: 发布了指令:backup
[INFO] [1749471995.092957723] [topic_publisher_02]: 发布了指令:backup


source install/setup.bash
ros2 run example_topic_rclpy topic_subscribe_02
[INFO] [1749472015.876325291] [topic_subscribe_02]: 大家好,我是topic_subscribe_02!
[INFO] [1749472016.093318771] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2
[INFO] [1749472016.593235108] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2
[INFO] [1749472017.093261376] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2
[INFO] [1749472017.593319627] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2
[INFO] [1749472018.093335419] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2
[INFO] [1749472018.593305671] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2
[INFO] [1749472019.093244578] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2
[INFO] [1749472019.593174787] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2
[INFO] [1749472020.093265443] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2
[INFO] [1749472020.593029732] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2
[INFO] [1749472021.093340110] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2
[INFO] [1749472021.593298624] [topic_subscribe_02]: 收到[backup]命令,发送速度-0.2

posted @ 2025-06-09 20:35  jack-chen666  阅读(108)  评论(0)    收藏  举报