赞
踩
前面我们实现了一个简单的ROS发送节点和接受信息的节点,在自动驾驶中最常遇到的场景是:两个或者几个节点相互通讯,不是单方面的发送信息,这里我们以实现两个整数求和为例,client端节点向server端节点发送a、b的请求,server端节点返回响应sum=a+b给client端节点.
1. 功能包的创建
在catkin_ws/src/目录下新建功能包service_example,并在创建时显式的指明依赖roscpp和std_msgs,依赖std_msgs将作为基本数据类型用于定义我们的服务类型。
- $ cd ~/catkin_ws/src/
- $ catkin_create_pkg service_example roscpp std_msgs
2. 在功能包中创建自定义服务类型
a. 通信过程中服务的数据类型需要用户自己定义,与消息std_msgs不同。数据类型定义文件都是以*.srv为扩展名并且被放在功能包的srv/文件夹下。我们创建 AddTwoInts.srv如下:
- int64 a
- int64 b
- ---
- int64 sum
在CMakeLists.txt中找到 : 修改成 :
b. 除了上面添加的依赖还需要,添加编译依赖message_generation,运行依赖message_runtime。
在CMakeLists.txt中找到: 修改成
找到: 取消注释修改成:
generate_messages的作用是自动创建我们自定义的消息类型*.msg与服务类型*.srv相对应的*.h,由于我们定义的服务类型使用了std_msgs中的int64基本类型,所以必须向generate_messages指明该依赖.
c. 打开功能包中的package.xml文件,填入下面三句依赖:
- <build_depend>message_generation</build_depend>
- <build_export_depend>message_generation</build_export_depend>
- <exec_depend>message_runtime</exec_depend>
d. 检查ROS是否识别新建的服务类型:我们通过<功能包名/服务类型名>找到该服务,打开命令行终端,输入命令:
- $ source ~/catkin_ws/devel/setup.bash
- $ rossrv show service_example/AddTwoInts
看到下面的输出,就说明新建服务类型能被ROS识别,新建服务类型成功了。
3. 源代码编写
在service_example/src/目录下新建两个文件server_node.cpp和client_node.cpp:
首先,介绍server节点server_node.cpp,代码内容如下:
- #include "ros/ros.h"
- #include "service_example/AddTwoInts.h"//编译时自动生成.h文件
-
- //这个函数实现两个int64整数求和的服务,两个int64值从request获取,返回求和结果装入response里。
- bool add_execute(service_example::AddTwoInts::Request &req,
- service_example::AddTwoInts::Response &res){
- res.sum = req.a + req.b;
- ROS_INFO("recieve request: a=%ld,b=%ld",(long int)req.a,(long int)req.b);
- ROS_INFO("send response: sum=%ld",(long int)res.sum);
- return true;
- }
-
- int main(int argc,char **argv){
- ros::init(argc,argv,"server_node");
- ros::NodeHandle nh;
- //创建服务,并将服务加入到ROS网络中,并且这个服务在ROS网络中以名称add_two_ints唯一标识
- ros::ServiceServer service = nh.advertiseService("add_two_ints",add_execute);
- ROS_INFO("service is ready!!!");
- ros::spin();
- return 0;
- }
介绍client节点client_node.cpp:
- #include "ros/ros.h"
- #include "service_example/AddTwoInts.h"
- #include <iostream>
-
- int main(int argc,char **argv){
- ros::init(argc,argv,"client_node");
- ros::NodeHandle nh;
- ros::ServiceClient client = nh.serviceClient<service_example::AddTwoInts>("add_two_ints");//创建client对象,用来向ROS网络中名称叫add_two_ints的service发起请求
- service_example::AddTwoInts srv;//定义了一个service_example::AddTwoInts服务类型的对象,该对象中的成员正是我们在*.srv文件中定义的a、b、sum,我们将待请求的数据填充到数据成员a、b,请求成功后返回结果会被自动填充到数据成员sum中。
- while(ros::ok()) {
- long int a_in,b_in;
- std::cout<<"please input a and b:";
- std::cin>>a_in>>b_in;
- srv.request.a = a_in;
- srv.request.b = b_in;
- if(client.call(srv)){//这一句便是通过client的方法call来向service发起请求,请求传入的参数srv在上面已经介绍过了。
- ROS_INFO("sum=%ld",(long int)srv.response.sum);
- }
- else{
- ROS_INFO("failed to call service add_two_ints");
- }
- }
- return 0;
- }
4. 编译配置及编译
在CMakeLists.txt文件的末尾行加入以下几句用于声明可执行文件就可以了:
- add_executable(server_node src/server_node.cpp)
- target_link_libraries(server_node ${catkin_LIBRARIES})
- add_dependencies(server_node service_example_gencpp)
-
- add_executable(client_node src/client_node.cpp)
- target_link_libraries(client_node ${catkin_LIBRARIES})
- add_dependencies(client_node service_example_gencpp)
add_executable用于声明可执行文件, target_link_libraries用于声明可执行文件创建时需要链接的库, add_dependencies用于声明可执行文件的依赖项,service_example_gencpp的作用是让编译系统自动根据我们的功能包和在功能包下创建的*.srv文件生成的对应的头文件和库文件, 接下来,就可以用下面的命令对功能包进行编译了:
- $ cd ~/catkin_ws/
- $ catkin_make -DCATKIN_WHITELIST_PACKAGES="service_example"
5. 功能包的启动运行
$ roscore //启动ROS节点管理器
$ cd ~/catkin_ws/
$ source devel/setup.bash //or $ source devel/setup.zsh
$rosrun service_example server_node //激活catkin_ws工作空间
看到有输出“servive is ready!!!”,就说明server节点已经正常启动并开始等待client节点向自己发起请求了.
$ cd ~/catkin_ws/
$ source devel/setup.bash //or $ source devel/setup.zsh
$ rosrun service_example client_node //激活catkin_ws工作空间
看到有输出提示信息“please input a and b:”后,键盘键入两个整数,以空格分割,输入完毕后回车。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。