第二章 ROS学习----通信机制

目录

2.1话题通信

2.1.1 分析

2.1.2 发布者,订阅者实现(C++实现)

2.1.3编译并实现

2.2 通信过程中的函数解析(c++)

2.3服务通信

2.3.1 原理


参考于2.1.2 话题通信基本操作A(C++) · Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程

2.1话题通信

2.1.1 分析

话题通信的角色:

1.master ---->管理者

2.Talker ----->发布者

3.listener----->订阅者

话题通信的关注点:(由于连接的建立已经封装,所以关注点有以下4点)

1.话题的设置

2.发布者的实现

3.订阅者的实现

4.关注消息载体

2.1.2 发布者,订阅者实现(C++实现)

mkdir -p demo04_ws/src  //建立目录

catkin_make //编译

code .  //利用vscode打开

选择Create catkin Package创立包

并添加依赖 roscpp,rospy,std_msgs

vscode中编译ros

快捷键 ctrl + shift + B 调用编译,选择:catkin_make:build

可以点击配置设置为默认,修改.vscode/tasks.json 文件

{
// 有关 tasks.json 格式的文档,请参见
    // https://go.microsoft.com/fwlink/?LinkId=733558
    "version": "2.0.0",
    "tasks": [
        {
            "label": "catkin_make:debug", //代表提示的描述性信息
            "type": "shell",  //可以选择shell或者process,如果是shell代码是在shell里面运行一个命令,如果是process代表作为一个进程来运行
            "command": "catkin_make",//这个是我们需要运行的命令
            "args": [],//如果需要在命令后面加一些后缀,可以写在这里,比如-DCATKIN_WHITELIST_PACKAGES=“pac1;pac2”
            "group": {"kind":"build","isDefault":true},
            "presentation": {
                "reveal": "always"//可选always或者silence,代表是否输出信息
            },
            "problemMatcher": "$msCompile"
        }
    ]
}

pub_c.cpp   发布者实现

/*
  实现流程:
        1.包含头文件 
        2.初始化 ROS 节点:命名(唯一)
        3.实例化 ROS 句柄
        4.实例化 发布者 对象
        5.组织被发布的数据,并编写逻辑发布数据

*/

#include "ros/ros.h"
#include"std_msgs/String.h"
#include<sstream>

int main(int argc,char *argv[])
{
  //设置编码
  setlocale(LC_ALL,"");

  //2.初始化ROS节点:命名唯一
  ros::init(argc,argv,"talker");

  //3.实例化ROS句柄
  ros::NodeHandle nh;

  //4.实例化发布者对象

  ros::Publisher pub =nh.advertise<std_msgs::String>("chatter",10);

  //5.组织被发布的数据,并编写逻辑发布数据
  std_msgs::String msg;

  std::string msg_front="Hello,你好";

  int count=0;//消息计数器

  //发布频率,1秒十次
  ros::Rate r(1);

  //若节点不死
  while(ros::ok)
  { 
    //使用stringsteam拼接字符串与编号
    std::stringstream ss;
    ss<<msg_front<<count;
    msg.data =ss.str();

    //发布消息
    pub.publish(msg);
    
    //加入调试,打印发送消息
    ROS_INFO("发送的消息:%s",msg.data.c_str());

    //休眠时间=1/频率
    r.sleep();
    count++;//循环结束前,让count递增

    //暂无应用
    ros::spinOnce();
    

  }
   return 0;


}

编写好发布方文件后,可以通过 rostopic echo 节点名称

来看看是否发布成功

sub_c.cpp 订阅者实现

/*
  实现流程:
        1.包含头文件 
        2.初始化 ROS 节点:命名(唯一)
        3.实例化 ROS 句柄
        4.实例化 发布者 对象
        5.组织被发布的数据,并编写逻辑发布数据

*/

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

//回调函数
void doMsg(const std_msgs::String::ConstPtr msg_p)
{
 ROS_INFO("我听见:%s",msg_p->data.c_str());
}


int main(int argc,char *argv[])
{
  setlocale(LC_ALL,"");
  //2.初始化ROS节点
  ros::init(argc,argv,"Listener");

  //实例化ROS句柄
  ros::NodeHandle nh;

  //4.实例化订阅者者对象
  ros::Subscriber sub =nh.subscribe<std_msgs::String>("chatter",10,doMsg);

  //6.设置循环调用回调函数
  ros::spin();//调用回调函数,循环读取接受的数据

    return 0;
}

修改cMakeLists.txt

其中 pub_c是pub_c.cpp文件的一个映射

2.1.3编译并实现

 快捷键 ctrl + shift + B 调用编译成功后,打开终端 

roscore

打开所在目录 cd demo04_ws

source ./devel/setup.bash

rosrun 包名 节点

2.2 通信过程中的函数解析(c++)


n.advertise<>()函数
  例句:ros::Publisher pub = n.advertise<std_msgs::String>("chatter", 1000);
  n–句柄名称,advertise<topic_message_type>()函数接受两个参数,第一个参数为要发布的topic名称,第二个参数为设置缓冲区的大小。<>内部为topic发布的数据类型。
  advertise()函数将会告知topic master要发布的话题名称。调用advertise()函数后,master node将master node将通知订阅该话题的subscriber,然后进行数据传输。
  advertise()返回一个Publisher的对象,调用该对象可以再此topic上发布消息。
ros::Rate loop_rate(int)函数
  ros::Rate类可定制频率的函数,接受一个int型参数,通过调用主函数末尾的上来sleep()函数,将该参数置为发布频率。
pub.publish(msg)函数
   publisher类的成员函数,接受一个消息对象的引用,利用此函数可以将消息对象msg里面的内容发布出去,消息对象msg的类型要和advertise<topic_message_type>()函数中标定的消息类型相一致。
ros::Rate sleep()函数
  与loop_rate()函数成套使用,使程序能按照设定的频率发布数据。
n.subscriber()函数
  例句:ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
  设置subscriber函数,该函数为一个topic生成subscriber,函数接受三个参数,第一个参数设置为订阅话题的名称,第二个参数为接受缓冲区的大小,第三个参数为接收到函数后需操作的调用函数。
"beginner_tutorials/AddTwoInts.h"头文件
  该头文件在设置srv文件时由ros自动生成,头文件原型为<package_name>/<file_name>.h,头文件内定义了该service接收的每个参数的类型以及服务返回值的类型。
n.advertiseService()函数
  例句:ros::ServiceServer service = n.advertiseService("add_two_ints", add);
  设置service函数,该函数将会在ros系统中生成一个service,函数接受两个参数,第一个参数将被设置为service的名称,第二个参数作为该service功能执行函数,供相应的client节点调用。
n.serviceClient()函数
  例句:ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
  设置client函数,该函数将在ros中生成一个client,该函数接受一个服务名作为参数,向ros指明client要调用的服务。
ros::ok()函数
  该函数会设置一个SIGINT监听,函数返回True,仅当以下四种情况发生时,该函数返回False:
   1. SIGINT被触发(Ctrl+c)
   2.被另一同名节点踢出
   3.函数ros::shutdown()被程序另一部分调用
   4.程序所有句柄被销毁
ros::spin(),ros::spinOnce()函数
  ros回调程序,spin()不会执行原程序,spinOnce()会继续执行原程序

ROS_INFO()函数

例句: ROS_INFO("发送的消息:%s",msg.data.c_str());打印输出

解释:句柄

系统为每个进程在内存中分配一定的区域,用来存放各个句柄,即一个个32位无符号整型值(32位操作系统中)。每个32位无符号整型值相当于一个指针,指向内存中的另一个区域(我们不妨称之为区域A)。而区域A中存放的正是对象在内存中的地址。当对象在内存中的位置发生变化时,区域A的值被更新,变为当前时刻对象在内存中的地址,而在这个过程中,区域A的位置以及对应句柄的值是不发生变化的。这种机制,用一种形象的说法可以表述为:有一个固定的地址(句柄),指向一个固定的位置(区域A),而区域A中的值可以动态地变化,它时刻记录着当前时刻对象在内存中的地址这样,无论对象的位置在内存中如何变化,只要我们掌握了句柄的值,就可以找到区域A,进而找到该对象。而句柄的值在程序本次运行期间是绝对不变的,我们(即系统)当然可以掌握它。
 

2.3服务通信

2.3.1 原理

2.3.2服务通信自定义srv

在建立并且编译项目后,建立srv 文件夹,接着建立.srv文件

接着对package.xml文件进行修改,添加

<build_depend>message_generation</build_depend>

 <exec_depend>message_runtime</exec_depend>

接着修改CMakeList.txt文件

 

 

添加中间文件include的路径到.json文件中

 

 

 

 编译文件,Cmake需要修改的地方

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值