ROS Indigo 入门速查笔记

本系列文章由 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_consolerqt_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}{服务}
    • 它由两部分组成:请求响应
  • msgsrv 使用的 字 段 类 型 \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 的名字)	  
    

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?

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值