目录

一、建图与保存地图

1.先启动机器人仿真节点

2.使用建图

(1).安装gmapping

(2).编写启动gmapping的launch文件gmapping_slam_start.launch

(3).启动gmapping

3.启动键盘键盘控制节点,用于控制机器人运动建图

4.保存地图launch文件map_save.launch

(1)编写保存地图launch文件

(2)启动保存地图launch文件

二、利用已经建好的图定位

1.加载地图

2.启动acml

(1)下载acml

(2)编写acml配置代码acml.launch

(3)解释

(4)如何使用

三、利用建立好的地图导航

1.初始准备

2.move_base导航介绍

3.地图分层介绍

4.参数文件介绍

(1)costmap_common_params.yaml

(2)global_costmap_params.yaml

(3)local_costmap_params.yaml

(4)base_local_planner_params

5.运行

四、导航和SLAM建图


参考链接:7.2.3 导航实现03_定位 · Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程

前言:

通过我的上一篇文章ROS机器人开发实践->机器人建模与仿真-CSDN博客,我们已经可以在仿真环境中创建一个机器人了,并可以得到他的传感器信息。接下来我们就利用这个机器人进行导航。我们的目的是以下几个功能:

1.建图与保存地图

2.利用已经建好的图定位

3.利用已经建好的图导航

4.边建图边导航

一、建图与保存地图

1.先启动机器人仿真节点

roslaunch car_gazebo_simulation start_gazebo_all.launch

2.使用建图

(1).安装gmapping

sudo apt install ros-<ROS版本>-gmapping

(2).编写启动gmapping的launch文件gmapping_slam_start.launch

<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" /> -->
    <!-- 可以保存 rviz 配置并后期直接使用-->
    <!--
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find my_nav_sum)/rviz/gmapping.rviz"/>
    -->
</launch>

解释:建图需要里程计和激光雷达的信息。对于这个launch文件,激光雷达数据通过话题scan获得,里程计的信息使用下面这两个坐标系的相对位置关系获得。

<param name="base_frame" value="base_footprint"/><!--底盘坐标系-->
<param name="odom_frame" value="odom"/> <!--里程计坐标系-->

输出上面配置文件里面没写,默认输出栅格地图的话题是/map,一会创建map的tf坐标,输出map → odom 的 tf

(3).启动gmapping

roslaunch car_gazebo_navigation gmapping_slam_start.launch

3.启动键盘键盘控制节点,用于控制机器人运动建图

rosrun teleop_twist_keyboard teleop_twist_keyboard.py

4.保存地图launch文件map_save.launch

(1)编写保存地图launch文件

finename的值就是地图保存路径

<launch>
    <arg name="filename" value="$(find car_gazebo_navigation)/map/nav" />
    <node name="map_save" pkg="map_server" type="map_saver" args="-f $(arg filename)" />
</launch>

默认将/map话题保存成地图,如果话题名不是/map,需要重映射

<launch>
    <arg name="filename" value="$(find car_gazebo_navigation)/map/nav" />
    <node name="map_save" pkg="map_server" type="map_saver" args="-f $(arg filename)">
        <remap from="map" to="your_map_topic_name" />
    </node>
</launch>

(2)启动保存地图launch文件

roslaunch car_gazebo_navigation  map_save.launch

二、利用已经建好的图定位

1.加载地图

    <node name="map_server" pkg="map_server" type="map_server" args="$(find car_gazebo_navigation)/map/$(arg map)"/>

2.启动acml

(1)下载acml

amcl已经被集成到了navigation包,navigation安装前面也有介绍,命令如下:

sudo apt install ros-<ROS版本>-navigation

(2)编写acml配置代码acml.launch

<launch>
<node pkg="amcl" type="amcl" name="amcl" output="screen">
  <!-- Publish scans from best pose at a max of 10 Hz -->
  <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"/>
  <!-- translation std dev, m -->
  <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_model_type" value="beam"/> -->
  <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>

(3)解释

amcl这个包输入base_frame和odom的tf。这样就可以知道Δx, Δy, Δθ,之后根据这个变化量更新粒子的位置。之后订阅了/scan和/map话题,用于确定每个例子的权重。之后订阅/initialpose用于确定初始位置。最后输出了map的tf。可以获得得到激光雷达修正之后,机器人的真实位置。

注意,上述文件中默认订阅/scan和/map,如果你的激光雷达数据和栅格地图数据不是这两个,那么需要你remap一下。

<node pkg="amcl" type="amcl" name="amcl" output="screen">
  <remap from="scan" to="/rplidar/scan"/>    <!-- 激光话题改名 -->
  <remap from="map" to="/my_map_topic"/>     <!-- 地图话题改名 -->
</node>

注意,为什么已经有了Δx, Δy, Δθ,还需要差分的模型呢?原因是acml在工作的时候,不仅考虑Δx, Δy, Δθ,还会考虑误差。所以不同的运动学模型,每次计算误差不同

① 差分驱动(odom_model_type=diff

  • 假设机器人靠左右轮差速来运动。

  • 当有误差时,主要体现为:

    • 直行误差:左右轮编码器不一致,导致直线走歪。

    • 旋转误差:原地转动时,两轮速度不对称,导致角度偏差。

  • 粒子采样时,AMCL 会在 Δθ 上加较多不确定性。


② 全向驱动(odom_model_type=omni

  • 假设机器人有麦克纳姆轮或全向轮,可以直接实现任意 Δx, Δy, Δθ。

  • 误差分布更均匀,直行时也可能有侧滑。

  • 粒子采样会在 Δx, Δy 上增加更多横向不确定性。

(4)如何使用

1.启动仿真环境

roslaunch car_gazebo_simulation start_gazebo_all.launch

2.启动遥控器

rosrun teleop_twist_keyboard teleop_twist_keyboard.py

3.启动定位节点

roslaunch car_gazebo_navigation dingwei.launch

######

dingwei.launch的代码如下

<launch>
    <!-- 设置地图的配置文件 -->
    <arg name="map" default="nav.yaml" />
    <!-- 运行地图服务器,并且加载设置的地图-->
    <node name="map_server" pkg="map_server" type="map_server" args="$(find car_gazebo_navigation)/map/$(arg map)"/>
    <!-- 启动AMCL节点 -->
    <include file="$(find car_gazebo_navigation)/launch/amcl.launch" />
    <!-- 运行rviz -->
    <!-- <node pkg="rviz" type="rviz" name="rviz"/> -->
</launch>

三、利用建立好的地图导航

1.初始准备

下载move_base导航包

sudo apt install ros-<ROS版本>-navigation

2.move_base导航介绍

基本架构就是订阅目标话题,输出速度控制话题

3.地图分层介绍

代价地图有两张:global_costmap(全局代价地图) 和 local_costmap(本地代价地图),前者用于全局路径规划,后者用于本地路径规划。

两张代价地图都可以多层叠加,一般有以下层级:

  • Static Map Layer:静态地图层,SLAM构建的静态地图。

  • Obstacle Map Layer:障碍地图层,传感器感知的障碍物信息。

  • Inflation Layer:膨胀层,在以上两层地图上进行膨胀(向外扩张),以避免机器人的外壳会撞上障碍物。

  • Other Layers:自定义costmap。

4.参数文件介绍

(1)costmap_common_params.yaml

sensor_frame: 激光雷达坐标系,要和tf中一致

data_type: 激光雷达数据类型

topic:激光雷达话题名

  • marking: true

    • 表示该传感器数据可以 在代价地图上添加障碍物

    • 举例:激光扫到墙 → 在 costmap 上标记为障碍。

  • clearing: true

    • 表示该传感器数据也可以 清除代价地图上的障碍物

    • 举例:原来 costmap 上有个障碍物,现在激光能穿过去了 → 把它删掉。

obstacle_range

  • 作用:设定传感器数据能在代价地图里“标记障碍物”的最大有效距离。

  • 举例:

    • 你用的是 10m 激光雷达,但 obstacle_range = 3.0

    • 那么只有 3m 内的障碍物会被认为是障碍,更新进局部代价地图。

  • 好处:

    • 只考虑近距离障碍,更符合局部规划需要(机器人一般不会管 10m 以外的障碍)。

    • 减少计算量。


raytrace_range

  • 作用:设定传感器的“自由空间射线”能清除障碍物的最远距离。

  • 举例:

    • raytrace_range = 3.5,表示如果激光打到 3.5m 外,就会把射线路径上更近的旧障碍物“清空”。

  • 这是为了防止“幽灵障碍物”:

    • 比如一个人走开了,之前 2m 处的障碍点如果不清除,就会一直留在 costmap 里。

    • 有了 raytrace,就能把消失的障碍物清掉。

#机器人几何参,如果机器人是圆形,设置 robot_radius,如果是其他形状设置 footprint
robot_radius: 0.12 #圆形
# footprint: [[-0.12, -0.12], [-0.12, 0.12], [0.12, 0.12], [0.12, -0.12]] #其他形状

obstacle_range: 3.0 # 用于障碍物探测,比如: 值为 3.0,意味着检测到距离小于 3 米的障碍物时,就会引入代价地图
raytrace_range: 3.5 # 用于清除障碍物,比如:值为 3.5,意味着清除代价地图中 3.5 米以外的障碍物


#膨胀半径,扩展在碰撞区域以外的代价区域,使得机器人规划路径避开障碍物
inflation_radius: 0.2
#代价比例系数,越大则代价值越小
cost_scaling_factor: 3.0

#地图类型
map_type: costmap
#导航包所需要的传感器
observation_sources: scan
#对传感器的坐标系和数据进行配置。这个也会用于代价地图添加和清除障碍物。例如,你可以用激光雷达传感器用于在代价地图添加障碍物,再添加kinect用于导航和清除障碍物。
scan: {sensor_frame: laser, data_type: LaserScan, topic: scan, marking: true, clearing: true}

(2)global_costmap_params.yaml

static_map: 就是订阅/map话题初始化全局地图,如果话题不是/map需要重映射一下。

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 # 是否使用一个地图或者地图服务器来初始化全局代价地图,如果不使用静态地图,这个参数为false.

(3)local_costmap_params.yaml

rolling_window: 这个为true表示局部代价地图随着机器人移动而变化,否则就是固定的一个位置。

这里为啥要使用里程计坐标系和机器人坐标系,这样得到的机器人的位置不是真实值。那么得到的局部地图不是偏了吗?

但是它的解释是使用odom比较稳定,局部地图的位置不会跳变,其实我觉的使用map和odom应该区别不大。

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 #是否使用动态窗口,默认为false,在静态的全局地图中,地图不会变化
  width: 3 # 局部地图宽度 单位是 m
  height: 3 # 局部地图高度 单位是 m
  resolution: 0.05 # 局部地图分辨率 单位是 m,一般与静态地图分辨率保持一致

(4)base_local_planner_params

使用DWA局部路径规划算法。

  sim_time: 0.8  每步采样仿真时间,应该指的是总仿真时间。

  vx_samples: 18  在vx的最大值和最小值之间随机采样18个速度

  vtheta_samples: 20:在vtheta最大值和最小值之间随机采样20个速度

sim_granularity: 0.05 : 采样完成之后生成轨迹。之后进行碰撞检测,这个是碰撞检测的时间步长。

TrajectoryPlannerROS:

# Robot Configuration Parameters
  max_vel_x: 0.5 # X 方向最大速度
  min_vel_x: 0.1 # X 方向最小速速

  max_vel_theta:  1.0 # 
  min_vel_theta: -1.0
  min_in_place_vel_theta: 1.0

  acc_lim_x: 1.0 # X 加速限制
  acc_lim_y: 0.0 # Y 加速限制
  acc_lim_theta: 0.6 # 角速度加速限制

# Goal Tolerance Parameters,目标公差
  xy_goal_tolerance: 0.10
  yaw_goal_tolerance: 0.05

# Differential-drive robot configuration
# 是否是全向移动机器人
  holonomic_robot: false

# Forward Simulation Parameters,前进模拟参数
  sim_time: 0.8
  vx_samples: 18
  vtheta_samples: 20
  sim_granularity: 0.05

5.运行

my_move_base.launch

<launch>

    <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen" clear_params="true">
        <rosparam file="$(find car_gazebo_navigation)/param/costmap_common_params.yaml" command="load" ns="global_costmap" />
        <rosparam file="$(find car_gazebo_navigation)/param/costmap_common_params.yaml" command="load" ns="local_costmap" />
        <rosparam file="$(find car_gazebo_navigation)/param/local_costmap_params.yaml" command="load" />
        <rosparam file="$(find car_gazebo_navigation)/param/global_costmap_params.yaml" command="load" />
        <rosparam file="$(find car_gazebo_navigation)/param/base_local_planner_params.yaml" command="load" />
    </node>

</launch>

path_finding.launch

<launch>
    <!-- 设置地图的配置文件 -->
    <arg name="map" default="nav.yaml" />
    <!-- 运行地图服务器,并且加载设置的地图-->
    <node name="map_server" pkg="map_server" type="map_server" args="$(find car_gazebo_navigation)/map/$(arg map)"/>
    <!-- 启动AMCL节点 -->
    <include file="$(find car_gazebo_navigation)/launch/amcl.launch" />

    <!-- 运行move_base节点 -->
    <include file="$(find car_gazebo_navigation)/launch/my_move_base.launch" />

</launch>

直接启动仿真节点和path_finding.launch

roslaunch car_gazebo_simulation start_gazebo_all.launch 


roslaunch car_gazebo_navigation path_finding.launch 

四、导航和SLAM建图

其实直接启动gammaping节点和move_base节点,还有仿真环境节点就可以了。但是要注意gammaping和move_base要求的话题名和tf坐标名

<launch>
    <!-- 启动SLAM节点 -->
    <include file="$(find car_gazebo_navigation)/launch/gmapping_slam_start.launch" />
    <!-- 运行move_base节点 -->
    <include file="$(find car_gazebo_navigation)/launch/my_move_base.launch" />
    <!-- 运行rviz -->
    <!-- <node pkg="rviz" type="rviz" name="rviz" args="-d $(find mycar_nav)/rviz/nav.rviz" /> -->
</launch>

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐