个人觉得,和前面话题的发布和订阅没有很大的区别,所以这一节主要将内容集中在总结上。
一、实验任务
通过C++代码创建一个客户端,该客户端通过向海龟可视化界面应用中的请求/spawn
服务,在指定位置产生一个新的海龟。
整个流程总结如下:
二、实验过程
2.1 创建一个package
到工作空间下的src中使用catkin_create_pkg
创建一个新的功能包:
catkin_create_pkg service_test roscpp std_msgs geometry_msgs turtlesim
注意添加上本次实验要用到的turtlesim功能包,roscpp、std_msgs 和geometry_msgs都是功能包。
2.2 编写服务端代码
无论是话题还是服务,无论是发起端还是请求端,基本过程都类似,总结如下:
在对一个应用进行服务请求前,可以通过rosserive list
查看当前可以使用的服务(注意,应用需要启动才能看到):
因为请求服务必须得知道约定的数据格式是什么,所以我们可以通过rosservice info + 服务名
查看服务约定的参数有哪些格式。这里我查看了/spawn
服务的信息:
为了进一步得到这个数据具体格式需要用到rosservice type /spawn
+rossrv show
:
可以很清楚的看出各参数的类型,具体含义需要查看服务是如何定义的,这里:x
y
theta
代表新海龟的位置和角度,name
表示海龟名字(可以让程序自动生成)。
#include <ros/ros.h>
#include <turtlesim/Spawn.h>
int main(int argc,char ** argv)
{
//初始化节点
ros::init(argc,argv,"requestNewLife");
ros::NodeHandle node;
//利用节点管理器node创建一个客户端
ros::service::waitForService("/spawn");//话题阻塞至服务启动
ros::ServiceClient client=node.serviceClient<turtlesim::Spawn>("/spawn");//模板参数是在语言层面上的,参数是实际通信层面的
//准备数据
turtlesim::Spawn srv;
srv.request.x=2.0;
srv.request.y=2.0;
srv.request.name="NewTurtle";
ROS_INFO("Requesting new turtle name= %s, at [%f,%f,%f]",
srv.request.name.c_str(),srv.request.x,srv.request.y,srv.request.theta);
//客户端数据输出操作
client.call(srv);
ROS_INFO("A new turtle created!");
return 0;
}
2.3 修改CMakeLists.txt并编译
新增以下语句:
add_executable(callforNewlife src/requestNewTurtle.cpp)
target_link_libraries(callforNewlife ${catkin_LIBRARIES})
回到工作空间根目录,catkin_make
,如无意外,显示结果如下:
2.4 启动核心和应用
roscore
rosrun turtlesim turtlesim_node
rosrun service_test callforNewlife
果然产生了一个小乌龟:
[1] https://www.ncnynl.com/archives/201608/503.html