ROS-5.服务机制

目录

一、创建或修改对应文件

1.创建功能包:

2.创建srv文件夹和.srv文件

3.在package.xml文件中添加以下功能包依赖配置

4.在CMakeLists.txt文件中添加如下配置

5.编写两个通讯.cpp文件,分别是客户端和服务端:

二、开始编译运行

三、catkin_make编译遇到的问题:

四、说一说:


关于ROS服务通讯图解:

img

以一个两个加数(a+b)相加的加法运算例子,从底层开始记录起。

一、创建或修改对应文件

1.创建功能包:

cd ~/catkin_ws/src
catkin_create_pkg learning_communication roscpp rospy std_msgs geometry_msgs

进入src文件夹中进行以上终端输入,创建一个功能包且配有以上依赖项。

2.创建srv文件夹和.srv文件

针对加法运算例子中的服务需求,可以用gedit方式创建一个定义服务数据类型的srv文件learning_communication/srv/AddTwoInts.srv:

int64 a
int64 b     
---
int64 sum   

这里的“---”起隔离作用,在“---”上是用于“请求request”,在之下则用于“应答response”。

3.在package.xml文件中添加以下功能包依赖配置

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>  #可以动态生成文件的一个功能包
#第一句用于build(构建)、第二句用于exec(执行)。

4.在CMakeLists.txt文件中添加如下配置

fing_package(catkin REQUIRED COMPONENTS)
    geometry_msgs
    roscpp
    rospy
    std_msgs
    message_generation          #这个比较关键
    
add_service_files(
     FILES
    AddTwoInts.srv                      #定义一个srv文件,让程序可以识别,自动搜索srv文件夹下的.srv文件
)
​
generate_messages(DEPENDENCIES std_msgs)        
#产生srv对应的头文件,生成在catkin_ws/devel/include/learning_communication中,没有这个产生不了头文件

打开CMakeLists.txt发现其实里面早就准备好了类似的模板,在这个前提下输入某些东西给的快捷键也多,减小了输入量。

关于find_package我只添加了最后一行message_generation;

关于add_srtvice_files需要自己添加,但是大体模板会在里面提供。

5.编写两个通讯.cpp文件,分别是客户端和服务端:

Server.cpp

#include "ros/ros.h"
#include "learning_communication/AddTwoInts.h"  //添加头文件,learning_communication是功能包名字,AddTwoInts.h是根据AddTwoInts.srv生成的头文件
/*
1.添加头文件
2.设计回调函数
3.初始化服务端节点名
4.创建句柄
5.注册一个服务端,创建话题
6.spin循环进行
*/
bool add(learning_communication::AddTwoInts::Request &req, learning_communication::AddTwoInts::Response &res)              //作为应答的一个回调函数,注意函数入口中的参数形式::Request &req和::Response &res是ROS中强制命名的
{
    res.sum= req.a + req.b;
    ROS_INFO("request:x=%ld ,y=%ld",(long int)req.a,(long int)req.b);
    ROS_INFO("sending back response:[%ld]",(long int)res.sum);
    return true;
}
​
int main(int argc, char **argv){
    //初始化,节点名字为serveci_nodename作为服务端节点名
    ros::init(argc,argv,"service_nodename");
    //创建一个句柄
    ros::NodeHandle n;
    //注册一个服务端,话题名为service_topicname,规定将客户端传来的数据传入add()函数中
    ros::ServiceServer service = n.advertiseService("service_topicname",add);
​
    ROS_INFO("Ready to add two ints");
    //开始循环函数
    ros::spin();    // 主程序到这里往下不再进行,等待话题进来回调就行
​
    return 0;
}

Client.cpp

#include <cstdlib> 
#include "ros/ros.h"
#include "learning_communication/AddTwoInts.h"
/*
1.添加头文件
2.初始化客户端节点名
3.创建句柄
4.注册一个客户端,向某个话题请求服务并发送数据
5.填充数据(向srv类型定义的变量幅值)并发送
*/
int main(int argc, char   **argv)
{
    //初始化,节点名为client_nodename作为客户端节点名
    ros::init(argc,argv,"client_nodename");
​
    if(argc!=3){
        ROS_INFO("Usage:plz enter three number a,b");
        return 1;
    }
    //创建一个句柄
    ros::NodeHandle n;
    //注册一个客户端,请求服务并将数据传输一个名字为"service_topicname"的话题中去
    ros::ServiceClient client = n.serviceClient<learning_communication::AddTwoInts>("service_topicname");
    //用该srv文件类型定义变量 srv
    learning_communication::AddTwoInts srv;
    //将输入的数值分别幅值给srv中“请求”的a与b,(为什么是a与b?因为srv文件中定义的变量名就是a与b)
    srv.request.a = atoll(argv[1]);
    srv.request.b = atoll(argv[2]);
    //client.call为发送请求函数,参数为上面定义的一个变量srv,等待应答response结果并进入该函数,有点类似发布话题中的NodeHandle_name.publish(TopicTrans_param);
    if(client.call(srv)){          
        ROS_INFO("Sum:%ld",(long int)srv.response.sum);
    }
    else
    {
        ROS_ERROR("Failed to call service to the topic service_topicname");
        return 1;
    }
    return 0;
}

6.在CMakeLists.txt中加入编译这两个通讯文件的功能

add_executable(Server src/Server.cpp)           
target_link_libraries(Server ${catkin_LIBRARIES})
add_dependencies(Server ${PROJECT_NAME}_gencpp)   #依赖动态生成的cpp文件
​
add_executable(Client src/Client.cpp)
target_link_libraries(Client ${catkin_LIBRARIES})
add_dependencies(Client ${PROJECE_NAME}_gencpp)

二、开始编译运行

打开终端:

cd ~/catkin_ws
catkin_make
source devel/setup.bash
roscore
rosrun learning_communication Server
rosrun learning_communication Client 4 9  //这里的4和9就是输入的两个加数

效果图:

图1 生成头文件(注意:Request和Response是ROS中强制定义的)

 图2 生成编译文件 Client 和 Server

 服务传输效果

三、catkin_make编译遇到的问题:

1.启动roscore时没有切换回python2导致报错。

解决:切换优先级

sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 100 
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 150

2.Error(s):

  • The manifest of package "learning_communication" (with format version 2) must not contain the following tags: run_depend

  • Please replace <run_depend> tags with <exec_depend> tags.

    解决:与版本有关,按照提示将package.xml文件中的 <run_depend>替换为 <exec_depend>即可。

3.缺少gencpp文件

解决:

将CMakeLists.txt中的: cmake_minimum_required(VERSION 3.0.2) 改成:cmake_minimum_required(VERSION 2.8.3)

4.缺少AddTwoInts.h头文件

/home/wood/catkin_ws/src/learning_communication/src/Client.cpp:3:10: fatal error: learning_communication/AddTwoInts.h: 没有那个文件或目录

#include "learning_communication/AddTwoInts.h"

^~~~~~~~~

解决:

由于CMakeLists.txt中缺少了一行生成头文件的代码,添加:

generate_messages(DEPENDENCIES std_msgs)

可恶啊!书上并没有这个!!!

四、说一说:

ros::spin();循环函数

在程序到达ros::spin()之前按照一系列规则,设定一系列话题订阅者。这些订阅者就开始嗷嗷待哺,等待话题进来,但这时候订阅者的嘴还没有打开。然后就到ros::spin(),这可以理解为一个动作,打开订阅者的嘴,这样订阅者们可以开始接受话题,最重要的是进入回调函数!当然,最开始的时候,没有话题进来,spin()是堵塞在这里的。一旦有话题进来,一系列订阅、回调、发布等等动作在spin()这里不断在进行,只要有合适的话题,相应的订阅者就订阅,然后直接进行回调。

在终端窗口体现就是进程一直没有结束,数据传输一直在进行。使函数一直处于循环的过程中,在这期间可以传递/接收数据又等待、传递/接收数据又等待……

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值