简介:介绍如何在一个node里调用现有的rosservice list查询到的service。
效果:通过talker publish需要调用服务的数据,listener接收到数据后调用服务进行三个整形数据相加,并返回相加和。
环境:ubuntu 14.04 +indigo.
备注:文中未详细介绍的api或ros的基本函数请参看之前博文。
[正文]
创建过程类似wiki教程中msg和srv的测试过程。在beginner_turtorials包下面创建。
1,创建msg文件夹,srv文件夹。
msg 文件夹下创建Num.msg,内容是
int32 A
int32 B
int32 C
srv文件夹下AddTwoInts.srv,内容是
int32 A
int32 B
int32 C
---
int32 sum
该文件表面输入是ABC,返回是 sum,两者通过“---”分割。
2,然后更改CMakeList.txt文件,修改为如下内容,主要设计msg,srv的其他依赖关系及编译运行的相关关系。
## Find catkin macros and libraries ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) ## is used, also find other catkin packages find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation )
## Generate messages in the 'msg' folder add_message_files( FILES Num.msg ) ## Generate services in the 'srv' folder add_service_files( FILES AddTwoInts.srv )
## Generate added messages and services with any dependencies listed here generate_messages( DEPENDENCIES std_msgs )
# include_directories(include) include_directories( ${catkin_INCLUDE_DIRS} )
catkin_package( # INCLUDE_DIRS include # LIBRARIES beginner_tutorials # CATKIN_DEPENDS roscpp rospy std_msgs # DEPENDS system_lib CATKIN_DEPENDS message_runtime )
也可参考,wiki中CreatingMsgAndSrv中过程,名称都没有改变,只是改变了文件中内容,改写完成后可以在catkin_ws目录下catkin_make一次,并source devel/setup.bash下。
3,建立几个cpp的源文件,位于src目录下。
3.1 src/example_srv_request.cpp
作用:主要实现服务的定义,初始化,注释由于ubuntu没装汉语输入,因此注释为英文...聊胜于无。
#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+req.C; ROS_INFO("request: A=%ld,B=%ld,C=%ld",(int)req.A,(int)req.B,(int)req.C); ROS_INFO("sending back response:[%ld]",(int)res.sum); return true; } int main(int argc,char **argv) { ros::init(argc,argv,"add_3_ints_server"); ros::NodeHandle n; //init service: //Name: add_3_ints,advertise the service. add: call back function ros::ServiceServer service=n.advertiseService("add_3_ints",add); ROS_INFO("Ready to add 3 ints."); ros::spin();// start to deal with the call back event return 0; }3.2 src/example_srv_response.cpp,该文件并非必要,是典型的client调用服务的形式,并非此文目的,不添加最终目的也可实现,调用示例是(现在还不能调用):
rosrun beginner_tutorials example_srv_response 1 2 3
#include "ros/ros.h" #include "beginner_tutorials/AddTwoInts.h" #include <cstdlib> int main(int argc,char **argv) { ros::init(argc,argv,"add_3_ints_client"); if(argc != 4) { ROS_INFO("usage: add_3_ints_client A B C"); return 1; } ros::NodeHandle n; ros::ServiceClient client=n.serviceClient<beginner_tutorials::AddTwoInts>("add_3_ints"); beginner_tutorials::AddTwoInts srv; //atoll:convert a string to long long int variable srv.request.A=atoll(argv[1]); srv.request.B=atoll(argv[2]); srv.request.C=atoll(argv[3]); if(client.call(srv)) { ROS_INFO("Sum:%ld",(long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_three_ints"); return 1; } return 0; }3.3 src/example_talker_msg.cpp
该文件主要实现3个参数的发布,此处发布了A=1,B=2,C=3;
#include "ros/ros.h" #include "beginner_tutorials/Num.h" #include <sstream> //Usage:publish a msg with topic named message int main(int argc, char **argv) { ros::init(argc, argv, "example_talker_msg"); ros::NodeHandle n; //advertise a topic named "message" ros::Publisher pub=n.advertise<beginner_tutorials::Num>("message",1000); ros::Rate loop_rate(10); while (ros::ok()) { beginner_tutorials::Num msg; msg.A=1; msg.B=2; msg.C=3; pub.publish(msg); ros::spinOnce(); loop_rate.sleep(); } return 0; }3.4 src/example_listener_msg.cpp
该文件主要实现对前文talker发布的数据的监听,监听到Num类型定义数据后,通过service: ros::service::call / client.call()两种方式进行add_3_ints服务的调用。
#include "ros/ros.h" #include "beginner_tutorials/Num.h" #include "beginner_tutorials/AddTwoInts.h" //declaration of the Example class:construct function, member and so on. class Example{ public: Example(); private: ros::NodeHandle nh; ros::ServiceClient client; ros::Subscriber listener; void messageCallback(const beginner_tutorials::Num::ConstPtr& msg); }; //implementation of construct function. Example::Example() { client=nh.serviceClient<beginner_tutorials::AddTwoInts>("add_3_ints"); //monitor a topic named "message",this -> current object,pointer listener=nh.subscribe("message",1000,&Example::messageCallback,this); } //implementation of one of the Example class memeber. void Example::messageCallback( const beginner_tutorials::Num::ConstPtr& msg) { // ROS_INFO("I heard:[%d] [%d] [%d]",msg->A,msg->B,msg->C); beginner_tutorials::AddTwoInts srv; srv.request.A=msg->A; srv.request.B=msg->B; srv.request.C=msg->C; if(ros::service::call("add_3_ints",srv)) ROS_INFO("SUM: %ld",(long int)srv.response.sum); else ROS_ERROR("Failed to call service add_three_ints"); /* if(client.call(srv)) { ROS_INFO("SUM: %ld",(long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_three_ints"); } */ } int main(int argc, char **argv) { ros::init(argc, argv, "example_listener_msg"); Example exp; ros::spin(); return 0; }4 再次修改CMakeList.txt文件
添加编译链接的相关控制语句。
add_executable(example_srv_request src/example_srv_request.cpp) target_link_libraries(example_srv_request ${catkin_LIBRARIES}) add_executable(example_srv_response src/example_srv_response.cpp) target_link_libraries(example_srv_response ${catkin_LIBRARIES}) add_executable(example_talker_msg src/example_talker_msg.cpp) target_link_libraries(example_talker_msg ${catkin_LIBRARIES}) add_executable(example_listener_msg src/example_listener_msg.cpp) target_link_libraries(example_listener_msg ${catkin_LIBRARIES})添加后在工作空间主目录cd ~/catkin_ws下进行catkin_make编译,理论上不会出现问题,若有问题检查自己包和msg,srv的生成及cmakelist文件。
5 测试
一个终端运行命令:roscore,
一个终端运行命令(注意此时近乎所有命令和包的名称及可执行文件名称都可以<table>自动补全):rosrun beginner_tutorials example_srv_request;会返回: [INFO][时间戳]:Ready to add 3 ints. 此时若通过roservice list查询ros提供的服务则会返回add_3_ints等几个服务。
一个终端运行命令:rosrun beginner_tutorials example_talker_msg
一个终端运行命令:rosrun beginner_tutorials example_listener_msg;此时会返回: [INFO][时间戳]:SUM: 6
在此文件中,我们实现了在一个node中以下面两种方式对add_3_ints的服务调用,而不是在命令行中通过rosrun beginner_tutorials example_srv_response 1 2 3调用。
if(ros::service::call("add_3_ints",srv)) ROS_INFO("SUM: %ld",(long int)srv.response.sum); else ROS_ERROR("Failed to call service add_three_ints"); /* if(client.call(srv)) { ROS_INFO("SUM: %ld",(long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_three_ints"); } */