目录
关于ROS服务通讯图解:
以一个两个加数(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()这里不断在进行,只要有合适的话题,相应的订阅者就订阅,然后直接进行回调。
在终端窗口体现就是进程一直没有结束,数据传输一直在进行。使函数一直处于循环的过程中,在这期间可以传递/接收数据又等待、传递/接收数据又等待……