概述
本系列文章由 youngpan1101 出品,转载请注明出处。
文章链接: http://blog.csdn.net/youngpan1101/article/details/61196300
作者:宋洋鹏(youngpan1101)
邮箱: yangpeng_song@163.com
1. 安装和配置 ROS 环境
$ export | grep ROS (查看 ROS 相关的环境变量)
$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/src
$ catkin_init_workspace (建立一个 catkin 工作空间)
$ cd ~/catkin_ws
$ catkin_make # 编译指定包 : $ catkin_make -DCATKIN_WHITELIST_PACKAGES="package1;package2"
$ echo "source $HOME/catkin_ws/devel/setup.bash" >> ~/.bashrc (让新打开的 shell 自动添加环境变量)
$ source ~/.bashrc(使环境变量设置立即生效)
$ echo $ROS_PACKAGE_PATH (查看自己建立的工作空间的目录是否在环境变量中)
2. 文件系统导航
$ rospack find [package_name] (返回 package 的路径)
$ roscd [package_name[/subdir]] (改变目录至 package 根目录或 package 的子目录)
$ roscd log (进入ROS储存log文件的文件夹)
$ rosls [package_name[/subdir]] (列出指定 package 中的目录)
$ cd ~/catkin_ws/src
$ catkin_create_pkg [package_name] [depends_name] (创建一个 catkin package)
$ rospack depends1 [package_name] (查看 package 的第一层依赖)
$ rospack depends [package_name] (查看 package 的所有递归的嵌套依赖)
3. 编译 ROS Package
# In a catkin workspace
$ catkin_make [make_targets] [-DCMAKE_VARIABLES=...] (必须在 catkin 工作空间的顶层使用该命令)
- ~/catkin_ws/build:编译空间的默认位置。
- ~/catkin_ws/src:存储源文件、Python 库、脚本,以及其他的静态文件。
- ~/catkin_ws/devel:存储编译所产生的文件,像库文件、可执行文件以及产生的代码。
4. 理解 ROS Node
- Node(节点)
- 一个 Node 就是一个可执行程序
- 它使用 ROS 可以和其他节点进行通信
- Node 也可以向 Topic 发起发布或者订阅
- Node 也可以提供或者使用一个 Service
- Message(消息):ROS 中订阅或者发布给 Topic 的一种数据类型。
- Topic(话题):Node 可以发布 Message 给一个 Topic,也可以订阅一个 Topic 去接受它的 Message。
- Master(主机):是 ROS 的名字服务器,为 ROS 提供名称服务(比如帮助 Nodes 找到彼此)。
$ roscore (在使用 ROS 之前首先运行的程序)
$ rosnode list (显示了正在运行的 ros node 的信息)
$ rosnode info [node_name] (可以返回特定 node 的信息)
$ rosrun [package_name] [node_name] (运行某 package 的某个 node)
$ rosnode ping [node_name] (测试 node 是否正在运行)
$ rosnode cleanup (用 Ctrl+c 结束 node 进程,在 rosnode list 命令时还会看到该 node,可以用该命令清理)
5. 理解 ROS Topic
$ rosrun rqt_graph rqt_graph (显示现在正在运行的各种 topic 和 node)
$ rostopic echo [topic] (查看发布在指定 topic 上的具体数据)
$ rostopic hz [topic] (报告数据发布的速度)
$ rostopic list (列出现在所有被订阅和发布的 topic)
$ rostopic list -v (显示详细的一系列 topic 的相关信息,包括发布的,订阅的和它们的类型)
$ rostopic type [topic] (返回 topic 发布的 message 类型)
$ rostopic type [topic] | rosmsg show (返回详细的 topic 发布的 message 信息)
$ rostopic pub [topic] [msg_type] [args] (把数据发布到正被广播的 topic 上)
[ex1]$ rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]' ("-1" 表示 rostopic 只发布一条 message 然后退出,双虚线告诉选项剖析器接下来的参数都不是参数选项)
[ex2]$ rostopic pub /turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]' ( "-r 1" 以 1HZ 的速度去发布速度命令给 topic)
$ rosrun rqt_plot rqt_plot(以时间轴的形式显示发布在 topic 上的数据)
6. 理解 ROS service 和 parameter
- ROS service 是 nodes 之间进行通信的 另 一 种 方 式 color{Red}{另一种方式} 另一种方式。
- service 允许 nodes 之间 发送请求 和 接受应答。
$ rosservice list (列出现在所有可使用的 services)
$ rosservice type [service] | rossrv show (查看 service 的具体参数)
$ rosservice call [service] [args] (调用 service)
- rosparam 允许你储存和操作在 ROS parameter server 上的数据
$ rosparam list (列出参数服务器上所有参数)
$ rosparam get [param_name] (获得参数的值)
$ rosparam set [param_name] (改变参数的值)
$ rosparam get / (显示整个参数服务器的内容)
$ rosparam dump [file_name] [namespace] (把所有参数都写入 namespace/file_name)
[ex]$ rosparam dump params.yaml
$ rosparam load [file_name] [namespace] (加载 namespace/file_name 的所有参数)
[ex]$ rosparam load params.yaml copy
7. 理解 rqt_console 和 roslaunch
- 使用 rqt_console 和 rqt_logger_level 来
调
试
color{Red}{调试}
调试
- rqt_console:附着在 ROS logging 框架上去显示 nodes 的输出结果。
- rqt_logger_level:允许我们去改变 nodes 运行时候的信息显示级别(调试,警告,信息和错误)。
$ rosrun rqt_console rqt_console (运行 rqt_console)
$ rosrun rqt_logger_level rqt_logger_level (运行 rqt_logger_level)
-
logger 级别:Fatal > Error > Warn > Info > Debug (Fatal 级别最高)
通过设置 logger 级别,你会得到这个 优 先 级 别 或 更 高 级 别 color{Red}{优先级别或更高级别} 优先级别或更高级别的 message。
比如,通过设置级别为 Warn, 我们会得到所有的 Warn,Error 和 Fatal 的记录消息。 -
使用 roslaunch (launch 文件解析):
$ roslaunch [package] [filename.launch]
example:
$ roscd beginner_tutorials
$ mkdir launch (创建一个 launch 目录)
$ cd launch
创建一个叫做 turtlemimic.launch 的 launch 文件:
<launch>
<!-- 在此处添加注释 -->
<group ns="turtlesim1">
<node pkg="turtlesim" name="sim" type="turtlesim_node"/>
</group>
<group ns="turtlesim2">
<node pkg="turtlesim" name="sim" type="turtlesim_node"/>
</group>
<node pkg="turtlesim" name="mimic" type="mimic">
<remap from="input" to="turtlesim1/turtle1"/>
<remap from="output" to="turtlesim2/turtle1"/>
</node>
</launch>
$ roslaunch beginner_tutorials turtlemimic.launch (用 roslaunch 启动 launch 文件)
$ rostopic pub /turtlesim1/turtle1/cmd_vel geometry_msgs/Twist -r 1 -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, -1.8]' (看到即使命令只是发布给 turtlesim1 但是两个小乌龟都开始运动)
8. 使用 rosed 编辑 ROS 文件
- 通过 package 的名字直接编辑一个 package 中的文件而 不 用 输 入 p a c k a g e 的 整 个 路 径 color{Red}{不用输入 {rm package} 的整个路径} 不用输入 package 的整个路径。
$ rosed [package_name] [filename]
[ex]$ rosed roscpp Logger.msg
9. 创建 msg 和 srv
- msg
- msg 文件是描叙 ROS message 字段的简单 文 本 文 件 color{Red}{文本文件} 文本文件(每行有字段类型和字段名字)。
- msg 文件用来 为 message 产生不同程序语言的源代码。
- srv
- 一个 srv 文件描叙了一种 服 务 color{Red}{服务} 服务。
- 它由两部分组成:请求 和 响应。
- msg 和 srv 使用的
字
段
类
型
color{Red}{字段类型}
字段类型有:
- int8, int16, int32, int64 (plus uint*)
- float32, float64
- string
- time, duration
- variable-length array[] and fixed-length array[C]
- Header header(包含一个时间戳和一个 ROS 中运用很普遍的坐标系信息,在 msg 文件中很常见)
- srv 文件类似于 msg 文件, 不 同 之 处 color{Red}{不同之处} 不同之处是它有两个部分:一个请求 和 一个应答,这两个部分由 ‘- - -’ 线分隔。
- 使用 msg
-
创建一个 msg
$ roscd beginner_tutorials $ mkdir msg $ echo "int64 num" > msg/Num.msg (将 "int64 num" 写入到 msg/Num.msg 文件中) // 让 msg 文件能够转化为 C++,Python 源代码或者其它语言,打开 package.xml 文件,需要添加: // 编译的时候需要 "message_generation" <build_depend>message_generation</build_depend> // 运行的时候需要 "message_runtime" <run_depend>message_runtime</run_depend> //增加 message_generation 依赖到 CMakeLists.txt 中已经存在的 find_package 调用中,这样就可以产生 message //有时候你会发现即使你没有调用有所有依赖的 find_package, 工程编译也没错。 //这是因为 catkin 结合了你的所有工程,所以如果你之前的工程调用过 find_package, 那么你的配置会是一样的。 //忘记调用意味着你的工程在独自编译时会轻易的中断 find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation ) //确认输出 message 运行时的依赖 catkin_package( ... CATKIN_DEPENDS message_runtime ... ) //增加 messages 文件 add_message_files( FILES Num.msg ) //保证 generate_messages() 函数能被调用 generate_messages( DEPENDENCIES std_msgs ) //重新生成 package $ cd ../.. $ catkin_make
- 使用 rosmsg
$ rosmsg show [message type] [ex]$ rosmsg show beginner_tutorials/Num [ex]>> int64 num [ex]$ rosmsg show Num (如果你不记得 msg 在哪个 package 里面,你可以列出 msg 的名字)
-
- 使用 srv
- 创建一个 srv
$ roscd beginner_tutorials $ mkdir -p srv/AddTwoInts.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> //在 CMakeLists.txt 中添加 messager_generatoin 依赖 find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation ) //增加 services 文件 add_service_files( FILES AddTwoInts.srv ) //重新生成 package $ cd ../.. $ catkin_make
- 使用 **rossrv** ``` $ rossrv show <service type> [ex]$ rosmsg show beginner_tutorials/AddTwoInts [ex]>> int64 a int64 b --- int64 sum [ex]$ rosmsg show AddTwoInts (如果你不记得 service 在哪个 package 里面,你可以列出 service 的名字)
- 创建一个 srv
10. 用 C++ 去写简单的发布者和订阅者
- 写一个
发
布
者
N
o
d
e
color{Red}{发布者 {rm Node}}
发布者 Node:创建一个会不断广播 message 的发布者(“talker”) node
src/talker.cpp
- 步骤
- 初始化 ROS 系统
- 广告给 master 我们将要发布 std_msgs/String message 到 chatter topic 上
- 在发布 message 的时候循环以满足 10 次每秒钟 (10Hz)
- 代码内容
```
// 包含了最常用的ROS系统部分所必须的一些头文件
#include “ros/ros.h”
// 包含了 std_msgs package 中的 std_msgs/String message
#include "std_msgs/String.h"
#include <sstream>
// This tutorial demonstrates simple sending of messages over the ROS system.
int main(int argc, char **argv)
{
// 初始化 ROS,指定 node 的名字
ros::init(argc, argv, "talker");
// 创建一个 handle,用来初始化 node
ros::NodeHandle n;
/**
* 让 master 告诉所有的 nodes 听取 chatter 这个 topic,在这个 tpoic 上有我们将要发布数据。
* 第二个参数是发布队列的大小.这样的话如果我们发布的太快,在开始丢弃之前的 message 前,它会最大缓冲是 1000 个 messages。
* NodeHandle::advertise() 返回一个 ros::Publisher 的对象,它有两个作用:
* (1)它允许你发布 message 到它创建的 topic 上的 publish();
* (2)当它超出范围时,会自动解除广播。
**/
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
// ros::Rate 对象会指定一个你想循环的频率
// 它会跟踪距离上次调用 Rate::sleep(), 有多长时间了,并且休眠正确长度的时间
ros::Rate loop_rate(10);
int count = 0;
// 一旦 ros::ok() 返回错误,所有的 ROS 调用都会失败
while (ros::ok())
{
// std::stringstream convert to std_msgs::String
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());
// 向任何一个连接上的人广播这个 message
chatter_pub.publish(msg);
/*
* 对于这个程序调用 ros::splinOnce() 不是必要的,因为我们不会接受到任何回叫信号。
* 然而,如果你打算为这个应用添加一个订阅,并且没有调用 ros::splinOnce(), 你绝不会得到回叫信号,所以还是添加的好。
*/
ros::spinOnce();
// 使用 ros::Rate 对象去空耗掉剩下的时间以满足10hz的发布速度
loop_rate.sleep();
++count;
}
return 0;
}
- 写一个$color{Red}{订阅者 {rm Node}}$
**src/listener.cpp**
> - 步骤
> - 初始化 ROS 系统
> - 订阅 chatter topic
> - Spin,等待 message 到来
> - 当一个 message 到来时,chatterCallback() 函数被调用
> - 代码内容
```
#include "ros/ros.h"
#include "std_msgs/String.h"
// This tutorial demonstrates simple receipt of messages over the ROS system.
/**
* 当一个新的 message 抵达 chatter topic 时这个回调函数会被调用。
* 这个 message 以 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,指定 node 的名字
ros::init(argc, argv, "listener");
// 创建一个 handle,用来初始化 node
ros::NodeHandle n;
/**
* 在master启动的前提下订阅chatter topic,ROS会调用chatter Callback()函数只要一个新的message到达时。
* 第二个参数是队列的大小,假设我们没有足够的能力去使发送message足够的快。
* 这样的话,如果队列达到 1000 个 messages,随着新的 message 的到来,我们会开始丢掉旧的message。
**/
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
// ros::spin() 进入了一个循环,尽可能快地进行 message 回调
// ros::spin()会退出一旦ros::ok()返回错误
ros::spin();
return 0;
}
```
- **CMakeLists.txt**
>
```
cmake_minimum_required(VERSION 2.8.3)
project(beginner_tutorials)
## Add support for C++11, supported in ROS Kinetic and newer
# add_definitions(-std=c++11)
## Find catkin macros and libraries
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)
## 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
)
## Declare a catkin package
catkin_package(
CATKIN_DEPENDS message_runtime
)
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)
```
- 运行 nodes
$ roscd beginner_tutorials
$ cd …/…
$ catkin_make
$ roscore
$ rosrun beginner_tutorials talker (在新的终端里输入)
$ rosrun beginner_tutorials listener(在新的终端里输入)
### 11. 用 C++ 去写简单的 service 和 client
- 写一个 Service Node
**src/add_two_ints_server.cpp**:
>
```
#include "ros/ros.h"
// 由之前创建的 srv/AddTwoInts.srv 产生的头文件
#include "beginner_tutorials/AddTwoInts.h"
// 这个函数用来使两个整数的相加,它吸收在srv文件中定义的 request 和 response 类型
// 返回一个布尔量
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;
// 这里 service 在 ROS 上被创建和广播
ros::ServiceServer service = n.advertiseService("add_two_ints", add);
ROS_INFO("Ready to add two ints.");
ros::spin();
return 0;
}
```
- 写一个 Client Node
**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;
// 这里为 add_two_ints service 创建了一个 client,
// ros::ServiceClient 对象后面被用来调用 service 。
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]);
/**
* 这里实际上调用了 service,因为 service 的调用一直处于被阻塞状态,一旦调用结束它就会返回。
* 如果 service 调用成功,call() 函数会返回真并且 srv.response 的值会有效;
* 如果调用没有成功,call() 函数会返回错误并且 srv.response 的值会无效。
**/
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;
}
```
-
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.3) project(beginner_tutorials) ## Add support for C++11, supported in ROS Kinetic and newer # add_definitions(-std=c++11) ## Find catkin macros and libraries find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation ) ## System dependencies are found with CMake's conventions # find_package(Boost REQUIRED COMPONENTS system) ## 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 ) ## Declare a catkin package catkin_package( CATKIN_DEPENDS message_runtime ) 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_generate_messages_cpp) 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_generate_messages_cpp)
-
运行 nodes
$ roscd beginner_tutorials $ cd ../.. $ catkin_make $ roscore $ rosrun beginner_tutorials add_two_ints_server (在新的终端里输入) $ rosrun beginner_tutorials add_two_ints_client 3 4 (在新的终端里输入)
12. 记录和重放数据
- 记录所有发布的 topics
$ rosbag record -a (-a 暗示所有发布的 topics 汇总在一个 bag 文件中)
- 校验和回放 bag 文件
$ rosbag info [bagfile name] (检查 bag 的内容,查看其相关信息) $ rosbag play [bagfile name] (重放 bag 文件) $ rosbag play -r 2 [bagfile name] (将发布数据的速度改为原先的 2 倍) $ rosbag record -O subset [指定的 topic, 比如 /turtle1/cmd_vel/turtle1/pose]
13. 编译指定 package
$ catkin_make --pkg [package A] [package B]
14. 删除指定 package 的编译文件
可以直接删除 [dir-to-catkin_ws] 路径下的 build 和 devel 文件夹,或者删除 build 文件夹下的对应 package 的文件夹,再删掉 devel 文件夹,后者速度快些。【参考:Is there a way to clean a certain package with catkin_make?】
最后
以上就是欢呼帆布鞋为你收集整理的ROS Indigo 入门速查笔记的全部内容,希望文章能够帮你解决ROS Indigo 入门速查笔记所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复