PDF下载地址:node
连接:https://pan.baidu.com/s/1l_FAbn_g04q-Z0lKSxx8tw
提取码:8lbp git
注:英文原文为《A Gentle Introduction to ROS》 【美】Jason M. O'Kane著shell
1、绪论编程
2、入门概述bash
1. 安装:参考 http://wiki.ros.org/cn服务器
(1)sudo rosdep init 初始化rosdep,rosdep用于检查和安装软件包的依赖网络
(2)rosdep update 初始化rosdep,在根目录下保存一些文件,文件夹名为.rosapp
(3)source /opt/ros/ros版本/setup.bashless
(3)测试ROS是否正确安装编程语言
注:三个终端分别执行指令
2. 经常使用术语和命令
(1)ROS功能包/软件包:一组用于实现特定功能的相关文件的集合,包括可执行文件和其余支持文件 //任何能找到且包含package.xml文件的目录
注:使用catkin编译生成的可执行文件放在外部标准目录devel中(源码外编译)
(2)节点node:ROS程序的运行实例 running instance
(3)rosrun命令:启动ROS节点 rosrun 功能包名 可执行文件名 //节点名不必定与可执行文件名相同,可使用 __name:=节点名 显式设置节点名称
注:节点名称必须惟一,不可多个节点拥有相同名称
(4)消息传递机制:节点管理器负责确保发布节点和订阅节点能找到对方,随后消息从发布节点直接传递到订阅节点,不通过节点管理器转交
注:节点只管发,无论收,有助于减小节点之间的耦合度;话题可共享,话题和消息的通讯机制是多对多的;服务是一对一的通讯机制
(5)rosmsg show 消息类型名 //输出消息类型的详细信息
(6)rostopic pub 话题名 消息类型 消息内容 //命令行手动发布消息
注:消息内容能够按照rosmsg show命令的显示结果进行输入,也能够以YAML字典的形式输入(显式指明结构域中变量名和值的映射关系)
(7)每一个消息类型均属于一个特定的包,如turtlesim/Color属于turtlesim包 //消息类型斜杠/前的是包名,斜杠/后是类型名
注:把包名包含在消息类型中的目的:
3、编写ROS程序
1. catkin编译系统试图一次性编译同一个工做区中的全部功能包
2. 建立功能包:catkin_create_pkg 包名 //包名只容许使用小写字母、数字和下划线,且首字符必须为字母
3. 清单文件package.xml中声明的依赖库并不会在编译过程当中进行检查,可是会在将包发布给他人时,他人会由于没有安装依赖库而编译报错
4. CMakeLists.txt中的${catkin_LIBRARIES}变量由find_package(catkin REQUIRED COMPONENTS ...)语句定义
5. source devel/setup.bash //专门为当前的工做区进行环境变量设置
6. 每一个话题都有一个消息类型,而每一个消息类型都有相应的C++头文件 //包含消息类型头文件 #include<包名/类型名.h> 如#include<geometry_msgs/Twist.h>
注:头文件定义了一个与消息类型对应的C++类,且该类定义在以包名命名的域名空间中,如geometry_msgs::Twist类
7. ros::NodeHandle类维护一个引用计数,仅在第一个NodeHandle对象建立时才会在节点管理器注册新的节点 //使用标准的roscpp接口,在单个程序中没法运行多个节点
8. 建立发布者ros::Publisher属于耗时操做,应该每一个话题建立一个发布者,在程序执行过程当中一直使用相应发布者 //发布者建立不要放在循环内,避免为每条消息生成新的发布者
9. ros::ok()返回false条件:
10. 订阅者回调函数:void function_name(const package_name::type_name &msg){ ... }
11. 显式调用 ros::spin()或ros::spinonce()让ROS执行回调函数
4、日志消息 //ROS使用log4cxx库实现日志功能
1. ROS日志系统的核心思想:使程序生成一些简短的文本字符流,即日志消息
2. 严重级别(递增):DEBUG、INFO、WARN、ERROR、FATAL
3. 产生日志消息的基本C++宏
注:日志系统是面向行的,调用任意宏会生成完整的一行日志消息 //无需使用std::endl
4. 日志消息的输出
(1)控制台
(2)/rosout 话题:消息类型为rosgraph_msgs/Log
注:rosout即表示话题,也表示节点
(3)日志文件:做为/rosout话题回调函数的一部分,由rosout节点生成
检查日志文件大小:rosclean check
删除日志文件:rosclean purge
5. 设置日志级别
(1)经过命令行设置:rosservice call /node-name /set_logger_level ros.包名 level // level参数包括DEBUG、INFO、WARN、ERROR、FATAL
注:参数ros.包名指按期望配置的日志记录器logger名称
(2)经过图形界面设置:rqt_logger_level
(3)经过C++代码设置:调用ROS实现日志功能的log4cxx提供的接口 #include<log4cxx/logger.h>
5、计算图源命名
1. 计算图源graph resource:节点、话题、服务和参数的统称,由短字符串表示的计算图源名称进行标识
2. 全局名称:/turtle1/cmd_vel //优势:任何地方均可以使用;缺点:须要完整列出其所属的命名空间
3. 相对名称 //利用ROS提供的默认命名空间
(1)典型特征:缺乏全局名称带有的前斜杠"/"
(2)解析相对名称:将当前的默认命名空间名称加在相对名称以前,生成全局名称,如 /turtle1 + cmd_vel => /turtle1/cmd_vel
(3)设置默认命名空间:单独为每一个节点设置 //不设置,则使用全局命名空间"/"做为默认命名空间
优势:避免在移植和整合来自不一样来源的节点时发生名称冲突
4. 私有名称 //用于节点内部仅与本节点有关的资源,如参数
(1)典型特征:以一个波浪字符(~)开始
(2)与相对名称一致,不能彻底肯定自身所在命名空间,须要利用ROS客户端库进行名称解析
(3)不使用当前的默认命名空间,而采用节点名称做为命名空间,如 /sim1/pubvel + ~max_vel => /sim1/pubvel/max_vel
(4)私有名称可用于管理节点的服务,话题不能命名为私有名称
注:私有名称的关键字"private"仅代表不使用所在的命名空间,其余节点能够经过私有名称解析后的全局名称进行访问 //仅在命名空间层面上有意义,注意与其余编程语言的不一样
5. 匿名名称:非用户指定的无语义信息的名字
(1)通常用于为节点命名,使节点的命名保存惟一性
(2)调用ros::init方法时请求一个自动分配的惟一名称
注:ros::init使用处理器时间在节点的基本名称后追加文本,保证名字的惟一性
6、启动文件
1. 目的:利用启动文件一次性配置和运行多个节点
2. 执行启动文件:roslaunch 包名 启动文件名 //若是没有运行roscore,roslaunch会自动启动roscore
(1)若是启动文件不属于任何功能包,则能够直接以启动文件路径启动 roslaunch + 启动文件路径
(2)启动文件内的节点几乎是同一时刻启动,没法肯定启动顺序,所以节点之间应尽可能保持独立
(3)添加-v选项能够输出详细信息:roslaunch -v 包名 启动文件名
(4)查找启动文件时,roslaunch工具会同时搜索每一个功能包目录的子目录
3. 启动文件基本元素
(1)根元素:<launch> ... </launch>
(2)启动节点:
<node
pkg=包名
type=可执行文件名
name=节点名
/>
(3)请求复位:respawn="true" //当节点中止时,roslaunch会从新启动该节点,可用于应对软件崩溃、硬件故障等引发的节点停止
(4)必要节点:required="true" //当必要节点停止时,roslaunch会终止全部其余活跃节点,并退出;与respawn做用相互矛盾,不能同时配置
(5)roslaunch全部节点共享一个终端,针对依赖控制台输入的节点来讲,须要维护独立的终端:使用启动前缀属性 launch-prefix="命令行前缀"
3. 在命名空间内启动节点 //经过配置节点元素的ns属性,压入命名空间
(1)尽管两个节点相对名称相同,可是因为命名空间不一样,因此两个节点相互独立
(2)因为话题名称定义时采用的也是相对名称,因此话题也分别位于独立的命名空间
4. 名称重映射remapping names //从更精细的层面控制节点名称的修改
(1)基于替换的思想:每一个重映射包含一个原始名称和一个新名称,每当节点使用原始名称时,ROS客户端库会将它自动替换为新名称
(2)建立重映射
注:重映射元素也能够做为节点的子元素:<node ...> <remap from="original-name" to "new-name"/> </node> 此时只应用于所在节点
注:
5. 其余元素
(1)启动文件的嵌套:include元素
(2)启动参数argument:便于配置启动文件,相似可执行程序中的局部变量(仅在声明的当前启动文件内有效,不可被包含的启动文件继承)
注:在ROS中,parameter和argument是有区别的
(3)建立组group:大型启动文件内管理节点的快捷方式
注:仅有0和1为合法取值,且不能使用布尔运算;也能够不使用组元素,单独为每一个节点设置ns、if和unless
7、参数parameter //配置节点信息的集中式方法
1. 主要思想:使用集中的参数服务器维护一个变量集的值(字典),适用于不会随时间频繁变动的信息
2. 经过命令行获取参数
(1)rosparam list //查看参数列表,输出 /rosdistro 等全局计算图源的名称字符串
(2)rosparam get parameter_name //查询参数,如 rosparam get /rosdistro 获得ROS版本
(3)rosparam get namespace //检索给定命名空间每一个参数的值,如 rosparam get / 查询全局命名空间/
(4)rosparam set parameter_name parameter_value //设置参数,修改已有参数的值或建立新参数
(5)rosparam set namespace values //设置同一命名空间的多个参数,其中值values要以YAML字典的形式给出参数和值的对应关系
(6)建立和加载参数文件(YAML形式) //可用于场景复现
注:命名空间参数可选,默认为全局命名空间/
注:
3. 使用C++接口获取参数 //参数名能够是全局的、相对的或者私有的
void ros::param::set(parameter_name, input_value);
bool ros::param::get(parameter_name, output_value); //读取成功返回true,不然代表参数还未指定值
注:在命令行中实现私有参数赋值 rosrun agitr pubvel_with_max _max_vel:=1 //参数max_vel前面添加下划线_前缀 _param-name:=param-value
4. 在启动文件中设置参数
(1)<param name="param-name" value="param-value"/> //设置参数,参数名是相对名称
(2)<node ...> <param name="param-name" value="param-value"/> </node> //在节点元素内包含param元素,不管是否以~或/开头,参数均为节点私有参数
(3)<rosparam command="load" file="path-to-param-file"/> //一次性从文件中加载多个参数,等价于rosparam load
注:一般采用 file="$(find package-name)/param-file" 指定文件路径
8、服务service
1. 与话题消息的区别
2. 执行过程:客户端节点发送请求数据到服务器节点,而且等待回应;服务器节点收到请求后,执行相应活动,随后发送响应数据给客户端节点;
3. 与话题内容由消息数据类型肯定相似,服务的内容也由服务数据类型决定
4. 从命令行查看和调用服务
(1)rosservice list //列出全部服务
(2)服务通常能够划分为两类:
5. rosnode info node-name //查看某个节点的服务类型
6. rosservice node service-name //查找提供服务的节点(反向查询)
7. rosservice info service-name //肯定服务的数据类型,一般也是由包名和类型名组成“包名/类型名”,如turtlesim/Spawn
8. rossrv show 服务数据类型名 //获取服务数据类型的详细信息(一系列数据域),注意rosservice和rossrv的区别
注:
9. rosservice call service-name request-content //调用服务,提供请求域的全部值,如rosservice call /spawn 3 3 0 Mikey 在位置(3, 3)处建立一个名为"Mikey"的新海龟,朝向为0
注:
10. 客户端程序
(1)声明请求和响应类型:#include<turtlesim/Spawn.h> //包含头文件,定义turtlesim::Spawn类(服务数据类型)
(2)建立客户端对象:ros::ServiceClient client = node_handle.serviceClient<service_type>(service_name) //服务名称通常应当为相对名称,如"spawn"
注:与话题发布者不一样,无需缓冲队列,会阻塞等待直至服务调用完成
(3)建立请求和响应对象 //上述头文件中定义了请求和响应的类,经过包名和服务类型引用,如turtlesim::Spawn::
注:服务类型的头文件中还定义了一个单独类package_name::service_type,同时拥有Request和Response做为数据成员;能够定义单独对象package_name::service_type srv,而不使用独立的Request和Response对象
(4)调用服务:bool success = service_client.call(request, response)
注:
11. 服务器程序
(1)编写回调函数 bool function_name(package_name::service_type::Request &req, package_name::service_type::Response &resp)
注:本例中请求和响应的数据类型均为std_srvs/Empty(空字符串),无需进行数据处理
(2)与话题订阅者相似,须要建立服务器对象ros::ServiceServer server=node_handle.advertiseService(service_name, pointer_to_callback_function);
注:本例使用ros::spinOnce()而非ros::spin(),缘由在于没有服务调用时还须要执行其余工做,即发布速度指令 //与第三章 表3.5 进行对比
(3)解决ros::spinOnce() + sleep()引发的延迟问题
9、消息录制与回放
1. rosbag:将发布在一个或多个话题上的消息录制到一个包文件中,可用于过后回放
注:术语包文件bag files指用于存储带时间戳的ROS消息的特殊文件格式
2. 命令行工具
(1)录制包文件:rosbag record -O filename.bag topic-names //不指定文件名时,rosbag基于当前的日期和时间自动生成文件名;会建立新节点 /record_...
(2)回放包文件:rosbag play filename.bag //保持与原始发布相同的顺序和时间间隔
注:尽可能避免系统中rosbag和“真实”节点向同一个话题发布消息
(3)检查文件包:rosbag info filename.bag //提供包文件的丰富信息
3. rosbag功能包
(1)rosrun rosbag record -O filename.bag topic-names;rosrun rosbag play filename.bag //利用record和play可执行文件
(2)在启动文件中使用包文件
注:须要提供参数
第十章 总结
1. 在网络环境中运行ROS:分布式机器人控制模式
(1)网络层配置:确保计算机之间可以互相通讯
(2)ROS层配置:确保全部节点都能与节点管理器通讯
2. 编写更规范的程序,如使用ros::Timer的回调函数替代ros::Rate对象
3. 使用rviz是数据可视化:订阅用户话题以显示消息
4. 建立消息和服务类型
5. 使用tf工具来管理多个坐标系:帮助节点完成坐标转换
6. 使用Gazebo仿真:高保真的机器人仿真器