参考:http://wiki.ros.org/cn/ROS/Tutorials/CreatingMsgAndSrv 参考:http://wiki.ros.org/cn/ROS/Tutorials/WritingServiceClient%28c%2B%2B%29 要注意在ROS中有catkin和rosbuild两种创建程序包的方法,关于catkin与rosbuild的区别,可参考博客http://blog.csdn.net/chishuideyu/article/details/53581013 个人感觉意思就是说catkin比rosbuild的方法要更鲁棒一些,因此选择catkin的方法创建包,在编译的时候不要把这两种给混淆
一、创建catkin工作空间
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/
catkin_make
创建好后,将会在src路径下生成CMakeLists.txt,并且在src的上一级文件夹中生成build和devel的文件夹,在devel文件夹中会看到几个setup.*sh文件,然后将这些文件的路径添加到环境变量中,为了避免每次都添加,直接在~/.bashrc文件的末尾添加以下语句即可
source ~/catkin_ws/devel/setup.bash
为了确保工作空间正确的添加,可以输出环境变量查看,是否有新建的工作空间catkin_ws
echo $ROS_PACKAGE_PATH
二、创建catkin程序包
在新建的工作空间中的src目录下,创建一个新的程序包,这个程序包依赖于std_msgs、roscpp和rospy
cd src
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
这将会创建一个名为beginner_tutorials的文件夹,这个文件夹里面包含一个package.xml文件和一个CMakeLists.txt文件,这两个文件都已经自动包含了部分你在执行catkin_create_pkg命令时提供的信息 新打开一个终端,运行命令,查看功能包是否创建
rospack find beginner_tutorials
三、在包中创建一个服务:
roscd beginner_tutorials
mkdir srv
在srv文件下创建AddTwoInts.srv的文件,内容如下:
int64 a
int64 b
---
int64 sum
还有很关键的一步:我们要确保srv文件被转换成C++,Python和其他语言的源代码。 查看package.xml, 确保它包含以下两条语句
<build_depend>message_generation</build_depend>
<run_depend>message_runtime</run_depend>
如果没有,添加进去。 注意,在构建的时候,我们只需要”message_generation”。然而,在运行的时候,我们只需要”message_runtime”。 现在认为,你已经如前边所介绍的,在CMakeLists.txt文件中增加对message_generation的依赖:
# Do not just add this line to your CMakeLists.txt, modify the existing line
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation)
(对的, message_generation 对msg和srv都起作用) 然后删掉#,去除对下边语句的注释(没有的话在文件末尾添加):
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )
用你自己的srv文件名替换掉那些Service*.srv文件:
add_service_files(
FILES
AddTwoInts.srv
)
以上就是创建一个服务所需的所有步骤。下面通过rosmsg show命令,检查ROS是否能够识该服务。 使用方法:
rossrv show <service type>
例子:
rossrv show beginner_tutorials/AddTwoInts
你将会看到:
int64 a
int64 b
---
int64 sum
你也可以不指定具体的package名来查找服务文件:
$ rossrv show AddTwoInts
[beginner_tutorials/AddTwoInts]:
int64 a
int64 b
---
int64 sum
[rospy_tutorials/AddTwoInts]:
int64 a
int64 b
---
int64 sum
接下来,在CMakeLists.txt中找到如下部分:
# generate_messages(
# DEPENDENCIES
# # std_msgs # Or other packages containing msgs
# )
去掉注释并附加上所有你消息文件所依赖的那些含有.msg文件的package(这个例子是依赖std_msgs,不要添加roscpp,rospy),结果如下
generate_messages(
DEPENDENCIES
std_msgs
)
由于增加了新的消息,所以我们需要重新编译我们的package:
# In your catkin workspace
cd ~/catkin_ws/
catkin_make
cd -
所有在msg路径下的.msg文件都将转换为ROS所支持语言的源代码。生成的C++头文件将会放置在~/catkin_ws/devel/include/beginner_tutorials/。 Python脚本语言会在 ~/catkin_ws/devel/lib/python2.7/dist-packages/beginner_tutorials/msg 目录下创建。 lisp文件会出现在 ~/catkin_ws/devel/share/common-lisp/ros/beginner_tutorials/msg/ 路径下.
五、编写Service节点
这里,我们将创建一个简单的service节点(“add_two_ints_server”),该节点将接收到两个整形数字,并返回它们的和。 首先进入所创建的beginner_tutorials包所在的目录:
roscd beginner_tutorials
在beginner_tutorials包中创建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;
}
现在,让我们来逐步分析代码。
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
beginner_tutorials/AddTwoInts.h是由编译系统自动根据我们先前创建的srv文件生成的对应该srv文件的头文件。
bool add(beginner_tutorials::AddTwoInts::Request &req,
beginner_tutorials::AddTwoInts::Response &res)
这个函数提供两个int值求和的服务,int值从request里面获取,而返回数据装入response内,这些数据类型都定义在srv文件内部,函数返回一个boolean值。
{
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值已经相加,并存入了response。然后一些关于request和response的信息被记录下来。最后,service完成计算后返回true值。
ros::ServiceServer service = n.advertiseService("add_two_ints", add);
这里,service已经建立起来,并在ROS内发布出来。
六、编写Client节点
在beginner_tutorials包中创建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;
}
现在,让我们来逐步分析代码。
ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
这段代码为add_two_ints service创建一个client。ros::ServiceClient 对象待会用来调用service。
beginner_tutorials::AddTwoInts srv;
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);
这里,我们实例化一个由ROS编译系统自动生成的service类,并给其request成员赋值。一个service类包含两个成员request和response。同时也包括两个类定义Request和Response。
if (client.call(srv))
这段代码是在调用service。由于service的调用是模态过程(调用的时候占用进程阻止其他代码的执行),一旦调用完成,将返回调用结果。如果service调用成功,call()函数将返回true,srv.response里面的值将是合法的值。如果调用失败,call()函数将返回false,srv.response里面的值将是非法的。
七、编译节点
再来编辑一下beginner_tutorials里面的CMakeLists.txt,文件位于~/catkin_ws/src/beginner_tutorials/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)
这段代码将生成两个可执行程序”add_two_ints_server”和”add_two_ints_client”,你可以直接调用可执行程序,或者使用rosrun命令去调用它们。它们不会被装在<prefix>/bin目录下,因为当你在你的系统里安装这个包的时候,这样做会污染PATH变量。如果你希望在安装的时候你的可执行程序在PATH变量里面,你需要设置一下install target 现在运行catkin_make命令:
# In your catkin workspace
cd ~/catkin_ws
catkin_make
八、测试节点
首先运行Service:
rosrun beginner_tutorials add_two_ints_server
然后运行Client并附带一些参数:
rosrun beginner_tutorials add_two_ints_client 1 3
你将会看到如下类似的信息:
request: x=1, y=3
sending back response: [4]