【ROS2开发】BOOST-C++实现topic通信

news2024/11/16 6:50:20

 一、说明

        不知是何原因,ROS2居然没有集成开发环境,因此工程管理、编译等是全手工活。本文将详细讲述工程构建、编译、topic节点具体内容。让初学者直接进入战场环境。结合图文,尽量看清开发过程。

二、目标实现

        我们这里就是要手工构建一个Publisher和一个Subscriber让它们实现简单通信。

三、开发过程

3.1 新建一个工作空间

        新建工作空间,叫mytry_ws:

mkdir -p mytry_ws/src
cd  mytry_ws/src

mkdir -p: 递归创建目录,即使上级目录不存在,会按目录层级自动创建目录

        注意:这里的src不是源代码所在地,而是包所在地。

3.2 创建工作包

        1)进入包的目录中:  

    cd  mytry_ws/src

         2)创建名称为mytopic的包

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

        3)语法解释

        ros2 pkg

          create mytopic   \                           #  建立一个包,名称 mytopic

          --build-type ament_cmake \           # 构建工具是 ament_cmake,这类似于cmake

          --dependencies  rclcpp std_msgs  # 依赖的基类,rclcpp是c++基础类,std_msgs是消息类

        以上实质性参数有三个:

  •         mytopic:        包名称
    • --build-type ament_cmake:     编译器是ament_cmake
    • --dependencies  rclcpp std_msgs:        依赖包指定为rclcpp、std_msgs;

        4)执行结果 

  •  创建固定工程路径,以下图所示,基本上是固定的框架。
  • CMakeLists。txt是编译用文件
  • package.xml是包的说明文件
  • include下的mytopic包名,是在编译的时候与其它包的include区别。
  • mytopic/src目录下,是真正的节点源文件。
  • 一个工程可以多个包
  • 一个包内可以多个节点

结果图如下,(注意这里用链表表示目录层次关系)

3.3  publisher节点编写

       在包内建立节点程序,mytry_ws/src/mytopic/src下创建lambda.cpp和sublambda.cpp俩个节点源代码。

3.3.1 定义一个发布方节点,源代码lambda.cpp

#include <chrono>
#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 a fancy C++11 lambda
 * function to shorten the callback syntax, at the expense of making the
 * code somewhat more difficult to understand at first glance. */

class MinimalPublisher : public rclcpp::Node
{
public:
  MinimalPublisher()
  : Node("minimal_publisher"), count_(0)
  {
    publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
    auto timer_callback =
      [this]() -> void {
        auto message = std_msgs::msg::String();
        message.data = "Hello, world! " + std::to_string(this->count_++);
        RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
        this->publisher_->publish(message);
      };
    timer_ = this->create_wall_timer(500ms, timer_callback);
  }

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

3.3.2 程序解释 

  • 1) 时间类

        #include <chrono>此处为调用时间类变量做准备。时间类变量这里举个例子:        

  •  2)你的节点类 MinimalPublisher继承了基类rclcpp::Node方可成为正式节点
    class MinimalPublisher : public rclcpp::Node
  •  3) MinimalPublisher 的构造函数中,初始化两个变量

     MinimalPublisher(): Node("minimal_publisher"), count_(0)
  •                 Node::name = "minimal_publisher" , 直接用父类定义节点名称;
  •                 和计数器属性,这里计数器 count_(n)是发送缓存长度

  • 4)定义一个发布者

             先定义了一个string类型的发布者,然后初始化:初始内容为“topic”,历史数据深度为10

     publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);

     private:
         rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
  • 5) 关于auto的用法

                auto  xxx = [  function ];

        此处的auto是自动变量,意思是说,xxx和=后面的函数返回变量一致。(这里避免写具体的类型,让编译器自己看着处理)

  • 6)关于函数指针
    auto timer_callback =
          [this]() -> void {}

        此处 timer_callback是个函数指针,指向  [this]() -> void {},这相当于定义:

    void  MinimalPublisher::timer_callback() { }

         7)定义字符串对象

 auto message = std_msgs::msg::String();

        这里定义一个字符串调用了函数值得吗,值得:1)可以用auto指针,2)确保了变量初始化。

         8) 把信息打印到屏幕

    RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());

         9)发布信息        

    this->publisher_->publish(message);

        10)定时器间歇性调用        

    timer_ = this->create_wall_timer(500ms, timer_callback);

        11)主函数入口 

         注意,这里构造函数就按以前的一般函数用了,在循环中重复调用。

3.4 Subscriber节点创建

3.4.1 消息订阅方代码

  节点程序名称:sublambda.cpp,位置mytry_ws/src/mytopic/src


#include <memory>

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

class MinimalSubscriber : public rclcpp::Node
{
public:
  MinimalSubscriber()
  : Node("minimal_subscriber")
  {
    subscription_ = this->create_subscription<std_msgs::msg::String>(
      "topic",
      10,
      [this](std_msgs::msg::String::UniquePtr msg) {
        RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());
      });
  }

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

3.4.2 代码解释

 subscription_ = this->create_subscription<std_msgs::msg::String>(
      "topic",
      10,
      [this](std_msgs::msg::String::UniquePtr msg) { ... } );

        此处回调函数获得数据指针,如获取数值,可以:

MsgT::SharedPtr my_msg;

auto sub = node->create_subscription<MsgT>(topic, 
[&](const MsgT::SharedPtr msg){my_msg = msg;}, 
QoS, 
callback_group);

四、编译前准备

4.1 修改Cmakelist.txt

1)依赖项追加

        如果新建功能包的时候没有加--dependencies rclcpp std_msgs等功能包, 则需要手动添加: (任意位置均可)

  • find_package(rclcpp REQUIRED)
  • find_package(std_msgs REQUIRED)


2)可执行节点定义

  •         add_executable()

            让编译器编译Customer.cpp和KFC.cpp这两个文件. 并生成可执行文件Customer_node和KFC_node

  •         ament_target_dependencies

             添加编译的依赖

add_executable(publisher_lambda lambda.cpp)
ament_target_dependencies(publisher_lambda rclcpp std_msgs)
add_executable(subscriber_lambda sublambda.cpp)
ament_target_dependencies(subscriber_lambda rclcpp std_msgs)

3)将编译好的文件安装到正确路径

install(TARGETS
  publisher_lambda
  subscriber_lambda
  DESTINATION lib/${PROJECT_NAME}
)

4.2 修改package.xml

        同样地, 新建功能包的时候没有加--dependencies rclcpp std_msgs等功能包, 则需要手动添加, 放置于<package>标签下

<depend>rclcpp</depend>
<depend>std_msgs</depend>
也可自行修改下面这些声明, 与实现功能无关, 但是最好写全

<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="fanziqi@fanziqi.site">fanziqi</maintainer>
<license>TODO: License declaration</license>
 

五、 编译

5.1 编译指定包名称

  • 注意:编译的时候以包为单位,指定哪个包,就编译哪个。

--packages-select指定编译customer_and_kfc功能包

    colcon build --packages-select mytopic 

5.2 刷新环境

  • 在ubuntu下:
echo "source /mytry_ws/install/setup.zsh" >> ~/.bashrc
source ~/.bashrc

六、 运行


        新建一个终端窗口, 运行发布节点

    ros2  run mytopic  publisher_lambda

        再另新建一个终端, 运行收听节点

    ros2 run mytopic subscriber_lambda  

        此时应该可以看见:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/366833.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

根据数据规模猜解法

文章目录0、结论1、题目1.1 题目描述1.2 思路分析1.2.1 暴力递归解法11.2.2 解法1修改成动态规划1.2.3 暴力递归解法21.2.4 解法2修改成动态规划1.2.5 对数器1.3 小结2、总结0、结论 1&#xff09;C/C&#xff0c;1秒处理的指令条数为 10810^8108 2&#xff09;Java等语言&am…

大数据核心技术是什么

大数据的核心层&#xff1a;数据采集层、数据存储与分析层、数据共享层、数据应用层&#xff0c;可能叫法有所不同本质上的角色都大同小异。 大数据的核心技术都包括什么&#xff1f; 1、数据采集 数据采集的任务就是把数据从各种数据源中采集和存储到数据存储上&#xff0c…

多种方法进行去基线处理

目录detrend函数去除基线多项式拟合原函数BEADS 基线处理小波算法经验模态分解&#xff08;EMD&#xff09;参考detrend函数去除基线 detrend函数只能用于去除线性趋势&#xff0c;对于非线性的无能为力。 函数表达式&#xff1a;y scipy.signal.detrend(x): 从信号中删除线…

3.【Linux】安装 elasticsearch-7.10.0 单机版

1.下载 版本 JDK 11ES elasticsearch-7.10.0 jdk安装 下载&#xff1a; wget https://download.java.net/openjdk/jdk11/ri/openjdk-1128_linux-x64_bin.tar.gz配置环境变量&#xff1a;# 编辑配置文件 vim /etc/profile# Java11环境变量配置 export JAVA_HOME/devtools/ja…

【编程语言】AWK 极简教程

1 概述 AWK 是一种解释执行的编程语言。它非常的强大,被设计用来专门处理文本数据。AWK 的名称是由它们设计者的名字缩写而来 —— Afred Aho, Peter Weinberger 与 Brian Kernighan。 由 GNU/Linux 发布的 AWK 版本通常被称之为 GNU AWK,由自由软件基金( Free Software Fou…

《爆肝整理》保姆级系列教程python接口自动化(二十二)--unittest执行顺序隐藏的坑(详解)

简介 大多数的初学者在使用 unittest 框架时候&#xff0c;不清楚用例的执行顺序到底是怎样的。对测试类里面的类和方法分不清楚&#xff0c;不知道什么时候执行&#xff0c;什么时候不执行。虽然或许通过代码实现了&#xff0c;也是稀里糊涂的一知半解&#xff0c;这样还好&am…

2023前端二面手写面试题总结

创建10个标签&#xff0c;点击的时候弹出来对应的序号 var a for(let i0;i<10;i){adocument.createElement(a)a.innerHTMLi<br>a.addEventListener(click,function(e){console.log(this) //this为当前点击的<a>e.preventDefault() //如果调用这个方法&#x…

Nordic nRF芯片FDS模块学习

FDS系统学习 文章目录FDS系统学习一、ROM&#xff0c;RAM&#xff0c;FLASH作用二、ROM,RAM和FLASH在单片中的运作原理三、Flash访问模块FDS用法1. FDS在sdk_config.h中的配置2. fds_register()注册3. fds_record_write()写记录4. fds_record_find()查找5. fds_record_open()读…

PWM实验

目录 一、pwm与RGB LCD 二、硬件原理 1、I.MX6U PWM 频率和占空比 2、原理图与数据手册 3、寄存器 PWM1_PWMCR PWM1_PWMIR​编辑 PWM1_PWMSR​编辑 PWM1_PWMPR​编辑 PWM1_PWMSAR​编辑 三、代码编写 1、编写bsp_backlight.h 2、编写bsp_backlight.c 一、pwm与RGB …

物联网平台源码 物联网源码 springmvc+Mysql+Html

IOT智慧物联网大数据平台源码 物联网平台是一套存在于云端的的软件&#xff0c;提供了一种支持将物联网系统中的设备层、网络层和应用层组织在一起的方案模板&#xff0c;物联网平台现已成为物联网生态系统中最重要的组成部分。 一般来讲&#xff0c;完整的物联网平台主要由以…

Linux C/C++或者嵌入式开发到底有没有35岁危机?

一个读者问了一个问题&#xff1a; 我现在25岁&#xff0c;双非一本本科。在深圳上班&#xff0c;做嵌入式开发&#xff0c;打算走Linux C/C开发&#xff0c;工资目前一般。读了前辈写的很多博客之后&#xff0c;觉得很棒。我现在有一些疑问。 1.最近互联网裁员很厉害嘛&#x…

【selenium自动化测试】如何定位页面元素,及对页面元素的操作方法

selenium元素定位 ​selenium定位元素的方式有8种。 fild_element(by,value)&#xff1a;by表示使用的定位方式&#xff0c;定位方式可以参见By类。value表示值&#xff0c;例如&#xff1a;根据id定位 By.ID&#xff0c;valueid属性的值。该方法返回元素对象&#xff0c;返…

【Linux学习笔记】3.Linux 忘记密码解决方法及远程登录

前言 本章介绍Linux的忘记密码解决方法及远程登录。 Linux 忘记密码解决方法 很多朋友经常会忘记Linux系统的root密码&#xff0c;linux系统忘记root密码的情况该怎么办呢&#xff1f;重新安装系统吗&#xff1f;当然不用&#xff01;进入单用户模式更改一下root密码即可。 …

【Leetcode 剑指Offer】第 4 天 查找算法(简单)

查找剑指 Offer 03. 数组中重复的数字剑指 Offer 53 - I. 在排序数组中查找数字 I二分法题目链接剑指 Offer 03. 数组中重复的数字 题&#xff1a;在一个长度为 n 的数组 nums 里的所有数字都在 0&#xff5e;n-1 的范围内。数组中某些数字是重复的&#xff0c;但不知道有几个数…

一个列表引发的思考(简单版)

最近老板让我按照设计图写一个页面&#xff0c;不嫌丢人的说这是我第一次写页面&#xff0c;哈哈哈。 然后设计图里有一个这样的需求&#xff0c;感觉挺有意思的。 为什么感觉有意思呢&#xff0c;因为这个列表它前面是图片&#xff0c;然后单行和双行的不一样。&#xff08;请…

电子技术——稳定性问题

电子技术——稳定性问题 本节我们讨论稳定性问题。 反馈放大器的传递函数 在考虑频率响应的情况下&#xff0c;开环增益 AAA 通常是关于复频率 sss 的函数 。那么 A(s)A(s)A(s) 就称为 开环传递函数 。同时&#xff0c; β\betaβ 也可能是一个关于复频率 sss 的函数。我们称…

Element表单嵌套树形表格的校验问题

如图&#xff0c;第一次遇到属性表格的校验问题 曾经写过单纯的表格校验是这样的 <el-form ref"forms" :model"forms"><el-table ref"multipleTable" :data"forms.tableData" tooltip-effect"dark" border style&…

关于iframe一些通讯的记录(可适用工作流审批)

一.知识点(1).我们可以通过postMessage(发送方)和onmessage(接收方)这两个HTML5的方法, 来解决跨页面通信问题&#xff0c;或者通过iframe嵌套的不同页面之间的通信a.父页面代码如下<div v-if"src" class"iframe"><iframeref"iframe"id…

SpringBoot集成Redis实现分布式会话

在单体应用的时代&#xff0c;Session 会话直接保存在服务器中&#xff0c;实现非常简单&#xff0c;但是随着微服务的流行&#xff0c;现代应用架构基本都是分布式架构&#xff0c;请求随机的分配到后端的多个应用中&#xff0c;此时session就需要共享&#xff0c;而存储在red…

【运动控制】CNC三轴小线段路径规划

CNC三轴小线段路径规划 文章目录CNC三轴小线段路径规划一、项目说明二、具体实现1、速度规划2、小线段插补3、运动学逆解刀轴插补点4、差分处理得到实际的速度和加速度5、加速度滑动平均6、实现的效果如图所示三、Reference写在前面&#xff0c;本文是作为一个练手小项目的总结…