ROS学习笔记(二) 话题通信

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

前言:
本文是新手的学习笔记。如有错误欢迎指正
使用版本:ubuntu20.04
使用语言:c++
参考链接:http://www.autolabor.com.cn/book/ROSTutorials/

https://blog.csdn.net/qq_44339029/article/details/120579608?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168007050016800184160811%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=168007050016800184160811&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-120579608-null-null.142v77insert_down38,201v4add_ask,239v2insert_chatgpt&utm_term=ubuntu20.04%E5%AE%89%E8%A3%85ros&spm=1018.2226.3001.4187

一、话题通信的理论模型

这里是赵老师的官方学习文档中的模型在这里插入图片描述具体化描述:Talker:提亲者,二狗子
Master:媒婆,婚介网站
Listener:翠花
实现流程:二狗子向媒婆提交个人信息,翠花向媒婆订阅男方个人信息(advertise subscribe)
媒婆把手机号发给翠花,
翠花打电话给狗子,
狗子回应并且加vx(此时二者建立连接,可以通过TCP越过master进行交流)

二、代码实现

1.发布方

(1)总体步骤:

1.包含头文件
2.初始化ros节点
3.创建节点句柄
4.创发布者对象
5.编写发布逻辑并发布数据

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
/*
发布方实现
    1.包含头文件
    2.初始化ros节点
    3.创建节点句柄
    4.创发布者对象
    5.编写发布逻辑并发布数据
*/
int main(int argc,char *argv[]){
    setlocale(LC_ALL,"");
    //初始化ros节点
    ros::init(argc,argv,"Hutao");
    //创建节点句柄
    ros::NodeHandle nh;
    //创建发布者对象
    ros::Publisher pub = nh.advertise<std_msgs::String>("fang",10);
    //编写发布逻辑和发布数据

    //*添加要求 10HZ 并且在文本后添加编号
    //先发布被创建的信息
    std_msgs::String msg;
    //发布;频率
    ros::Rate rate(10);
    //编号
    int count = 0 ;
    //编写循环,循环中发布数据

    while(ros::ok()){
        count++;
        //实现字符串拼接数字;stringstream类:https://blog.csdn.net/Sakuya__/article/details/122751238
        std::stringstream  ss;

        ss<<"hello ---"<<count;

        //msg.data="hello";
        msg.data=ss.str();
        pub.publish(msg);
        //添加日志
        ROS_INFO("发布的数据是:%s",ss.str().c_str());
        rate.sleep();
        ros::spinOnce();//官方建议添加。处理回调函数
    }

}

(3)调整cmake

add_executable(demo01_pub src/demo01_pub.cpp)
target_link_libraries(demo01_pub
  ${catkin_LIBRARIES}
)

(4)终端代码及效果

cd 工作空间
source ./devel/setup.bash
source rosrun 文件夹 cpp文件名(无后缀)

在这里插入图片描述

(5)可能出现的问题
中文乱码问题:???????
解决方法:setlocale(LC_ALL,"");

2.订阅方实现

1.步骤

1.包含头文件
    ros中文本类型--->std_msgs/String.h
2.初始化ros节点
3.创建节点句柄
4.创建订阅者对象
5.处理订阅到的数据
6.spin()函数

2.代码实现

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


void doMsg(const std_msgs::String::ConstPtr &msg_p){
    //通过msg获取并且操作订阅到的数据
    ROS_INFO("翠花订阅到的数据:%s",msg_p->data.c_str());
    // ROS_INFO("我听见:%s",(*msg_p).data.c_str());
}

int main(int argc,char *argv[]){
    setlocale(LC_ALL,"");

    ros::init(argc,argv,"listener");
    ros::NodeHandle nh;
    //实例化 订阅者对象
    ros::Subscriber sub= nh.subscribe("fang",10,doMsg);//fang就是主题

    //处理订阅的消息(回调函数)
    ros::spin();//如果没有很可能订阅不到,这里是堵住的意思,等待话题进来回调
    */

}

3.终端及代码实现/终端输入:与上面发布方同理
效果:在这里插入图片描述

3.自定义msg的发布方和订阅方

0.预先:

(1)在功能包(src)下定义msg目录,添加文件person.msg

string name
int32 age
float32 height

(2)在package.xml中添加依赖

  <build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

(3)在cmakeList中编译相关
这几个解除注释,**部分为标注,请自行添加

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  ***message_generation***
)
# 生成消息时依赖于 std_msgs
generate_messages(
  DEPENDENCIES
  std_msgs
)
#执行时依赖
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES demo02_talker_listener
  CATKIN_DEPENDS roscpp rospy std_msgs ***message_runtime***
#  DEPENDS system_lib
)

# 需要加入 message_generation,必须有 std_msgs

(4)c_cpp_properties.json配置
head文件路径:邮件继承目录打开,pwd并且去掉include后面部分

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

1.代码部分

/*
    需求: 循环发布人的信息

*/

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

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    ROS_INFO("这是消息发布方:");
    //1.初始化 ROS 节点
    ros::init(argc,argv,"talker_person");

    //2.创建 ROS 句柄
    ros::NodeHandle nh;

    //3.创建发布者对象
    ros::Publisher pub = nh.advertise<plumbing_pubsub::Person>("information",10);

    //4.组织被发布的消息,编写发布逻辑并发布消息
    plumbing_pubsub::Person person;
    person.name = "张三";
    person.age = 1;
    person.height = 1.73;

    ros::Rate rate(1);
    while (ros::ok())
    {
        pub.publish(person);
        person.age += 1;
        ROS_INFO("我叫:%s,今年%d岁,高%.2f米", person.name.c_str(), person.age, person.height);

        rate.sleep();
        ros::spinOnce();
    }



    return 0;
}
--------------------------------------------
/*
订阅方
    1.包含头文件
    2.初始化ros节点
    3.创建节点句柄
    4.处理订阅者对象
    5.处理订阅的数据
    6.调用spin()函数
*/
#include "ros/ros.h"
#include "plumbing_pubsub/Person.h"


void doPerson(const plumbing_pubsub::Person::ConstPtr& person){
    ROS_INFO("订阅人的信息:%s, %d, %.2f",person->name.c_str(),person->age,person->height);
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    ROS_INFO("订阅方:");
    //1.初始化 ROS 节点
    ros::init(argc,argv,"listen_people");

    //2.创建 ROS 句柄
    ros::NodeHandle nh;

    //3.创建发布者对象
    ros::Subscriber sub = nh.subscribe("information",10,doPerson);

  

    ros::spin();

    return 0;
}

2.依赖部分

add_executable(demo03_pubmsg src/demo03_pubmsg.cpp)
add_executable(demo04_submsg src/demo04_submsg.cpp)
add_dependencies(demo03_pubmsg ${PROJECT_NAME}_generate_messages_cpp)
add_dependencies(demo04_submsg ${PROJECT_NAME}_generate_messages_cpp)
target_link_libraries(demo03_pubmsg
  ${catkin_LIBRARIES}
)
target_link_libraries(demo04_submsg
  ${catkin_LIBRARIES}
)

3.终端及效果(包含计算图)

roscore

zzl@zzl-lenovo:~$ cd talker_c
zzl@zzl-lenovo:~/talker_c$ source ./devel/setup.bash

zzl@zzl-lenovo:~/talker_c$ rosrun plumbing_pubsub demo03_pubmsg
zzl@zzl-lenovo:~/talker_c$ rosrun plumbing_pubsub demo04_submsg

在这里插入图片描述rqt_graph
在这里插入图片描述

4.注意事项:

(1)不要提前写依赖,可能在编译时出现这个情况
在这里插入图片描述这里我提前写了订阅方的依赖导致的

4.一个想要讨论的概念:回调函数和spin()

一个讲的比较好的视频链接:https://www.bilibili.com/video/BV1vL411t78b/?spm_id_from=333.337.search-card.all.click&vd_source=d8532aebb8bb1bfb5088a1a3cef25521

尽管如此,我仍旧不能清楚认知回调函数和spin(),以下为为的个人理解。希望有大佬可以指正
回调函数:即把函数名(函数指针)作为参数调用

关于上面subscribe调用domsg函数,我的理解是:subscribe和发布者的消息连接,当有新消息传来时候,subscribe就调用domsg函数作为回调函数,但是如果没有spin(),就不会执行,相当于开辟一个子流程,类似异步通信?中断驱动?spin()就是停下来不断检测有无回调函数

关于我对这个函数的回调和spin()粗俗理解:
翠花订阅二狗子后,一旦二狗子在房有新消息,就给翠花发消息,翠花就把不断看微信消息这件事放在代办里(回调函数),spin是一直反复检查代办。如果不检查则不会看代办

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值