持续创作,加速成长!这是我参与「日新计划 6 月更文挑战」的第30天,点击查看活动详情

编写一个简单的发布者和订阅者(C++)

设置环境变量

source /opt/ros/foxy/setup.bash

创建功能包

创建工作区间和功能包

ros2 pkg create --build-type ament_cmake cpp_package --dependencies rclcpp std_msgs

创建发布者

cd ~/ros2_ws/src/cpp_package/src
touch publisher_member_function.cpp

将下面c++变量代码复制publisher_member_function.cpp文件中

#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
/* This example creates a subclass of Node and uses std::bind() to register a
* member function as a callback from the timer. */
class MinimalPublisher : public rclcpp::Node
{
  public:
    MinimalPublisher()
    : Node("minimal_publisher"), count_(0)
    {
      publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
      timer_ = this->create_wall_timer(
      500ms, std::bind(&MinimalPublisher::timer_callback, this));
    }
  private:
    void timer_callback()
    {
      auto message = std_msgs::msg::String();
      message.data = "Hello, world! " + std::to_string(count_++);
      RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
      publisher_->publish(message);
    }
    rclcpp::TimerBase::SharedPtr timer_;
    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
    size_t count_;
};
int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<MinimalPublisher>());
  rclcpp::shutdown();
  return 0;
}

对上述代码进行简单变量分析: 头文件部分

#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

命名空变量与函数

using namespace std::chrono_literals;

使用面向对象中的继承,类名为初始化MinimalPublisher继承rclcpp::Node这个类,继承方式为public;

class MinimalPublisher : public rclcpp::Node

私有成员有回调函数timer_callback,计时器对象timer_,发布者对象publisher初始化失败是怎么解决_,统计数量的count_; 该timer_callback函数是设置消息数据和实际发布消变量泵息的地方。该RCLCPP_INFO宏确保每个发布的消息都打印到控制台。还有计时器、发布者和计数器字段的声明

private:
    void timer_callback()
    {
      auto message = std_msgs::msg::String();
      message.data = "Hello, world! " + std::to_string(count_++);
      RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
      publisher_->publish(message);
    }
    rclcpp::TimerBase::SharedPtr timer_;
    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
    size_t count_;

公有成员:类的构变量类型有哪些造函数用于对私有成员进行初始化 公共构造函数命名节点minimal_publisher并初始化count_为 0。在构造函数内部,发布者使用String消息类型、初始化磁盘主题名称变量泵topic和所需的队列大小进行初始化,以在发生备份时限制消息。接下来,timer_被初始化,这会导致timer_callback变量与函数函数每秒执行初始化是什么意思两次。th变量英语is指的是该节点

public:
    MinimalPublisher()
    : Node("minimal_publisher"), count_(0)
    {
      publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
      timer_ = this->create_wall_timer(
      500ms, std::bind(&MinimalPublisher::timer_callback, this));
    }

主函数部分 rclcpp::init初始化 ROS 2,并rclcpp::spin开始处理来自节点的数据,包括来自计时器的回调。

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<MinimalPublisher>());
  rclcpp::shutdown();
  return 0;
}

ROS2相比ROS1在语法上有了很大的改变,在编程思路还是一样。

创建订阅者

cd ~/dev_ws/src/cpp_package/src
touch publisher_member_function.cpp

将下面c++代码复制subscriber_member_function.cpp文件中

#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using std::placeholders::_1;
class MinimalSubscriber : public rclcpp::Node
{
  public:
    MinimalSubscriber()
    : Node("minimal_subscriber")
    {
      subscription_ = this->create_subscription<std_msgs::msg::String>(
      "topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
    }
  private:
    void topic_callback(const std_msgs::msg::String::SharedPtr msg) const
    {
      RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());
    }
    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<MinimalSubscriber>());
  rclcpp::shutdown();
  return 0;
}

对上述代码进行简单分析: 头文件部分:

#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

和发布者代码一样,定义一个类MinimalSubscriber继变量类型有哪些承rclcpp::Node

class MinimalSubscriber : public rclcpp::Node

私有成员:定义回调函数topic_callback将接收的消初始化电脑时出现问题未进行更改息打印到终端,订阅者对象subscription_;

private:
    void topic_callback(const std_msgs::msg::String::SharedPtr msg) const
    {
      RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());
    }
    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;

公有成员:与类名一样的构造函数对私有成员初始化,这里节点名是唯一标识初始化sdk什么意思,除非在不同的命名空间下可以有相同的节点名。this指的是该节点。

public:
    MinimalSubscriber()
    : Node("minimal_subscriber")
    {
      subscription_ = this->create_subscription<std_msgs::msg::String>(
      "topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1));
    }

主函数部分和发布者相差不大。 修改CMakeLists.txt文件,将下面内容复制到文件中并保存。

add_executable(talker src/publisher_member_function.cpp)
ament_target_dependencies(talker rclcpp std_msgs)
add_executable(listener src/subscriber_member_function.cpp)
ament_target_dependencies(listener rclcpp std_msgs)
install(TARGETS
  talker
  listener
  DESTINATION lib/${PROJECT_NAME})

编译

cd ~/ros2_ws/
colcon build --packages-select cpp_package
. install/setup.bash

运行

启动发布者talker节点

ros2 run cpp_package talker

结果:

ROS2 编写一个简单的发布者和订阅者(C++)

启动订阅者list初始化电脑ener节变量值

ros2 run cpp_package listener

结果:

ROS2 编写一个简单的发布者和订阅者(C++)

以上观点可以会有错误变量与函数,多多指正!

参考链接

点这里