文档维护:Arvin
网页部署:Arvin
▶
写在前面 :本文旨在记录学习ROS过程中的一些重要知识概念和遇到的错误问题。主要参考赵虚左老师的ROS课程(第一个参考链接),由于赵老师用的noetic版本,而我用的是melodic版本,细节上可能会有所差异。
机器人系统仿真
常用组件
1.URDF :
URDF 是 Unified Robot Description Format 的首字母缩写,直译为统一(标准化)机器人描述格式 ,可以以一种 XML 的方式描述机器人的部分结构,比如底盘、摄像头、激光雷达、机械臂以及不同关节的自由度…,该文件可以被 C++ 内置的解释器转换成可视化的机器人模型,是 ROS 中实现机器人仿真的重要组件。
2.Xacro :
Xacro 是 XML Macros 的缩写,Xacro 是一种 XML 宏语言,是可编程的 XML。
Xacro 可以声明变量,可以通过数学运算求解,使用流程控制控制执行顺序,还可以通过类似函数的实现,封装固定的逻辑,将逻辑中需要的可变的数据以参数的方式暴露出去,从而提高代码复用率以及程序的安全性。
3.Rviz :
RViz 是 ROS Visualization Tool 的首字母缩写,直译为ROS的三维可视化工具 。它的主要目的是以三维方式显示ROS消息,可以将 数据进行可视化表达。例如:可以显示机器人模型,可以无需编程就能表达激光测距仪(LRF)传感器中的传感 器到障碍物的距离,RealSense、Kinect或Xtion等三维距离传感器的点云数据(PCD, Point Cloud Data),从相机获取的图像值等。
4.Gazebo :
Gazebo是一款3D动态模拟器,用于显示机器人模型并创建仿真环境,能够在复杂的室内和室外环境中准确有效地模拟机器人。与游戏引擎提供高保真度的视觉模拟类似,Gazebo提供高保真度的物理模拟,其提供一整套传感器模型,以及对用户和程序非常友好的交互方式。
总的来说:
URDF 是用于描述机器人模型的 xml 文件,可以使用不同的标签具代表不同含义,URDF 编写机器人模型代码冗余,xacro 可以优化 URDF 实现,代码实现更为精简、高效、易读。容易混淆的是Rviz与Gazebo,在此我们着重比较以下二者的区别:
rviz是三维可视化工具 ,强调把已有的数据可视化显示;
gazebo是三维物理仿真平台 ,强调的是创建一个虚拟的仿真环境。
rviz需要已有数据 。
rviz提供了很多插件,这些插件可以显示图像、模型、路径等信息,但是前提都是这些数据已经以话题、参数的形式发布,rviz做的事情就是订阅这些数据,并完成可视化的渲染,让开发者更容易理解数据的意义。
gazebo不是显示工具,强调的是仿真,它不需要数据,而是创造数据 。
导航
ROS官方导航功能包集:
关键技术:
全局地图
自身定位
路径规划
运动控制
环境感知
下面我们使用ROS官方的功能包,在仿真环境下完整走一边流程,其中仿真环境搭建参考链接:http://www.autolabor.com.cn/book/ROSTutorials/di-6-zhang-ji-qi-ren-xi-tong-fang-zhen.html
搭建好的环境如图所示:
SLAM建图
SLAM算法有很多,这里选择gmapping。
安装gmapping
1 sudo apt install ros-melodic-gmapping
编写gmapping节点相关launch文件
launch文件编写可以参考 github 的演示 launch文件:https://github.com/ros-perception/slam_gmapping/blob/melodic-devel/gmapping/launch/slam_gmapping_pr2.launch
复制并修改如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <launch > <param name ="use_sim_time" value ="true" /> <node pkg ="gmapping" type ="slam_gmapping" name ="slam_gmapping" output ="screen" > <remap from ="scan" to ="scan" /> <param name ="base_frame" value ="base_footprint" /> <param name ="odom_frame" value ="odom" /> <param name ="map_update_interval" value ="5.0" /> <param name ="maxUrange" value ="16.0" /> <param name ="sigma" value ="0.05" /> <param name ="kernelSize" value ="1" /> <param name ="lstep" value ="0.05" /> <param name ="astep" value ="0.05" /> <param name ="iterations" value ="5" /> <param name ="lsigma" value ="0.075" /> <param name ="ogain" value ="3.0" /> <param name ="lskip" value ="0" /> <param name ="srr" value ="0.1" /> <param name ="srt" value ="0.2" /> <param name ="str" value ="0.1" /> <param name ="stt" value ="0.2" /> <param name ="linearUpdate" value ="1.0" /> <param name ="angularUpdate" value ="0.5" /> <param name ="temporalUpdate" value ="3.0" /> <param name ="resampleThreshold" value ="0.5" /> <param name ="particles" value ="30" /> <param name ="xmin" value ="-50.0" /> <param name ="ymin" value ="-50.0" /> <param name ="xmax" value ="50.0" /> <param name ="ymax" value ="50.0" /> <param name ="delta" value ="0.05" /> <param name ="llsamplerange" value ="0.01" /> <param name ="llsamplestep" value ="0.01" /> <param name ="lasamplerange" value ="0.005" /> <param name ="lasamplestep" value ="0.005" /> </node > <node pkg ="joint_state_publisher" name ="joint_state_publisher" type ="joint_state_publisher" /> <node pkg ="robot_state_publisher" name ="robot_state_publisher" type ="robot_state_publisher" /> <node pkg ="rviz" type ="rviz" name ="rviz" /> </launch >
执行
1.先启动 Gazebo 仿真环境(此过程略)
2.然后再启动地图绘制的 launch 文件:
3.启动键盘键盘控制节点,用于控制机器人运动建图
1 rosrun teleop_twist_keyboard teleop_twist_keyboard.py
4.在 rviz 中添加组件,显示栅格地图 最后,就可以通过键盘控制gazebo中的机器人运动,同时,在rviz中可以显示gmapping发布的栅格地图数据了,下一步,还需要将地图单独保存。
读写地图
ROS中提供关于地图数据的功能包为map-server
安装move_base
1 sudo apt install ros-melodic-map-server
编写launch文件保存地图
1 2 3 4 <launch > <arg name ="filename" value ="$(find mycar_nav)/map/nav" /> <node name ="map_save" pkg ="map_server" type ="map_saver" args ="-f $(arg filename)" /> </launch >
在前面的基础上(保证启动了仿真环境,键盘控制节点与SLAM节点)
通过键盘控制机器人运动并绘图
启动上述编写好的launch保存地图
在指定的路径下会生成两个文件,xxx.pgm
和xxx.yaml
。第一个文件就是一个图片,第二个文件保存的是地图元数据信息,用于描述图片,内容格式如下:
1 2 3 4 5 6 image: ./nav.pgm resolution: 0.050000 origin: [-50.000000 , -50.000000 , 0.000000 ]negate: 0 occupied_thresh: 0.65 free_thresh: 0.196
目前只需要关注路径是否正确即可。
读取地图
通过 map_server 的 map_server 节点可以读取栅格地图数据,编写 launch 文件如下:
1 2 3 4 5 6 <launch > <arg name ="map" default ="nav.yaml" /> <node name ="map_server" pkg ="map_server" type ="map_server" args ="$(find mycar_nav)/map/$(arg map)" /> </launch >
在 rviz 中使用 map 组件可以显示栅格地图:
定位
所谓定位就是推算机器人自身在全局地图中的位置。在ROS的导航功能包集navigation中提供了 amcl 功能包,用于实现导航中的机器人定位。
安装
1 sudo apt install ros-melodic-navigation
编写acml相关launch文件
关于launch文件的实现,在amcl功能包下的example目录已经给出了示例,可以作为参考,具体实现:
该目录下会列出两个文件: amcl_diff.launch 和 amcl_omni.launch 文件,前者适用于差分移动机器人,后者适用于全向移动机器人,可以按需选择,此处参考前者,新建 launch 文件,复制 amcl_diff.launch 文件内容并修改如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <launch > <node pkg ="amcl" type ="amcl" name ="amcl" output ="screen" > <param name ="odom_model_type" value ="diff" /> <param name ="odom_alpha5" value ="0.1" /> <param name ="transform_tolerance" value ="0.2" /> <param name ="gui_publish_rate" value ="10.0" /> <param name ="laser_max_beams" value ="30" /> <param name ="min_particles" value ="500" /> <param name ="max_particles" value ="5000" /> <param name ="kld_err" value ="0.05" /> <param name ="kld_z" value ="0.99" /> <param name ="odom_alpha1" value ="0.2" /> <param name ="odom_alpha2" value ="0.2" /> <param name ="odom_alpha3" value ="0.8" /> <param name ="odom_alpha4" value ="0.2" /> <param name ="laser_z_hit" value ="0.5" /> <param name ="laser_z_short" value ="0.05" /> <param name ="laser_z_max" value ="0.05" /> <param name ="laser_z_rand" value ="0.5" /> <param name ="laser_sigma_hit" value ="0.2" /> <param name ="laser_lambda_short" value ="0.1" /> <param name ="laser_lambda_short" value ="0.1" /> <param name ="laser_model_type" value ="likelihood_field" /> <param name ="laser_likelihood_max_dist" value ="2.0" /> <param name ="update_min_d" value ="0.2" /> <param name ="update_min_a" value ="0.5" /> <param name ="odom_frame_id" value ="odom" /> <param name ="base_frame_id" value ="base_footprint" /> <param name ="global_frame_id" value ="map" /> <param name ="resample_interval" value ="1" /> <param name ="transform_tolerance" value ="0.1" /> <param name ="recovery_alpha_slow" value ="0.0" /> <param name ="recovery_alpha_fast" value ="0.0" /> </node > </launch >
编写集成launch文件
amcl节点是不可以单独运行的,运行 amcl 节点之前,需要先加载全局地图,然后启动 rviz 显示定位结果,上述节点可以集成进launch文件,内容示例如下:
1 2 3 4 5 6 7 8 9 10 <launch > <arg name ="map" default ="nav.yaml" /> <node name ="map_server" pkg ="map_server" type ="map_server" args ="$(find mycar_nav)/map/$(arg map)" /> <include file ="$(find mycar_nav)/launch/amcl.launch" /> <node pkg ="rviz" type ="rviz" name ="rviz" /> </launch >
执行
1.先启动 Gazebo 仿真环境(此过程略);
2.启动键盘控制节点:
1 rosrun teleop_twist_keyboard teleop_twist_keyboard.py
3.启动上一步中集成地图服务、amcl 与 rviz 的 launch 文件;
4.在启动的 rviz 中,添加RobotModel、Map组件,分别显示机器人模型与地图,添加 posearray 插件,设置topic为particlecloud来显示 amcl 预估的当前机器人的位姿,箭头越是密集,说明当前机器人处于此位置的概率越高;
5.通过键盘控制机器人运动,会发现 posearray 也随之而改变。
路径规划
ROS的导航功能包集navigation中提供了 move_base 功能包。机器人导航(尤其是路径规划模块)是依赖于地图的,SLAM构建的地图是静态地图,静态地图无法直接应用于导航,其基础之上需要添加一些辅助信息的地图,比如时时获取的障碍物数据,基于静态地图添加的膨胀区等数据。我们可以通过move_base功能包生成代价地图。
代价地图有两张:global_costmap(全局代价地图) 和 local_costmap(本地代价地图),前者用于全局路径规划,后者用于本地路径规划。
两张代价地图都可以多层叠加,一般有以下层级:
Static Map Layer:静态地图层,SLAM构建的静态地图。
Obstacle Map Layer:障碍地图层,传感器感知的障碍物信息。
Inflation Layer:膨胀层,在以上两层地图上进行膨胀(向外扩张),以避免机器人的外壳会撞上障碍物。
Other Layers:自定义costmap。
多个layer可以按需自由搭配。
安装
1 sudo apt install ros-melodic-navigation
调用
1 2 3 4 5 6 7 8 9 10 11 <launch > <node pkg ="move_base" type ="move_base" respawn ="false" name ="move_base" output ="screen" clear_params ="true" > <rosparam file ="$(find 功能包)/param/costmap_common_params.yaml" command ="load" ns ="global_costmap" /> <rosparam file ="$(find 功能包)/param/costmap_common_params.yaml" command ="load" ns ="local_costmap" /> <rosparam file ="$(find 功能包)/param/local_costmap_params.yaml" command ="load" /> <rosparam file ="$(find 功能包)/param/global_costmap_params.yaml" command ="load" /> <rosparam file ="$(find 功能包)/param/base_local_planner_params.yaml" command ="load" /> </node > </launch >
启动了 move_base 功能包下的 move_base 节点,respawn 为 false,意味着该节点关闭后,不会被重启;clear_params 为 true,意味着每次启动该节点都要清空私有参数然后重新载入;通过 rosparam 会载入若干 yaml 文件用于配置参数。
配置文件
关于配置文件的编写,可以参考一些成熟的机器人的路径规划实现,比如: turtlebot3,github链接:https://github.com/ROBOTIS-GIT/turtlebot3/tree/master/turtlebot3_navigation/param
在功能包下新建 param 目录,复制下载的文件到此目录: costmap_common_params_burger.yaml、local_costmap_params.yaml、global_costmap_params.yaml、base_local_planner_params.yaml,并将costmap_common_params_burger.yaml 重命名为:costmap_common_params.yaml
costmap_common_params.yaml
该文件是move_base 在全局路径规划与本地路径规划时调用的通用参数,包括:机器人的尺寸、距离障碍物的安全距离、传感器信息等。配置参考如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 robot_radius: 0.12 obstacle_range: 3.0 raytrace_range: 3.5 inflation_radius: 0.2 cost_scaling_factor: 3.0 map_type: costmap observation_sources: scan scan: {sensor_frame: laser , data_type: LaserScan , topic: scan , marking: true , clearing: true }
global_costmap_params.yaml
该文件用于全局代价地图参数设置:
1 2 3 4 5 6 7 8 9 10 global_costmap: global_frame: map robot_base_frame: base_footprint update_frequency: 1.0 publish_frequency: 1.0 transform_tolerance: 0.5 static_map: true
local_costmap_params.yaml
该文件用于局部代价地图参数设置:
1 2 3 4 5 6 7 8 9 10 11 12 13 local_costmap: global_frame: odom robot_base_frame: base_footprint update_frequency: 10.0 publish_frequency: 10.0 transform_tolerance: 0.5 static_map: false rolling_window: true width: 3 height: 3 resolution: 0.05
base_local_planner_params
基本的局部规划器参数配置,这个配置文件设定了机器人的最大和最小速度限制值,也设定了加速度的阈值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 TrajectoryPlannerROS: max_vel_x: 0.5 min_vel_x: 0.1 max_vel_theta: 1.0 min_vel_theta: -1.0 min_in_place_vel_theta: 1.0 acc_lim_x: 1.0 acc_lim_y: 0.0 acc_lim_theta: 0.6 xy_goal_tolerance: 0.10 yaw_goal_tolerance: 0.05 holonomic_robot: false sim_time: 0.8 vx_samples: 18 vtheta_samples: 20 sim_granularity: 0.05
集成launch文件
如果要实现导航,需要集成地图服务、amcl 、move_base 与 Rviz 等,集成示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <launch > <arg name ="map" default ="nav.yaml" /> <node name ="map_server" pkg ="map_server" type ="map_server" args ="$(find mycar_nav)/map/$(arg map)" /> <include file ="$(find mycar_nav)/launch/amcl.launch" /> <include file ="$(find mycar_nav)/launch/path.launch" /> <node pkg ="rviz" type ="rviz" name ="rviz" args ="-d $(find mycar_nav)/rviz/nav.rviz" /> </launch >
执行
1.先启动 Gazebo 仿真环境(此过程略);
2.启动导航相关的 launch 文件;
3.添加Rviz组件(参考演示结果),可以将配置数据保存,后期直接调用;
全局代价地图与本地代价地图组件配置如下:
全局路径规划与本地路径规划组件配置如下:
4.通过Rviz工具栏的 2D Nav Goal设置目的地实现导航。