ROS(话题通信)发布订阅通信机制

一、ROS基本数据类型的发布和订阅

​ ros中的std_msgs包含了许多基本的数据类型,基本数据类型的发布订阅通过std_msgs中的数据类型实现(后续会有自定义数据类型)。

​ std_msgs中包含的数据类型,可以通过在终端中键入“rosmsg list ”查看,下面给出std_msgs包含的一些基本的数据类型:

std_msgs/Bool
std_msgs/Byte
std_msgs/ByteMultiArray
std_msgs/Char
std_msgs/ColorRGBA
std_msgs/Duration
std_msgs/Empty
std_msgs/Float32
std_msgs/Float32MultiArray
std_msgs/Float64
std_msgs/Float64MultiArray
std_msgs/Header
std_msgs/Int16
std_msgs/Int16MultiArray
std_msgs/Int32
std_msgs/Int32MultiArray
std_msgs/Int64
std_msgs/Int64MultiArray
std_msgs/Int8
std_msgs/Int8MultiArray
std_msgs/MultiArrayDimension
std_msgs/MultiArrayLayout
std_msgs/String
std_msgs/Time
std_msgs/UInt16
std_msgs/UInt16MultiArray
std_msgs/UInt32
std_msgs/UInt32MultiArray
std_msgs/UInt64
std_msgs/UInt64MultiArray
std_msgs/UInt8
std_msgs/UInt8MultiArray

1、ROS字符串数据类型的发布和订阅

1.1 发布方实现

#include "ros/ros.h"
#include "std_msgs/String.h"

int main(int argc, char *argv[])
{
    //乱码问题的解决
    setlocale(LC_ALL,"");
    //初始化ROS节点
    ros::init(argc,argv,"pubNode");
    //句柄
    ros::NodeHandle nh;
    //发布对象的创建
    ros::Publisher pub;
    pub = nh.advertise<std_msgs::String>("string",100);
    //发布频率的设置
    ros::Rate rate(1); //一秒一次

    //创建待发布消息对象
    std_msgs::String pubString;
    std::string str1 = "第";
    std::string str2 = "次发送!";

    int8_t number = 1;

    while(ros::ok())
    {
        //组织消息
        std::stringstream ss;
        ss<< str1 << std::to_string(number) <<str2;
        pubString.data = ss.str();
        //发布
        pub.publish(pubString);
        rate.sleep();
        number++;
    }
    return 0;
}

1.2 订阅方实现

#include "ros/ros.h"
#include "std_msgs/String.h"

void doMsg(const std_msgs::String::ConstPtr& msg)
{
    ROS_INFO("订阅到的消息为:%s",msg->data.c_str());
}

int main(int argc, char *argv[])
{
    //乱码问题的解决
    setlocale(LC_ALL,"");
    //初始化ROS节点
    ros::init(argc,argv,"subNode");
    //句柄
    ros::NodeHandle nh;
    //发布对象的创建
    ros::Subscriber sub;
    sub = nh.subscribe<std_msgs::String>("string",100,doMsg);
    //回旋函数
    ros::spin();
    return 0;
}

1.3 launch文件

<launch>
    <node pkg="string_pub_sub" type="demo_pub" name="pub" output="screen"/>
    <node pkg="string_pub_sub" type="demo_sub" name="sub" output="screen"/>
</launch>

2、ROS整形数据类型的发布和订阅

整形数据分int8、uint8、int16、uint16等多种,不同的长度在实现发布订阅时只是使用std_msgs中的数据类型不同,在此以int8为例

2.1 发布方实现

#include "ros/ros.h"
#include "std_msgs/Int8.h"

int main(int argc, char  *argv[])
{
    /* code */
    //解决乱码
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc, argv, "pub");
    //句柄
    ros::NodeHandle nh;
    //初始化发布者对象
    ros::Publisher pub;
    pub = nh.advertise<std_msgs::Int8>("intPub",100);
    //组织数据
    int8_t number = 1;
    //设置发布频率
    ros::Rate rate(1); //一秒一次

    while(ros::ok())
    {
        //组织发布数据
        std_msgs::Int8 dataPub;
        dataPub.data = number;
        //发布
        pub.publish(dataPub);
        //休眠
        rate.sleep();  
        //自增
        number++;     
    }


    return 0;
}

2.2 订阅方实现

#include "ros/ros.h"
#include "std_msgs/Int8.h"

void doMsg(const std_msgs::Int8::ConstPtr& msg)
{
    ROS_INFO("接受到的消息为:%d",msg->data);
}

int main(int argc, char *argv[])
{
    /* code */
    //解决乱码
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"sub");
    //句柄
    ros::NodeHandle nh;
    //订阅方对象
    ros::Subscriber sub;
    sub = nh.subscribe<std_msgs::Int8>("intPub",100,doMsg);
    //回旋
    ros::spin();
    return 0;
}

launch文件

<launch>
    <node pkg="int_pub_sub" type="demo_pub_int" name="pub" output="screen"/>
    <node pkg="int_pub_sub" type="demo_sub_int" name="sub" output="screen"/>
</launch>

3、ROS浮点型数据类型的发布和订阅

3.1 发布方实现

#include "ros/ros.h"
#include "std_msgs/Float32.h"

int main(int argc, char *argv[])
{
    /* code */
    //解决乱码
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"pub");
    //句柄
    ros::NodeHandle nh;
    //创建发布者对象
    ros::Publisher pub;
    pub = nh.advertise<std_msgs::Float32>("floatPub",100);
    //发布频率设置
    ros::Rate rate(1);
    
    double number = 1.0;

    while(ros::ok())
    {
        //组织发布消息
        std_msgs::Float32 pubData;
        pubData.data = number;
        //发布
        pub.publish(pubData);
        //自增
        number = number +0.1;
        rate.sleep();
    }

    return 0;
}


3.2订阅方实现

#include "ros/ros.h"
#include "std_msgs/Float32.h"

void domsg(const std_msgs::Float32::ConstPtr& msg)
{
    ROS_INFO("接收到的消息为%.2f",msg->data);
}

int main(int argc, char *argv[])
{
    /* code */
    //解决乱码
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"pub");
    //句柄
    ros::NodeHandle nh;
    //创建订阅者对象
    ros::Subscriber sub;
    sub = nh.subscribe<std_msgs::Float32>("floatPub",100,domsg);
    ros::spin();
    return 0;
}

launch文件

<launch>
    <node pkg="flaoat_pub_sub" type="demo_pub_float" name="pub" output="screen"/>
    <node pkg="flaoat_pub_sub" type="demo_sub_float" name="sub" output="screen"/>
</launch>

4、ROS布尔型数据类型的发布和订阅

4.1发布方实现

#include "ros/ros.h"
#include "std_msgs/Bool.h"

int main(int argc, char *argv[])
{
    /* code */
    //解决乱码问题
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"pub");
    //句柄
    ros::NodeHandle nh;
    //发布者对象
    ros::Publisher pub;
    pub = nh.advertise<std_msgs::Bool>("boolPub",100);
    //发布频率
    ros::Rate rate(1);
    //组织数据
    bool boolData =0;

    while(ros::ok())
    {
        //组织被发布数据
        std_msgs::Bool boolPub;
        boolPub.data = boolData;
        //发布数据
        pub.publish(boolPub);
        //反转
        if (boolData==1)
        {
            boolData = 0;
        }
        else
        {
            boolData = 1;
        }
        //休眠
        rate.sleep();
    }



    return 0;
}

4.2订阅方实现

#include "ros/ros.h"
#include "std_msgs/Bool.h"

void doMsg(const std_msgs::Bool::ConstPtr& msg)
{
    if(msg->data == 1)
    {
        ROS_INFO("接收到的消息为真");
    }
    else
    {
        ROS_INFO("接收到的消息为假");
    }
}

int main(int argc, char *argv[])
{
    /* code */
    //解决乱码问题
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"pub");
    //句柄
    ros::NodeHandle nh;
    //订阅者对象
    ros::Subscriber sub;
    sub = nh.subscribe<std_msgs::Bool>("boolPub",100,doMsg);
    ros::spin();

    return 0;
}

launch文件

<launch>
    <node pkg="bool_pub_sub" type="demo_pub_bool" name="pub" output="screen"/>
    <node pkg="bool_pub_sub" type="demo_sub_bool" name="sub" output="screen"/>
</launch>

二、ROS自定义数据类型的发布和订阅

std_msgs中封装了一些常用的数据类型,但是在实际应用中可能会根据项目的需求自定义一些消息类型,因此需要能够创建自定义消息。

1、相关配置

1.1定义msg文件

在功能包下创建msg文件夹,在该文件夹中添加.msg文件

例:

发布一个联系人的消息,该消息包括姓名、性别、电话号码、地址(前四个为字符串类型)、年龄(int类型)和身高(float类型)

string name
string gender
string phoneNumber
string addres
int8 age
float32 height

1.2 编辑配置文件

在package.xml文件中添加编译依赖和执行依赖

  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>
  <!-- 
  exce_depend 以前对应的是 run_depend 现在非法
  -->

1.3 CMakeList.txt编辑msg相关配置

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
# 需要加入 message_generation,必须有 std_msgs

## 配置 msg 源文件
add_message_files(
  FILES
  Person.msg #自定义的文件名称
)

# 生成消息时依赖于 std_msgs
generate_messages(
  DEPENDENCIES
  std_msgs
)

#执行时依赖
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES demo02_talker_listener
  CATKIN_DEPENDS roscpp rospy std_msgs message_runtime # 新加message_runtime
#  DEPENDS system_lib
)

1.4编译

编译后的中间文件查看

在这里插入图片描述

1.5 vscode配置

为了方便代码提示以及避免误抛异常,需要先配置vscode,为了方便代码提示以及避免误抛异常,需要先配置 vscode,将前面生成的 head 文件路径配置进 c_cpp_properties.json 的 includepath属性:

注:路径的查看可以右击生成的中间文件的include文件夹,选择“在集成终端中打开”,然后再终端输入“pwd”命令,然后复制路径,注意include后面的“/**”不要忘了

在这里插入图片描述

{
    
    
    "configurations": [
        {
    
    
            "browse": {
    
    
                "databaseFilename": "",
                "limitSymbolsToIncludedHeaders": true
            },
            "includePath": [
                "/opt/ros/noetic/include/**",
                "/usr/include/**",
                "/xxx/yyy工作空间/devel/include/**", //配置 head 文件的路径 
                "/home/wang/demo03_ws/devel/include/**",//例子
            ],
            "name": "ROS",
            "intelliSenseMode": "gcc-x64",
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c11",
            "cppStandard": "c++17"
        }
    ],
    "version": 4
}

2、发布方实现

#include "ros/ros.h"
#include "msg_pub_sub/Person.h"

int main(int argc, char *argv[])
{
    /* code */
    //解决乱码
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"pub");
    //句柄
    ros::NodeHandle nh;
    //创建发布者对象
    ros::Publisher pub;
    pub = nh.advertise<msg_pub_sub::Person>("msgPub",100);
    //组织发布消息
    msg_pub_sub::Person person;
    person.age = 18;
    person.addres = "ubuntu路ros小区msg号";
    person.gender = "男";
    person.height = 1.88;
    person.name = "msgPubSub";
    person.phoneNumber = "12345678910";

    //发布频率
    ros::Rate rate(1);

    while(ros::ok())
    {
        pub.publish(person);
        rate.sleep();
    }



    return 0;
}

3、订阅方实现

#include "ros/ros.h"
#include "msg_pub_sub/Person.h"


void doMsg(const msg_pub_sub::Person::ConstPtr& msg)
{
    ROS_INFO("联系人的姓名:%s",msg->name.c_str());
    ROS_INFO("联系人的地址:%s",msg->addres.c_str());
    ROS_INFO("联系人的性别:%s",msg->gender.c_str());
    ROS_INFO("联系人的电话:%s",msg->phoneNumber.c_str());
    ROS_INFO("联系人的年龄:%d",msg->age);
    ROS_INFO("联系人的身高:%.2f",msg->height);
    
}

int main(int argc, char *argv[])
{
    /* code */
    //解决乱码
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"sub");
    //句柄
    ros::NodeHandle nh;
    //创建发布者对象
    ros::Subscriber sub;
    sub = nh.subscribe<msg_pub_sub::Person>("msgPub",100,doMsg);
    ros::spin();
}


4、launch文件

<launch>
    <node pkg="msg_pub_sub" type="demo_pub_msg" name="pub" output="screen"/>
    <node pkg="msg_pub_sub" type="demo_sub_msg" name="sub" output="screen"/>
</launch>

猜你喜欢

转载自blog.csdn.net/weixin_49216787/article/details/132655918