【ROS2】【分步讲解】节点的使用以及引入消息接口的方法

写在前面

主要参考了小鱼的ROS2教程,其他教程在分部拆解上有些模棱两可
不算完全原创,只能说是个人再解释,个人笔记

建立完整功能节点的步骤概述

  1. 创建节点
  2. 定义该节点的身份
  3. 为节点分配具体任务
  4. ros2 run

打个比方,今天要完成送快递的任务,将任务拆解后可分为:

  1. 招人
  2. 让这个人变成快递员
  3. 给TA分配具体任务(把城北的快递派送完)
  4. 让TA干活

完整程序展示(以publisher为例)

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:
    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_;
    // 声明节点
    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr command_publisher_;
};

分部拆解

  • 创建节点
    • 创建节点发生在auto node = std::make_shared(“topic_publisher_01”);
      当构造函数TopicPublisher01被调用,节点名称参数写入Node(name)时,节点就被创建完成了
      相当于在没有人的情况下,招了个人进来,但是TA现在还不知道自己是来干嘛的,只知道自己是人,是一个劳动力
    • 仅仅被创建的节点本身不具有任何功能,具体功能是加在上面的程序基础上的
    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;
    }
    
  • 节点功能定义
    • 相比上面的程序两行代码,将该节点定义成publisher,作为消息的发布者
    • 相当于从无业游民变成了快递员
      public:
          command_publisher_ = this->create_publisher<std_msgs::msg::String>("command", 10);
      private:
          rclcpp::Publisher<std_msgs::msg::String>::SharedPtr command_publisher_;
      
      具体解释:创建一个发布者,向名为 “command” 的话题发布 std_msgs::msg::String 类型的消息,并设置消息队列长度为 10(即最大消息缓存数量)
  • 分配具体任务
    • 为发布者节点增加定时发送的功能,主要增加了下面的代码
      相当于为快递员分配的具体的工作任务,招人了总是要用起来的
      timer_ = this->create_wall_timer(std::chrono::milliseconds(500), std::bind(&TopicPublisher01::timer_callback, this));
      
      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_;
      // 声明节点
      rclcpp::Publisher<std_msgs::msg::String>::SharedPtr command_publisher_;
      
  • 运行程序
    • 使用下面的指令运行对应节点即可
      cd xxx/工作空间_ws/
      colcon build --packages-select 功能包名称			# 编译功能包
      source install/setup.bash						# 安装编译后的结果,防止运行时找不到相关依赖
      ros2 run 功能包名称 功能包中的节点名称				# 运行节点
      

完整程序参考最上面的完整程序展示,下面的分部拆解并不是正确的语法

订阅者节点代码展示

实现过程和发布者完全相同

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"


class TopicSubscriber : public rclcpp::Node
{
public:
    TopicSubscriber(std::string name) : Node(name)
    {
        RCLCPP_INFO(this->get_logger(), "this is %s", name.c_str());
        command_subscriber = this->create_subscription<std_msgs::msg::String>("command", 10, std::bind(&TopicSubscriber::command_callback, this, std::placeholders::_1));
    }
private:
    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr command_subscriber;
    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(), "receive command [%s], the speed is %f", msg->data.c_str(), speed);
    }
};


int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    /*创建对应节点的共享指针对象*/
    auto node = std::make_shared<TopicSubscriber>("topic_subscriber_0");
    /* 运行节点,并检测退出信号*/
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

服务通信同理

也就是创建、赋予职能、安排具体任务这三部分,无非比话题通信多一个回调函数
代码上确实相对复杂不少,但是多数都是用于回调处理的
具体程序参考:小鱼的ROS2教程


最后补充一下引入消息接口的方法 (以std_msgs为例)

  1. 在CMakeLists.txt中,增加

    find_package(std_msgs REQUIRED)
    ament_target_dependencies(topic_publisher_01 rclcpp std_msgs)
    

    第一句找到需要的接口库,第二句将找到的接口库和当前构建的目标节点关联起来

  2. 在packages.xml中增加下面的代码,和其他的depend放在一起即可

     <depend>std_msgs</depend>
    
  3. 在cpp程序中,使用#include “std_msgs/msg/string.hpp”,调用这些接口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值