ROS 创建服务和请求
来源:互联网 发布:供销社大数据集团 地点 编辑:程序博客网 时间:2024/05/21 17:01
教程
维基 http://wiki.ros.org/cn/ROS/Tutorials
快速过程
创建包
$ cd ~/catkin_ws$ mkdir ~/catkin_ws/src$ cd ~/catkin_ws/src$ catkin_init_w$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
编译包:
$ cd ~/catkin_ws$ catkin_make
详细过程
1安装环境配置(桌面进入命令行)
echo "source /opt/ros/indigo/setup.bash" >> ~/.bashrcsource ~/.bashrc
2.1创建工作环境并编译 (生成的在home文件夹下)
mkdir -p ~/catkin_ws/srccd ~/catkin_ws/catkin_make
2.2自己创建的包环境 能看到’build’和’devel’这两个文件夹。
将当前工作环境设置在ROS工作环境
source /home/dongdong/catkin_ws/devel/setup.bash
如果永久性配置
echo "source /home/dongdong/catkin_ws/devel/setup.bash" >> ~/.bashrcsource ~/.bashrc
查看是否配置成功
echo $ROS_PACKAGE_PATH
3 创建包
cd ~/catkin_ws/srccatkin_create_pkg beginner_tutorials std_msgs rospy roscpp
- 依赖包文件
std_msgs
rospy
roscpp
4编译(空 可不编译)
cd ~/catkin_wscatkin_make
5 创建ROS消息和ROS服务
- 一般消息类型
int8, int16, int32, int64 (plus uint*)float32, float64stringtime, durationother msg filesvariable-length array[] and fixed-length array[C]
- 特殊的数据类型:Header
它含有时间戳和坐标系信息
Header header string child_frame_id geometry_msgs/PoseWithCovariance pose geometry_msgs/TwistWithCovariance twist
5.1 创建一个msg
$ cd ~/catkin_ws/src/beginner_tutorials$ mkdir msg$ echo "int64 num" > msg/Num.msg
上面是最简单的例子——在.msg文件中只有一行数据。当然,你可以仿造上面的形式多增加几行以得到更为复杂的消息:
string first_namestring last_nameuint8 ageuint32 score
接下来,还有关键的一步:我们要确保msg文件被转换成为C++,Python和其他语言的源代码:
查看package.xml, 确保它包含一下两条语句:
<build_depend>message_generation</build_depend> <run_depend>message_runtime</run_depend>
查看CMakeLists.txt
(过程可跳过,直接下面CMakeLists.txt 文件最终内容复制进去beginner_tutorials/CMakeLists.txt 更改)
cmake_minimum_required(VERSION 2.8.3)project(beginner_tutorials)## Find catkin and any catkin packagesfind_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)## Declare ROS messages and servicesadd_message_files(DIRECTORY msg FILES Num.msg)add_service_files(DIRECTORY srv FILES AddTwoInts.srv)## Generate added messages and servicesgenerate_messages(DEPENDENCIES std_msgs)## Declare a catkin packagecatkin_package()
CMakeLists.txt 具体设置过程
利用find_packag函数,增加对message_generation的依赖
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation)
设置了运行依赖
catkin_package( ... CATKIN_DEPENDS message_runtime ... ...)
找到并去掉注释#
# add_message_files(# FILES# Message1.msg# Message2.msg# )
替换.msg 文件
add_message_files( FILES Num.msg)
手动添加.msg文件后,我们要确保CMake知道在什么时候重新配置我们的project。 确保添加了如下代码:
generate_messages()
现在,你可以生成自己的消息源代码了
5.2 使用一个msg
通过rosmsg show命令,检查ROS是否能够识消息。
$ rosmsg show beginner_tutorials/Num
你将会看到:
int64 numstring first_namestring last_nameuint8 ageuint32 score
6 创建一个服务 srv
在刚刚那个package中创建一个服务:
$ roscd beginner_tutorials$ mkdir srv
这次我们不再手动创建服务,而是从其他的package中复制一个服务。 roscp是一个很实用的命令行工具,它实现了将文件从一个package复制到另外一个package的功能。
$ roscp [package_name] [file_to_copy_path] [copy_path]
从rospy_tutorials package中复制一个服务文件了:
$ roscp rospy_tutorials AddTwoInts.srv srv/AddTwoInts.srv
还有很关键的一步:我们要确保srv文件被转换成C++,Python和其他语言的源代码。
查看package.xml, 确保它包含一下两条语句(第5步创建msg时已经添加):
<build_depend>message_generation</build_depend> <run_depend>message_runtime</run_depend>
在CMakeLists.txt文件中
(过程可跳过,直接下面CMakeLists.txt 文件最终内容复制进去beginner_tutorials/CMakeLists.txt 更改,第5步创建msg时如果直接复制了可不用执行):
# Do not just add this line to your CMakeLists.txt, modify the existing linefind_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation)
(对的, message_generation 对msg和srv都起作用)
用你自己的srv文件名替换掉那些Service*.srv文件:
add_service_files( FILES AddTwoInts.srv )
6.2使用rossrv
$ rossrv show beginner_tutorials/AddTwoInts
你将会看到:
int64 aint64 b---int64 sum
7 msg和srv都需要的步骤(可省略 直接讲最终CMakeLists.txt内容替换即可)
在CMakeLists.txt中找到如下部分:
# generate_messages(# DEPENDENCIES# # std_msgs # Or other packages containing msgs# )
去掉注释并附加上所有你消息文件所依赖的那些含有.msg文件的package(这个例子是依赖std_msgs,不要添加roscpp,rospy),结果如下:
generate_messages(DEPENDENCIES std_msgs)
最终CMakeLists.txt文件内容为(和第五步创建msg的一样):
cmake_minimum_required(VERSION 2.8.3)project(beginner_tutorials)## Find catkin and any catkin packagesfind_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)## Declare ROS messages and servicesadd_message_files(DIRECTORY msg FILES Num.msg)add_service_files(DIRECTORY srv FILES AddTwoInts.srv)## Generate added messages and servicesgenerate_messages(DEPENDENCIES std_msgs)## Declare a catkin packagecatkin_package()
重新编译我们的package:
cd ~/catkin_wscatkin_make
8编写简单的消息发布器和订阅器 (C++)
切换到之前创建的 beginner_tutorials package 路径下:
cd ~/catkin_ws/src/beginner_tutorials
在 beginner_tutorials package 路径下创建一个src文件夹:
发布者节点
mkdir -p ~/catkin_ws/src/beginner_tutorials/src
这个文件夹将会用来放置 beginner_tutorials package 的所有源代码。
在 beginner_tutorials package 里创建 src/talker.cpp 文件,并将如下代码粘贴到文件内:
//引用了 ROS 系统中大部分常用的头文件#include "ros/ros.h"//引用了 std_msgs/String 消息, 它存放在 std_msgs package 里,是由 String.msg 文件自动生成的头文件#include "std_msgs/String.h"#include <sstream>int main(int argc, char **argv){ //初始化 ROS 。它允许 ROS 通过命令行进行名称重映射 ros::init(argc, argv, "talker"); /** 为这个进程的节点创建一个句柄。 第一个创建的 NodeHandle 会为节点进行初始化, 最后一个销毁的 NodeHandle 则会释放该节点所占用的所有资源。 */ ros::NodeHandle n; /** 告诉 master 我们将要在 chatter(话题名) 上发布 std_msgs/String 消息类型的消息。 这样 master 就会告诉所有订阅了 chatter 话题的节点,将要有数据发布。 第二个参数是发布序列的大小。如果我们发布的消息的频率太高,缓冲区中的消息在大于 1000 个的时候就会 开始丢弃先前发布的消息。 NodeHandle::advertise() 返回一个 ros::Publisher 对象,它有两个作用: 1) 它有一个 publish() 成员函数可以让你在topic上发布消息; 2) 如果消息类型不对,它会拒绝发布。 */ ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000); //我们让它以 10Hz 的频率运行。 ros::Rate loop_rate(10); /** * A count of how many messages we have sent. This is used to create * a unique string for each message. */ int count = 0; /* roscpp 会默认生成一个 SIGINT 句柄,它负责处理 Ctrl-C 键盘操作——使得 ros::ok() 返回 false。 如果下列条件之一发生,ros::ok() 返回false: SIGINT 被触发 (Ctrl-C) 被另一同名节点踢出 ROS 网络 ros::shutdown() 被程序的另一部分调用 节点中的所有 ros::NodeHandles 都已经被销毁 一旦 ros::ok() 返回 false, 所有的 ROS 调用都会失效。 */ while (ros::ok()) { /** 一个由 msg file 文件产生的『消息自适应』类在 ROS 网络中广播消息。现在我们使用标准的String消 息,它只有一个数据成员 "data" */ std_msgs::String msg; std::stringstream ss; ss << "hello world " << count; msg.data = ss.str(); //ROS_INFO 和其他类似的函数可以用来代替 printf/cout 等函数 ROS_INFO("%s", msg.data.c_str()); /** 我们向所有订阅 chatter 话题的节点发送消息。 */ chatter_pub.publish(msg);/*在这个例子中并不是一定要调用 ros::spinOnce(),因为我们不接受回调。然而,如果你的程序里包含其他回调函数,最好在这里加上 ros::spinOnce()这一语句,否则你的回调函数就永远也不会被调用了。*/ ros::spinOnce(); loop_rate.sleep(); ++count; } return 0;}
订阅者节点
在 beginner_tutorials package 目录下创建 src/listener.cpp 文件,并粘贴如下代码:
#include "ros/ros.h"#include "std_msgs/String.h"/** 这是一个回调函数,当接收到 chatter 话题的时候就会被调用。消息是以 boost shared_ptr 指针的形式传输,这就意味着你可以存储它而又不需要复制数据。 */void chatterCallback(const std_msgs::String::ConstPtr& msg){ ROS_INFO("I heard: [%s]", msg->data.c_str());}int main(int argc, char **argv){ ros::init(argc, argv, "listener"); ros::NodeHandle n; /** 告诉 master 我们要订阅 chatter 话题上的消息。 当有消息发布到这个话题时,ROS 就会调用 chatterCallback() 函数。 第二个参数是队列大小,以防我们处理消息的速度不够快,当缓存达到 1000 条消息后, 再有新的消息到来就将开始丢弃先前接收的消息。 NodeHandle::subscribe() 返回 ros::Subscriber 对象,你必须让它处于活动状态直到你不再想订阅该 消息。当这个对象销毁时,它将自动退订 chatter 话题的消息。 */ ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback); /** ros::spin() 进入自循环,可以尽可能快的调用消息回调函数。如果没有消息到达,它不会占用很多 CPU, 所以不用担心。一旦 ros::ok() 返回 false,ros::spin() 就会立刻跳出自循环。这有可能是ros::shutdown() 被调用,或者是用户按下了 Ctrl-C,使得 master 告诉节点要终止运行。也有可能是 节点被人为关闭的。 */ ros::spin(); return 0;}
编译节点
之前教程中使用 catkin_create_pkg 创建了 package.xml 和 CMakeLists.txt 文件。
cmake_minimum_required(VERSION 2.8.3)project(beginner_tutorials)## Find catkin and any catkin packagesfind_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)## Declare ROS messages and servicesadd_message_files(DIRECTORY msg FILES Num.msg)add_service_files(DIRECTORY srv FILES AddTwoInts.srv)## Generate added messages and servicesgenerate_messages(DEPENDENCIES std_msgs)## Declare a catkin packagecatkin_package()
在 CMakeLists.txt 文件末尾加入几条语句:
include_directories(include ${catkin_INCLUDE_DIRS})add_executable(talker src/talker.cpp)target_link_libraries(talker ${catkin_LIBRARIES})add_executable(listener src/listener.cpp)target_link_libraries(listener ${catkin_LIBRARIES})
最终看起来
cmake_minimum_required(VERSION 2.8.3)project(beginner_tutorials)## Find catkin and any catkin packagesfind_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)## Declare ROS messages and servicesadd_message_files(FILES Num.msg)add_service_files(FILES AddTwoInts.srv)## Generate added messages and servicesgenerate_messages(DEPENDENCIES std_msgs)## Declare a catkin packagecatkin_package()## Build talker and listenerinclude_directories(include ${catkin_INCLUDE_DIRS})add_executable(talker src/talker.cpp)target_link_libraries(talker ${catkin_LIBRARIES})add_dependencies(talker beginner_tutorials_generate_messages_cpp)add_executable(listener src/listener.cpp)target_link_libraries(listener ${catkin_LIBRARIES})add_dependencies(listener beginner_tutorials_generate_messages_cpp)
这会生成两个可执行文件, talker 和 listener, 默认存储到 devel space 目录下,具体是在
~/catkin_ws/devel/lib/ 中.
现在要为可执行文件添加对生成的消息文件的依赖:
add_dependencies(talker beginner_tutorials_generate_messages_cpp)
这样就可以确保自定义消息的头文件在被使用之前已经被生成。因为 catkin 把所有的 package 并行的编译,所以如果你要使用其他 catkin 工作空间中其他 package 的消息,你同样也需要添加对他们各自生成的消息文件的依赖。
现在运行 catkin_make:
# In your catkin workspace$ catkin_make
测试消息发布器和订阅器
确保roscore可用,并运行:
roscore
catkin specific 如果使用catkin,确保你在调用catkin_make后,在运行你自己的程序前,已经source了catkin工作空间下的setup.sh文件: (我们在创建工作区的时候已经永久写入配置文件,不需要在进行设置)
# In your catkin workspace$ cd ~/catkin_ws$ source ./devel/setup.bash
启动发布者
$ rosrun beginner_tutorials talker (C++)
你将看到如下的输出信息:
[INFO] [WallTime: 1314931831.774057] hello world 1314931831.77[INFO] [WallTime: 1314931832.775497] hello world 1314931832.77[INFO] [WallTime: 1314931833.778937] hello world 1314931833.78[INFO] [WallTime: 1314931834.782059] hello world 1314931834.78[INFO] [WallTime: 1314931835.784853] hello world 1314931835.78[INFO] [WallTime: 1314931836.788106] hello world 1314931836.79
启动订阅者
$ rosrun beginner_tutorials listener (C++)
你将会看到如下的输出信息:
[INFO] [WallTime: 1314931969.258941] /listener_17657_1314931968795I heard hello world 1314931969.26[INFO] [WallTime: 1314931970.262246] /listener_17657_1314931968795I heard hello world 1314931970.26[INFO] [WallTime: 1314931971.266348] /listener_17657_1314931968795I heard hello world 1314931971.26[INFO] [WallTime: 1314931972.270429] /listener_17657_1314931968795I heard hello world 1314931972.27[INFO] [WallTime: 1314931973.274382] /listener_17657_1314931968795I heard hello world 1314931973.27[INFO] [WallTime: 1314931974.277694] /listener_17657_1314931968795I heard hello world 1314931974.28[INFO] [WallTime: 1314931975.283708] /listener_17657_1314931968795I heard hello world 1314931975.28
9 编写简单的服务和客户端
9.1 编写Service节点
进入先前你在catkin workspace教程中所创建的beginner_tutorials包所在的目录:
cd ~/catkin_ws/src/beginner_tutorials
在beginner_tutorials包中创建src/add_two_ints_server.cpp文件,并复制粘贴下面的代码:
#include "ros/ros.h"//编译系统自动根据我们先前创建的srv文件生成的对应该srv文件的头文件。#include "beginner_tutorials/AddTwoInts.h"/*int值从request里面获取,而返回数据装入response内,这些数据类型都定义在srv文件内部,函数返回一个boolean值。*/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;}
9.2 编写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"); //我们实例化一个由ROS编译系统自动生成的service类,并给其request成员赋值。一个service类包含两个成员request和response。同时也包括两个类定义Request和Response。 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;}
编译节点
再来编辑一下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”,这两个可执行程序默认被放在你的devel space下的包目录下,默认为~/catkin_ws/devel/lib/share/。你可以直接调用可执行程序,或者使用rosrun命令去调用它们。它们不会被装在/bin目录下,因为当你在你的系统里安装这个包的时候,这样做会污染PATH变量。如果你希望在安装的时候你的可执行程序在PATH变量里面,你需要设置一下install target,
运行catkin_make命令:
cd ~/catkin_wscatkin_make
10 测试简单的Service和Client
roscore
启动服务
rosrun beginner_tutorials add_two_ints_server
你将会看到如下类似的信息:
Ready to add two ints.
运行Client
rosrun beginner_tutorials add_two_ints_client 1 3
你将会看到如下类似的信息:
request: x=1, y=3sending back response: [4]
现在,你已经成功地运行了你的第一个Service和Client程序!
- ROS 创建服务和请求
- 创建ROS消息和ROS服务
- 创建ROS消息和ROS服务
- ROS入门_1.13 创建ROS消息和ROS服务
- ROS教程(十):创建ROS消息和ROS服务
- ROS笔记:(7)创建ROS消息和ROS服务
- ROS学习--(十一)创建ROS的信息和服务
- 创建ROS消息和ROS服务(九)
- ROS Learning-012 beginner_Tutorials (编程) 创建自定义的ROS消息和ROS服务
- ROS学习(基于Ubuntu 15.04 和ROS Jade)第三章 ROS核心教程 之 10 创建ROS消息和ROS服务
- ROS服务和客户端
- ROS)服务和参数
- ROS服务和参数
- 学习9:rosed命令的简单介绍 + 创建ROS消息和ROS服务。
- ROS Learning-009 beginner_Tutorials ROS服务 和 ROS参数
- ROS总结——ROS消息和ROS服务
- rosparam和ROS参数服务
- 创建ROS msg 和 srv
- mysql 5.6 数据库 占用 内存 过多 的 解决方案
- Laravel核心理解(一)--服务提供者(ServiceProvider)
- 在vs2013中设置全局的include和lib方法
- yii 原生sql使用数据库前缀
- 程序员应该吃什么
- ROS 创建服务和请求
- css : 标准文档流
- Linux学习笔记:用户和组管理
- 思诚90后程序员们对老爸说的话 | …
- HDU 1213 How Many Tables
- 说出你的偶像 | SCTV原创视频
- Keras学习之六:训练辅助及优化工具
- 【转】Linux 中的/lib和/usr/lib目录区别
- java关键字---this 和super