写一个Service节点
这里我们将会创建一个名为"add_two_ints_server"的Service节点,其接收两个整型数,并返回两个数的和。
首先,切换到我们之前所创建的“beginner_tutorials”包中:
roscd beginner_tutorials
同时,请确保我们在前面博客:ROS学习-创建一个ROS
msg和一个srv中已经创建了这里所需要的AddTwoInts.srv文件。
Service节点源码
在“beginner_tutorials”包中的/src文件夹下创建一个“add_two_ints_server.cpp”文件。
touch src/add_two_ints_server.cpp
并写入下述内容:
#include "ros/ros.h" #include "beginner_tutorials/AddTwoInts.h" bool add(beginner_tutorials::AddTwoInts::Request &req, beginner_tutorials::AddTwoInts::Response &res) { 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) { ros::init(argc, argv, "add_two_ints_server"); ros::NodeHandle n; ros::ServiceServer service = n.advertiseService("add_two_ints", add); ROS_INFO("Ready to add two ints."); ros::spin(); return 0; }
Service节点源码解释
现在,我们对上述源码进行分段解释:
首先是头文件引用:
#include "ros/ros.h" #include "beginner_tutorials/AddTwoInts.
"ros/ros.h"是常用的ROS头文件,“beginner_tutorials/AddTwoInts.h"是在创建”.srv"文件过程中所生成的头文件。
接下来是是一个bool函数:
bool add(beginner_tutorials::AddTwoInts::Request &req, beginner_tutorials::AddTwoInts::Response &res) { 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; }
这个函数提供两个整型数相加的服务,其使用了在srv文件中所定义的请求AddTwoInts::Request和响应AddTwoInts::Response数据的类型,并返回一个bool类型。此外上述代码中还把一些关于请求和响应的信息通过ROS_INFO记录下来并显示了。
接下来使用下述代码创建了一个service节点,并广播。
ros::ServiceServer service = n.advertiseService("add_two_ints", add);
写一个client节点
client节点源码
在“beginner_tutorials”包中的/src文件夹下创建一个“add_two_ints_client.cpp”文件。
touch src/add_two_ints_client.cpp
并写入下述内容:
#include "ros/ros.h" #include "beginner_tutorials/AddTwoInts.h" #include <cstdlib> int main(int argc, char **argv) { ros::init(argc, argv, "add_two_ints_client"); if (argc != 3) { ROS_INFO("usage: add_two_ints_client X Y"); return 1; } ros::NodeHandle n; ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints"); beginner_tutorials::AddTwoInts srv; srv.request.a = atoll(argv[1]); srv.request.b = atoll(argv[2]); if (client.call(srv)) { ROS_INFO("Sum: %ld", (long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_two_ints"); return 1; } return 0; }
client节点源码解释
类似的,我们对上述源码进行分段解释:
首先是头文件引用:
#include "ros/ros.h" #include "beginner_tutorials/AddTwoInts.h" #include <cstdlib>
接着是初始化节点:
ros::init(argc, argv, "add_two_ints_client");
判断参数数量是否满足使用要求:
if (argc != 3) { ROS_INFO("usage: add_two_ints_client X Y"); return 1; }
为名字为:add_two_ints 的 service对象创建一个ros::ServiceClient对象。这个ros::ServiceClient对象在后续用来调用service。
ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
接着,我们实例化一个自动生成的service类,并对其中的request成员赋值。一个service类包含两个成员,request 和 response。它还包括Request 和 Response两个类的定义。
最后,调用前述创建的service,并判断是否调用成功(返回true)。
if (client.call(srv))
如果服务调用成功,call()将返回true,srv.response中的值将有效。如果调用未成功,call()将返回false,srv.response中的值将无效。
编译节点
首先,再次在CMakeLists.txt中修改对应的内容,增加:
add_executable(add_two_ints_server src/add_two_ints_server.cpp) target_link_libraries(add_two_ints_server ${catkin_LIBRARIES}) add_dependencies(add_two_ints_server beginner_tutorials_gencpp) add_executable(add_two_ints_client src/add_two_ints_client.cpp) target_link_libraries(add_two_ints_client ${catkin_LIBRARIES}) add_dependencies(add_two_ints_client beginner_tutorials_gencpp)
切换到“catkin_ws”工作空间所在的文件路径,使用catkin_make命令进行编译。这将创建两个可执行文件, add_two_ints_server和 add_two_ints_client,默认生成到package包中的devel空间中。
catkin_make
运行节点
打开两个新的Terminal窗口,与上一篇博客中运行talker和listener节点类似的,我们也可以通过rosrun的方式,或者直接运行可执行文件的方式调用add_two_ints_server和add_two_ints_client节点。
第一个窗口中输入:
$ rosrun beginner_tutorials add_two_ints_server
返回结果:
[ INFO] [1637129512.406196185]: Ready to add two ints.
第二个窗口输入:
$ rosrun beginner_tutorials add_two_ints_client 2 3
返回结果:
[ INFO] [1637129869.838190279]: Sum: 5
同时,第一个窗口界面中也会返回以下结果:
[ INFO] [1637129869.838004528]: request: x=2, y=3 [ INFO] [1637129869.838039617]: sending back response: [5]