9. turtlebot仿真(利用karto)
参考链接
https://blog.csdn.net/qq_40078576/article/details/104773668
https://blog.csdn.net/lingchen2348/article/details/79503970
9.1. 安装Gazebo仿真软件
安装ros时已经安装。
9.2. 下载Gazobo的模型包
不需要再下载模型包了,turtlebot包会加载出模型。
9.3. 安装slam建图包
turtlebot3支持gmapping、cartographer、hector、karto、frontier_exploration。
9.3.1. karto安装
sudo apt-get install ros-melodic-slam-karto
9.3.2. 安装cartographer_turtlebot(待完善TODO)
注意这里不是cartographer_ros,参考链接https://www.ncnynl.com/archives/201801/2230.html
9.4. 安装turtlebot相关包
sudo apt-get install ros-melodic-turtlebot-*
9.5. 加载环境
roslaunch turtlebot3_gazebo turtlebot3_world.launch
报错:‘TURTLEBOT3_MODEL’ is not set。表示TURTLEBOT3_MODEL没有设置, 需要给它指定[burger, waffle, waffle_pi]中的一个, 我们随便指定一个:export TURTLEBOT3_MODEL=burger
(可以写入.bashrc文件),重新执行命令。
9.6. 启动键盘遥控节点
可以遥控小车行走。新建终端,
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
9.7. 建图
这里选择了karto。新建终端,
roslaunch turtlebot3_slam turtlebot3_slam.launch slam_methods:=karto
9.8. 保存地图
控制小车扫描完地图后,保存地图:
mkdir -p ~/maps/turtlebot3
rosrun map_server map_saver -f ~/maps/turtlebot3/map1
9.9. 导航
利用刚才扫描的地图进行导航控制。关闭建图终端,关闭手动键盘控制后:
roslaunch turtlebot3_navigation turtlebot3_navigation.launch map_file:=~/maps/turtlebot3/map1.yaml
记录本机地址:roslaunch turtlebot3_navigation turtlebot3_navigation.launch map_file:=/mnt/e/wsl/maps/turtlebot3/map1.yaml
接下来首先要做的是调整RViz中turtlebot在地图中的位姿,使其与Gazebo中turtlebot在环境中的位姿一致。做法是用鼠标选中RViz工具栏中的“2D Pose Estimate”,然后根据Gazebo中tuetlebot的位姿点击RViz地图中的相应位置,注意姿态也要相同。
接下来我们就开始导航了,鼠标选择工具栏中的“2D Nav Goal”,在地图中任意设置一个目标位姿,turtlebot便会自动规划路径,然后慢悠悠地移动过去。
这里2D Pose Estimate会向
/initialpose
队列发送一个坐标,该队列会由/amcl
节点监听。
9.10. 分析
9.10.1. 建图分析
9.10.1.1. 建图启动文件
建图的指令中用到了turtlebot3_slam.launch文件
<launch>
2 <!-- Arguments -->
3 <arg name="model" default="$(env TURTLEBOT3_MODEL)" doc="model type [burger, waffle, waffle_pi]"/>
4 <arg name="slam_methods" default="gmapping" doc="slam type [gmapping, cartographer, hector, karto, frontier _exploration]"/>
5 <arg name="configuration_basename" default="turtlebot3_lds_2d.lua"/>
6 <arg name="open_rviz" default="true"/>
7
8 <!-- TurtleBot3 -->
9 <include file="$(find turtlebot3_bringup)/launch/turtlebot3_remote.launch">
10 <arg name="model" value="$(arg model)" />
11 </include>
12
13 <!-- SLAM: Gmapping, Cartographer, Hector, Karto, Frontier_exploration, RTAB-Map -->
14 <include file="$(find turtlebot3_slam)/launch/turtlebot3_$(arg slam_methods).launch">
15 <arg name="model" value="$(arg model)"/>
16 <arg name="configuration_basename" value="$(arg configuration_basename)"/>
17 </include>
18
19 <!-- rviz -->
20 <group if="$(arg open_rviz)">
21 <node pkg="rviz" type="rviz" name="rviz" required="true"
22 args="-d $(find turtlebot3_slam)/rviz/turtlebot3_$(arg slam_methods).rviz"/>
23 </group>
24 </launch>
可以看到默认的slam_methods是gmapping,我们传入的是karto。有三大部分:TurtleBot3、SLAM和rviz。
TurtleBot3加载了turtlebot3_remote.launch文件,对应了/robot_state_publisher节点,SLAM加载了turtlebot3_karto.launch,对应了/slam_karto节点,打开了rviz软件。
9.10.1.2. 建图节点视图
执行rosrun rqt_graph rqt_graph
如图所示:
我们通过rosnode info /slam_karto
查看到/slam_karto发布的主题/map是nav_msgs/OccupancyGrid类型,可以供保存地图使用。
9.10.2. 保存地图
保存地图使用的指令:
rosrun map_server map_saver -f ~/maps/turtlebot3/map1
这里利用了map_server的命令行功能,从/map
中接收了[nav_msgs/OccupancyGrid]
类型的数据,可以通过rosmsg show nav_msgs/OccupancyGrid
查看数据的格式,并把它写到map1.pgm和map1.yaml中。
.pgm
说明如下:
- 该图像描述了相应像素的颜色中的世界的每个单元的占用状态。白色像素是自由的,黑色像素被占据,并且两者之间的像素是未知的。接受彩色和灰度图像,但大多数地图都是灰色的(即使它们可能存储为彩色)。YAML文件中的阈值用于划分三个类别; 阈值在map_server内部完成。
- 当与阈值参数比较时,图像像素的占用概率计算如下:occ =(255-color_avg)/ 255.0其中color_avg是通过在所有通道上求平均值而得到的8位值,例如,如果图像是24位颜色,具有颜色0x0a0a0a的像素具有0.96的概率,这是非常占用的。颜色0xeeeeee产生0.07,这是非常空的。
- 当通过ROS消息通信时,占用被表示为范围[0,100]中的整数,0意味着完全自由,100意味着完全被占用,并且特殊值-1用于完全未知。
.yaml
格式如下:
image:包含占用数据的图像文件的路径; 可以是绝对的,或相对于YAML文件的位置
resolution:地图的分辨率,米/像素
origin:可以计算出地图的(0,0)点,[0,0,0]表示在地图的右下角![-1,-2,0]中x为-1表示地图右移1m,-2表示下移2m,0表示逆时针旋转的角度,一般为0。
occupancy_thresh:占据概率大于该阈值的像素被认为完全占用。
free_thresh:占有概率小于该阈值的像素被认为是完全自由的。
negate:白/黑自由/占用语义是否应该被反转(阈值的解释不受影响)
其余具体参考/map_server章节。
9.10.3. 导航分析
9.10.3.1. 启动文件
导航用的是turtlebot3_navigation.launch文件:
<launch>
<!-- Arguments -->
<arg name="model" default="$(env TURTLEBOT3_MODEL)" doc="model type [burger, waffle, waffle_pi]"/> <!--模型-->
<arg name="map_file" default="$(find turtlebot3_navigation)/maps/map.yaml"/> <!--地图参数-->
<arg name="open_rviz" default="true"/>
<arg name="move_forward_only" default="false"/>
<!-- Turtlebot3 -->
<include file="$(find turtlebot3_bringup)/launch/turtlebot3_remote.launch">
<arg name="model" value="$(arg model)" />
</include>
<!-- Map server -->
<node pkg="map_server" name="map_server" type="map_server" args="$(arg map_file)"/>
<!-- AMCL -->
<include file="$(find turtlebot3_navigation)/launch/amcl.launch"/>
<!-- move_base -->
<include file="$(find turtlebot3_navigation)/launch/move_base.launch">
<arg name="model" value="$(arg model)" />
<arg name="move_forward_only" value="$(arg move_forward_only)"/>
</include>
<!-- rviz -->
<group if="$(arg open_rviz)">
<node pkg="rviz" type="rviz" name="rviz" required="true"
args="-d $(find turtlebot3_navigation)/rviz/turtlebot3_navigation.rviz"/>
</group>
</launch>
9.10.3.2. 节点视图
如图所示:
9.10.3.3. /tf和/tf_static
/tf : 多个时间的坐标系变换
/tf_static : 只保留最新的那个坐标系变换,查询的时候总会有。
9.10.3.4. /gazebo
-
发布的消息队列
- /scan [sensor_msgs/LaserScan] 一帧激光数据
参考http://docs.ros.org/en/api/sensor_msgs/html/msg/LaserScan.html
std_msgs/Header header #头部数据 uint32 seq #序列号 time stamp #时间戳 string frame_id #扫描数据的名称 float32 angle_min #开始扫描的角度[rad] float32 angle_max #结束扫描的角度[rad] float32 angle_increment #测量之间的角度增量[rad] float32 time_increment #测量之间的时间增量[Sec] float32 scan_time #扫描之间的时间[Sec] float32 range_min #最小范围数值[m] float32 range_max #最大范围数值[m] float32[] ranges #范围内的数据[m] float32[] intensities #强度数据
sensor_msgs::LaserScan转pcl::PointCloud:参考https://www.guyuehome.com/12913
- /odom [nav_msgs/Odometry] 里程计数据
里程计模型,参考链接https://zhuanlan.zhihu.com/p/218319127
std_msgs/Header header #头部数据 ... string child_frame_id geometry_msgs/PoseWithCovariance pose #位姿,包含两部分 geometry_msgs/Pose pose #Pose,位姿 ... float64[36] covariance #6*6协方差矩阵 geometry_msgs/TwistWithCovariance twist #线速度和角速度 协方差矩阵 geometry_msgs/Twist twist ... float64[36] covariance
协方差矩阵待完善
- /joint_states [sensor_msgs/JointState]
关节状态
Header header string[] name #名称,是数组,对应多个关节 float64[] position #the position of the joint (rad or m), 关节位置??? float64[] velocity #the velocity of the joint (rad/s or m/s),关节速度 float64[] effort #the effort that is applied in the joint (Nm or N) 施加在关节上的力
这里name是
wheel_right_joint, wheel_left_joint
,关节位置应该是左右轮子的位置,但具体意义不明? - /scan [sensor_msgs/LaserScan] 一帧激光数据
-
订阅的消息队列
- /cmd_vel [geometry_msgs/Twist]
线速度和角速度
geometry_msgs/Vector3 linear float64 x float64 y float64 z geometry_msgs/Vector3 angular float64 x float64 y float64 z
- /cmd_vel [geometry_msgs/Twist]
9.10.3.5. /robot_state_publisher
本节点订阅/joint_state
队列,同时发布tf转换关系。发布的哪些坐标系是由robot_description
描述的urdf格式文件决定的。
需要注意的是,本节点有两种发布方式,对于urdf文件中type为Floating的关节,会监听
/joint_state
来动态发布tf关系,而对于其他type的关节,只会发布一次static_tf关系。
推测在AGV中实际使用中,不需要发布数据到/joint_state
队列。
9.10.3.6. /amcl
AMCL是ROS/ROS2系统中最官方的定位模块,是导航模块中唯一指定的定位算法,在ROS/ROS2系统中,乃至整个移动机器人领域都是举足轻重的重要地位。虽然陆续也有许多其它的定位算法出现,但是在ROS/ROS2系统中,目前也仅仅是为AMCL打些配合类辅助。AMCL并不是时髦的新技术,很传统,也迟早会被其它更优秀的技术所代替。然而就目前来说,是所有机器人技术的初学者来说,是不折不扣的必备知识。
AMCL是Adaptive Monte Carlo Localization(也即是自适应蒙特卡洛定位)的简称,是基于多种蒙特卡洛融合算法在ROS/ROS2系统中的一种实现。
主要步骤如下:
- 随机生成粒子,每个粒子对应了一个AGV的位置和方向;
- 里程计移动一段距离,各个粒子进行相应的距离和方向偏移;
- 此时将一帧激光数据套入各个粒子上,然后对每个激光点坐标和背景障碍物进行概率估计,所有激光数据求出本粒子的权重;
- 对所有粒子按权重进行重采样,筛选出权重高的,然后在权重高的附近再撒粒子;
- 迭代多次后所有粒子就会聚集到一起。
似然域模型(Likelihood Field)是AMCL中推荐使用的传感器模型,计算出某个粒子的一个激光点位置和周围障碍物的最近距离d后,权重通过下面公式计算:
q = q * (Phit * 1/sqrt(2PI) * sig * exp(-d2/2sig2)) + Prand * 1/zmax) ,这里Phit sig Prand是需要给定的参数。其实后面括号中的第一部分是利用高斯计算的,落在中间轴的右边,d越大计算的结果越小,最终返回的是该粒子的概率,也即置信度。当然一批粒子算完后,置信度需进行归一化处理。
9.10.3.7. /map_server
map_server有两个功能:
- 当做map_server节点服务,它从磁盘加载静态地图数据作为一个ROS服务提供地图数据。
- 提供map_saver地图保存命令行功能,通过指令从
/map
中接收网格地图数据,然后保存成ROS专用格式的地图,参考上面的[保存地图]章节。
本节点发布话题/map给move_base用,具体格式参考上面的[保存地图]章节。
9.10.3.8. /move_base
参考链接https://www.pianshen.com/article/3044120500/
局部路径规划之DWAPlannerROS分析:https://www.cnblogs.com/sakabatou/p/8297479.html
参考<move_base详解>