ROS Indigo 入门速查笔记

    xiaoxiao2021-03-25  121

    本系列文章由 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, float64stringtime, durationvariable-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?】

    转载请注明原文地址: https://ju.6miu.com/read-20990.html

    最新回复(0)