教程

维基 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" >> ~/.bashrc
source ~/.bashrc

2.1创建工作环境并编译 (生成的在home文件夹下)

mkdir -p ~/catkin_ws/src
cd ~/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" >> ~/.bashrc
source ~/.bashrc

查看是否配置成功

echo $ROS_PACKAGE_PATH

3 创建包

cd ~/catkin_ws/src
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
  • 依赖包文件

    std_msgs

    rospy

    roscpp

4编译(空 可不编译)

cd ~/catkin_ws
catkin_make

5 创建ROS消息和ROS服务

  • 一般消息类型
int8, int16, int32, int64 (plus uint*)
float32, float64
string
time, duration
other msg files
variable-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_name
string last_name
uint8 age
uint32 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 packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg) ## Declare ROS messages and services
add_message_files(DIRECTORY msg FILES Num.msg)
add_service_files(DIRECTORY srv FILES AddTwoInts.srv) ## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs) ## Declare a catkin package
catkin_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 num
string first_name
string last_name
uint8 age
uint32 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 line
find_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 a
int64 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 packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg) ## Declare ROS messages and services
add_message_files(DIRECTORY msg FILES Num.msg)
add_service_files(DIRECTORY srv FILES AddTwoInts.srv) ## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs) ## Declare a catkin package
catkin_package()

重新编译我们的package:

cd ~/catkin_ws
catkin_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 packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg) ## Declare ROS messages and services
add_message_files(DIRECTORY msg FILES Num.msg)
add_service_files(DIRECTORY srv FILES AddTwoInts.srv) ## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs) ## Declare a catkin package
catkin_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 packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg) ## Declare ROS messages and services
add_message_files(FILES Num.msg)
add_service_files(FILES AddTwoInts.srv) ## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs) ## Declare a catkin package
catkin_package() ## Build talker and listener
include_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_ws
catkin_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=3
sending back response: [4]

现在,你已经成功地运行了你的第一个Service和Client程序!

ROS 创建服务和请求的更多相关文章

  1. ROS之服务

    服务(service)是另一种在节点之间传递数据的方法,服务其实就是同步的跨进程函数调用,它能够让一个节点调用运行在另一个节点中的函数. 我们就像之前消息类型一样定义这个函数的输入/输出.服务端(提供 ...

  2. AngularJS开发指南15:AngularJS的创建服务,将服务注入到控制器,管理服务依赖详解

    创建服务 虽然AngularJS提供了很多有用的服务,但是如果你要创建一个很棒的应用,你可能还是要写自己的服务.你可以通过在模块中注册一个服务工厂函数,或者通过Module#factory api或者 ...

  3. nodejs零基础详细教程2:模块化、fs文件操作模块、http创建服务模块

    第二章  建议学习时间4小时  课程共10章 学习方式:详细阅读,并手动实现相关代码 学习目标:此教程将教会大家 安装Node.搭建服务器.express.mysql.mongodb.编写后台业务逻辑 ...

  4. node.js零基础详细教程(2):模块化、fs文件操作模块、http创建服务模块

    第二章  建议学习时间4小时  课程共10章 学习方式:详细阅读,并手动实现相关代码 学习目标:此教程将教会大家 安装Node.搭建服务器.express.mysql.mongodb.编写后台业务逻辑 ...

  5. Angular5学习笔记 - 创建服务(九)

    一.创建服务 ng generate service service-name #简写 ng g s component-name ng g s services/userService 二.效果 三 ...

  6. springcloud-Netflix创建服务消费者

    目录 springcloud-Netflix创建服务消费者 Ribbon 创建服务消费者-Ribbon方式 ribbon的架构 Feign 创建包和基本项目结构 创建Feign访问服务的接口和访问co ...

  7. 允许asp.net MVC报 错说明: 访问服务此请求所需的资源时出错。服务器可能未配置为访问所请求的 URL。错误消息 401.2。: 未经授权

    运行mvc3程序报以下错误 详细报错如下: “/”应用程序中的服务器错误. 访问被拒绝. 说明: 访问服务此请求所需的资源时出错.服务器可能未配置为访问所请求的 URL. 错误消息 401.2.: 未 ...

  8. WIN32服务程序(一):创建服务

    MSDN中有安装服务的例子Installing a Service(可点击进入),我们这里的创建服务,和MSDN里的例子基本上是一样的.这里做一些简单的说明: 打开控制面板,管理工具,服务.我们看到的 ...

  9. 创建服务factory和service方法的区别

    factory方法返回的是对象,json或数组,也可以返回字符串类型的数据,但service方法只能返回数据或对象 创建服务有3种方法 $provide.provider('服务名',function ...

随机推荐

  1. float浮动的世界

    loat有四个属性,分别是: float:none:  没有浮动: float:left:  左浮动: float:right: 右浮动: float:inherit:继承父元素的浮动: ------ ...

  2. 微信wx.request

    官方 wx.request 代码,Post 没成功过,使用Get 方式成功了. wx.request({ url: 'test.php', //仅为示例,并非真实的接口地址 data: { x: '' ...

  3. POJ1509 Glass Beads(最小表示法 后缀自动机)

    Time Limit: 3000MS   Memory Limit: 10000K Total Submissions: 4901   Accepted: 2765 Description Once ...

  4. 微信小程序心得

    首先从官方文档给的框架说起,微信小程序官方文档给出了app.js, app.json, app.wxss. 先从这三个文件说起. - app.js 这个文件是整个小程序的入口文件,开发者的逻辑代码在这 ...

  5. springboot 文件上传下载

    关键点: 1,使用 POST 请求2,consumes=MediaType.MULTIPART_FROM_DATA_VALUE3,@RequestParm 里面的字符串和前端 input 控件的 na ...

  6. Java之static作用的全方位总结

    1.深度总结 引用一位网友的话,说的非常好,如果别人问你static的作用:如果你说静态修饰 类的属性 和 类的方法 别人认为你是合格的:如果是说 可以构成 静态代码块,那别人认为你还可以: 如果你说 ...

  7. python特性--property

    在定义一个类的时候,有时我们需要获取一个类的属性值,而这个属性值需要经过类中的其他属性运算来获得的.那么很容易,只要我们在类中定义一个方法,并且通过调用方法可以获取到那个需要运算的属性值.那么,问题来 ...

  8. html-edm(邮件营销)编写规则

    最近写了一个edm邮件 以前没有接触过  使用的是很老的html页面编写规则  只能用table标签  在此记录一下edm编写的一些规则 个人参考的是这两个网址,转载一下 http://www.zco ...

  9. The process could not read file xxx due to OS error 53

      在不同地域的两个SQL Server服务器上配置了复制(Replication)用于同步数据(生产环境配置有Replication,测试环境也配有Replication),两地通过专线连接起来,这 ...

  10. ERROR 1044 (42000): Access denied for user 'root'@'localhost'

    从供应商那边接手一个MySQL数据库(数据库版本为5.7.21 MySQL Community Server (GPL)),在创建账号时遇到了"ERROR 1044 (42000): Acc ...