【ROS教程 003】ROS系统初体验

需要特别说明:ROS版本必须与Ubuntu系统版本匹配
实验环境:
ROS Fuerte
Ubuntu 12.04
在进行实际使用ROS开发之前,首先对ROS中的一些基础操作内容进行学习。使用TurtleSim进行练习,其中包括如何建立功能包、使用节点、使用参数服务和移动一个虚拟的机器人。
(1)查看ROS文件系统
使用rospack和rosstack来获取有关功能包、功能包集、路径和依赖性等信息。
查找turtlesim包的路径

$ rospack find turtlesim

获得功能包或功能包集下面的文件列表

$ rosls turtlesim

进入到某个文件夹,使用roscd命令

$ roscd turtlesim

(2) 创建工作空间
查看ROS正在使用的工作空间

$ echo $ROS_PACKAGE_PATH

我们将要创建的文件夹是在~/dev/rosbook/中,使用如下命令

$ cd ~
$ mkdir -p dev/rosbook

创建好文件夹后我们需要将新路径添加到ROS_PACKAGE_PATH,需要在~/.bashrc文件的末尾添加新的一行:

$ echo "export ROS_PACKAGE_PATH=~/dev/rosbook:${ROS_PACKAGE_PATH}" >> ~/.bashrc
$ . ~/.bashrc

这样我们就在ROS系统中创建和配置完成自己的新文件夹。
(3)创建ROS功能包
可以使用手动创建功能包,为了避免繁琐工作,推荐使用roscreate-pck命令行工具。
在rosbook文件夹下创建新的功能包

$ roscreate-pkg davebobo_tutorials std_msgs rospy roscpp

此功能包的格式包括功能包名称和依赖项;其中依赖项包括std_msgs rospy roscpp,如下命令行所示

$ roscreate-pkg [package_name] [depend1] [depend2] [depend3]

值得说明的是:

  • std_msgs 包含了常见消息类型,表示基本数据类型和其他基本的消息构造,如多维数组
  • rospy 一个ROS的纯Python客户端库。
  • roscpp 使用C++实现的ROS的各种功能。程序员能够用这些接口快速完成与ROS的主题、服务和参数相关的开发工作。

正确执行以上命令后的效果:
这里写图片描述
我们可以使用rospack、roscd、rosls命令来获取新的功能包信息。
(4)编译ROS功能包
如果创建了一个功能包并且编写了一下代码,就需要编译功能包了。编译功能包时主要是代码的编译过程,为了编译功能包,可以使用命令rosmak

roscd davebobo_tutorials
rosmake davebobo _tutorial

这里写图片描述
几秒之后编译成功。
(5)使用ROS节点
节点都是可执行程序,位于packagename/bin目录中,我们使用turtlesim的功能包进行练习。
在开始之前,必须使用如下命令启动roscore

$ roscore

使用rosrun命令启动一个新的节点。

$ rosrun turtlesim turtlesim_node

我们可以看见出现一个新窗口,窗口中间出现一个小海龟。
这里写图片描述
这时再去查看节点列表就会看到出现一个新的节点。叫做/turtlesim。使用rosnode info Nodename查看节点的信息。

$ rosnode info /turtlesim
--------------------------------------------------------------------------------
Node [/turtlesim]
Publications:
 * /turtle1/color_sensor [turtlesim/Color]
 * /rosout [rosgraph_msgs/Log]
 * /turtle1/pose [turtlesim/Pose]

Subscriptions:
 * /turtle1/command_velocity [unknown type]

Services:
 * /turtle1/teleport_absolute
 * /turtlesim/get_loggers
 * /turtlesim/set_logger_level
 * /reset
 * /spawn
 * /clear
 * /turtle1/set_pen
 * /turtle1/teleport_relative
 * /kill

contacting node http://davebobo-virtual-machine:60313/ ...
Pid: 3770
Connections:
 * topic: /rosout
  * to: /rosout
  * direction: outbound
  * transport: TCPROS

以上信息中,包括发布者(及相应主题)、订阅者(及相应主题)和该节点具有的服务(srv)及它们各自唯一的名称。
(6)使用主题与节点交互
首先需要打开一个终端在里面运行roscore:

$ roscore

再打开一个终端,在里面运行一个turtlesim_node节点:

$ rosrun turtlesim turtlesim_node

打开另一个终端,在里面输入:

$ rosrun turtlesim turtle_teleop_key

在运行完这条命令后,在这个终端下,按键盘上的方向键可以看到,之前我们运行的乌龟开始移动,:-),很有意思吧。
urtlesim_node和turtle_teleop_key通过ROS的主题来相互通信。turtle_teleop_key把用户按下的键发布到主题上,turtlesim_node也订阅了同一个主题用来接收用户按下的键,并做出相应的动作。我们有这个例子可以体会到主题的作用,更加深刻的认识到了节点的概念。
可以使用以下命令查看/teleop_turtle和/turtlesim节点的信息。

$ rosnode info /teleop_turtle
$ rosnode info /turtlesim

使用rostopic pub [topic] [msg_type] [args]命令直接发布主题。

$ rostopic pub -1 /turtle1/command_velocity turtlesim/Velocity -- 1 1

可以看到小海龟在做曲线运动。
(7)使用服务
同上,先运行roscore并启动turtlesim节点。使用以下命令列出在turtlesim节点运行时系统提供的服务。

$ rosservice list

使用/spawn服务在不同的方向和不同的位置创建另一只小海龟。

$ rosservice call /spawn 3 3 0.2 "new_turtle"

(8)使用参数服务器
参数服务器用于存储所有节点均可以访问的共享数据。ROS中用于管理参数服务器的工具称为rosparam,查看被所有节点所使用的服务器参数:

$ rosparam list

可以使用get参数读取某个值,也可以使用set参数设定一个新的值。rosparam的另外一个特性是参数转存。通过该参数可以保存或加载参数服务器的内容。
使用rosparam dump [file_name]来保存参数服务器。

$ rosparam dump save.yaml

使用rosparam load [file_name] [namesapce]像参数服务器加载一个新的数据文件。

$ rosparam load save.yaml namespace

(9)创建节点和编译节点
本节使用一个实例进行学习,一个发布一些数据,另一个接收这些数据,两个节点之间使用最基本的工作进行通信。进入如下文件位置:

$ roscd davebobo_tutorials/src/

创建两个文件并分别命名为exaple1_a.cpp和example_b.cpp, exaple1_a.cpp文件将会发送带有节点名称的数据, exaple1_b.cpp文件会把这些数据显示在shell窗口中。
exaple1_a.cpp中的代码如下:

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>

int main(int argc,char **argv)
{
     ros::init(argc,argv,"example1_a");
     ros::NodeHandle n;
     ros::Publisher chatter_pub = n.advertise<std_msgs::String>("message",1000);
     ros::Rate loop_rate(10);
while(ros::ok())
{
std_msgs::String msg;
std::stringstream ss;
ss << "I am the example1_a node";
msg.data = ss.str();
chatter_pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}

exaple1_b.cpp中的代码如下:

#include "ros/ros.h"
#include "std_msgs/String.h"

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,"example1_b");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("message",100,chatterCallback);
ros::spin();
return 0;
}

编写好程序后,当使用davebobo_tutorials功能包时,需要自行编辑CMakeLists.txt文件。使用自己喜欢的编辑器或直接使用rosed工具将会在VIM编辑器下打开这个文件,并将以下命令行复制到文件的末尾处:

rosbuild_add_executable(example1_a src/example1_a.cpp)
rosbuild_add_executable(example1_b src/example1_b.cpp)

启动ROS,然后在不同的shell窗口下分别运行以下命令

$ rosrun davebobo_tutorials example1_a
$ rosrun davebobo_tutorials example1_b

可以发现在example1_b运行的shell窗口可以打印出INFO消息。
(10)创建并使用msg和srv文件
① 服务
首先,在davebobo_tutorials功能包下创建msg文件夹,并在其中创建一个新的文件davebobo_msg1.msg。在文件中增加以下行:

int32 A
int32 B
int32 C

接着编辑CMakeList.txt从rosbuild_genmsg()这一行中删除#,然后使用rosmake命令编译功能包。

$ rosmake dvaebobo_tutorials

为检查编译是否正确,使用rosmsg命令,如果可以看到与davebobo_msg1.msg文件中相同的内容说明编译正确。

$ rosmsg show davebobo_tutorials/davebobo_msg1

现在创建一个srv文件,同样在dvaebobo_tutorials文件夹下创建一个名为srv的文件,并新建davebobo_srv1.srv.在文件中增加以下行

int32 A
int32 B
int32 C
---
int32 sum

编辑 CMakeList.txt从rosbuild_gensrv()这一行中删除#,重新编译功能包并使用rossrv工具来检查。

$ rossrv show davebobo_tutorials/davebobo_srv1.srv

上面我们在ROS中创建一个服务,接着我们需要两个节点,一个服务器和一个客户端。在davebobo_tutorials功能包中新建两个节点分别命名为example2_a.cpp和 example2_b.cpp.
example2_a.cpp中的代码:

#include "ros/ros.h"
#include "davebobo_tutorials/davebobo_srv1.h"

bool add(davebobo_tutorials::davebobo_srv1::Request &req,
  davebobo_tutorials::davebobo_srv1::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;

  ros::ServiceServer service = n.advertiseService("add_3_ints", add);
  ROS_INFO("Ready to add 3 ints.");
  ros::spin();

  return 0;
}

example2_b.cpp中的代码:

#include "ros/ros.h"
#include "davebobo_tutorials/davebobo_srv1.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<davebobo_tutorials::davebobo_srv1>("add_3_ints");
  davebobo_tutorials::davebobo_srv1 srv;
  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_two_ints");
  return 1;
  }

  return 0;
}

为了编译节点,在CMakeList.txt文件中增加以下行:

rosbuild_add_executable(example2_a src/example2_a.cpp)
rosbuild_add_executable(example2_b src/example2_b.cpp)

执行编译命令:

$ rosmake davebobo_tutorials

分别在不同命令窗口启动节点:

$ rosrun davebobo_tutorials example2_a
$ rosrun davebobo_tutorials example2_b 1 2 3

example2_a窗口如下显示
这里写图片描述
example2_b窗口如下显示
这里写图片描述
② 消息
现在将使用自定义的msg文件来创建节点。创建example3_a.cpp和 example3_b.cpp文件,同时调用davebobo_msg1.msg
example3_a.cpp中代码

#include "ros/ros.h"
#include "davebobo_tutorials/davebobo_msg1.h"
#include <sstream>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "example1_a");
  ros::NodeHandle n;
  ros::Publisher pub = n.advertise<davebobo_tutorials::davebobo_msg1>("message", 1000);
  ros::Rate loop_rate(10);
  while (ros::ok())
  {
  davebobo_tutorials::davebobo_msg1 msg;
  msg.A = 1;
  msg.B = 2;
  msg.C = 3;
  pub.publish(msg);
  ros::spinOnce();
  loop_rate.sleep();
  }
  return 0;
}

example3_b.cpp中代码

#include "ros/ros.h"
#include "davebobo_tutorials/davebobo_msg1.h"

void messageCallback(const davebobo_tutorials::davebobo_msg1::ConstPtr& msg)
{
  ROS_INFO("I heard: [%d] [%d] [%d]", msg->A, msg->B, msg->C);
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "example1_b");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("message", 1000, messageCallback);
  ros::spin();
  return 0;
}

现在运行这两个节点会显示如下:
这里写图片描述
References:
[1]. Aaron Martinez Enrique Fern andez, ROS机器人程序设计[B], P14-42, 2014.
http://blog.csdn.net/xiaocainiaoshangxiao/article/details/13578493

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DaveBobo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值