ROS(11)move_base详解

2023-05-16

11. move_base详解

11.1. move_base配置参数解读

参考链接:https://blog.csdn.net/banzhuan133/article/details/90239252
https://wenku.baidu.com/view/1ae6d9a56729647d27284b73f242336c1fb9304d.html
https://blog.csdn.net/qq_29313679/article/details/106237063
在仿真中,查看turtlebot3_navigation/launch/move_base.launch,发现局部规划器用的是DWAPlannerROS,同时加载了下面几个yaml文件:

costmap_common_params_$(arg model).yaml  
local_costmap_params.yaml  
global_costmap_params.yaml  
move_base_params.yaml  
dwa_local_planner_params_$(arg model).yaml  

这里的(arg model)用的burger模型。
在rviz下,直接用鼠标选定2D navigation goal就可以指定目标了,但是,你可能会发现效果不太好,比如,疯狂原地打转,走S型,绕大圈等现象。这些都可以通过调参搞定。
重点看后两个move_base_params.yaml、dwa_local_planner_params_$(arg model).yaml文件,地图相关参数放到Costmap2DROS分析章节中。
move_base_params.yaml:

shutdown_costmaps: false   #当move_base不在活动状态时,是否关掉costmap的加载。  
controller_frequency: 10.0 #局部规划器执行频率,也是发送cmd_vel命令的频率。     
planner_patience: 5.0  #全局规划器未规划出路线超过本时间,进行清理操作。        
controller_patience: 15.0  #局部规划器未规划出路线超过本时间,进行清理操作。   
conservative_reset_dist: 3.0 #在恢复模块执行后,重置的代价地图范围  
planner_frequency: 5.0   #全局规划操作频率,如果为0,则仅在接收到新的目标点或局部路径堵塞时才重新规划一次路径。       
oscillation_timeout: 10.0  #执行修复机制前,允许的震荡时长(秒)     
oscillation_distance: 0.2  #来回运动在多大距离以上不会认为是震荡  
recovery_behavior_enabled: true  #是否使用恢复模块     
clearing_rotation_allowed: true  #在清除操作时,是否原地旋转

dwa_local_planner_params.yaml

DWAPlannerROS:  
 # Robot Configuration Parameters (机器人配置参数)                                 
   max_vel_x: 0.22  #最大x轴方向线速度  
   min_vel_x: -0.22 #最小x轴方向线速度  

   max_vel_y: 0.0  
   min_vel_y: 0.0  

  # The velocity when robot is moving in a straight line (机器人直线运行时的速度)  
    max_vel_trans:  0.22  #最大线速度  
    min_vel_trans:  0.11  
 
    max_vel_theta: 2.75  #最大角速度  
    min_vel_theta: 1.37  
 
    acc_lim_x: 2.5  #x轴方向最高加速度  
    acc_lim_y: 0.0  
    acc_lim_theta: 3.2  
 
  # Goal Tolerance Parametes (目标误差参数)  
    xy_goal_tolerance: 0.05  #路径规划到达点与目标点的距离允许偏差  
    yaw_goal_tolerance: 0.17 #路径规划到达点与目标点的角度允许偏差  
    latch_xy_goal_tolerance: true  
    trans_stopped_vel: 0 #当机器人线速度低于这个时候,就认为是停止的
 
  # Forward Simulation Parameters(前向仿真参数)  
    sim_time: 1.5  #仿真时间,仿真距离=sim_time*vel  
    vx_samples: 20 #x轴方向速度采样数量,至少是1,否则会被强制设定为1  
    vy_samples: 0  
    vth_samples: 40  
    controller_frequency: 10.0  #发布控制速度的频率    
 
  # Trajectory Scoring Parameters(轨迹评分参数),系数影响的是本代价算法在最终代价中的一个比例    
    path_distance_bias: 32.0  #局部规划路径与全局路径保持一致的权重系数, path_costs和alignment_costs使用 
    goal_distance_bias: 20.0 #无论从什么路径以多大权重尝试到达目标点,增大后于全局规划路径一致性降低,goal_costs_和goal_front_costs_使用  
    occdist_scale: 0.02  #权衡机器人以多大的权重躲避障碍物。该值过大会导致机器人陷入困境,obstacle_costs_使用  
    forward_point_distance: 0.325  #将机器人与目标点连线并延长forward_point_distance距离作为一个评分点  
    stop_time_buffer: 0.2  #为防止碰撞,机器人必须提前停止的时间长度  
    scaling_speed: 0.25  #开始缩放机器人足迹时的速度的绝对值,单位为m/s  
    max_scaling_factor: 0.2  #最大缩放因子  
 
  # Oscillation Prevention Parameters(避免振荡参数)  
    oscillation_reset_dist: 0.05  #机器人运动多远距离才会重置振荡标记  
 
  # Debugging  
    publish_traj_pc : true  
    publish_cost_grid_pc: true  #是否发布计算后的cost话题  

11.2. 启动流程

move_base节点源文件位于/navigation-melodic-devel/move_base/move_base_node.cpp,其调用了move_base.cpp中的MoveBase的构造。主要的初始化过程也在这个构造中。main函数只有下面几句话:

  tf2_ros::Buffer buffer(ros::Duration(10));// 10s的缓冲数据
  tf2_ros::TransformListener tf(buffer); //内部监听"/tf"和"/tf_static"坐标
  move_base::MoveBase move_base( buffer );

由节点关系图可以看到,这里监听的"/tf"来自定位模块,可以是amcl或其他定位模块,传输的是各个坐标系间的转换关系。
构造流程下:

  • 构建MoveBaseActionServer,基于ROS的actionlib机制启动了一个action服务,主要作用是接收客户端发送的目标点,在回调中处理目标点并驱动AGV行走,回调函数是executeCb
  • 各个参数的初始化,在上面的仿真中,很多默认参数已经被配置文件修改了,如上面的仿真中局部规划器被改为了DWA;
  • 创建全局规划器线程;
  • 创建全局地图和局部地图;
  • 加载全局规划器、局部规划器的插件;
  • 初始化状态机状态等等。

11.3. executeCb回调

该回调函数在收到目标点时会触发调用,收到新的目标点的话会通过ROS的actionlib机制进行处理,可以调用一些接口来判断,actionlib我们不关心,大概的流程如下:

  • 通过一个信号量planner_cond_激发了全局规划器线程进行了规划,
  • 定义变量ros::Rate r(controller_frequency_)来控制下面while循环的频率,这个频率比较关键,最终体现在发送cmd_vel指令的频率上,我们称之为“控制频率”,程序中好多地方用到;
  • 中间过程不关心,调用了executeCycle()接口,来控制AGV行走,该接口会返回AGV是否到达目标点。

11.4. executeCycle接口

本函数的核心在状态CONTROLLING处理逻辑中:

  • 通过调用LatchedStopRotateController类的isGoalReached()接口判断是否到达目标点,这个类参考后面的<目标点达到控制>章节;
  • 通过调用dwa_planner_ros.cppDWAPlannerROS类的computeVelocityCommands()接口来计算下发给AGV底盘的指令。这里AGV清除恢复CLEARING及流程我们不关心。

11.5. DWAPlannerROS::computeVelocityCommands

DWA参考链接: http://gaoyichao.com/Xiaotu/?book=turtlebot&title=dwa_local_planner
本接口会进行一个是否到达目标点的判断(通过LatchedStopRotateController):

  • 最开始部分会调用planner_util_.getLocalPlan()接口,将原/map坐标系下的全局路径转换到/odom坐标系下;
  • 调用LatchedStopRotateController::isPositionReached只判断XY是否到达,如果到达那么会调用latchedStopRotateController_.computeVelocityCommandsStopRotate()来判断角度是否到达,角度没到达进行旋转控制,否则发送停止;如果没到达xy,那么会调用DWAPlannerROS::dwaComputeVelocityCommands()来把最佳轨迹对应的速度作为下发底盘的速度cmd_vel。xy到达后的旋转参考后面的<目标点到达控制>章节;
  • 未到达目标点,调用DWAPlanner类的findBestPath()接口,它又调用了SimpleScoredSamplingPlanner接口中的findBestTrajectory(),后者会通过SimpleTrajectoryGenerator类创建出轨迹,并调用代价算法来计算轨迹得分。
    DWAPlanner类中存储了7种代价计算方法,分别是:
OscillationCostFunction oscillation_costs_  // 减少晃动  
ObstacleCostFunction obstacle_costs_        // 减少机器人撞上障碍物
MapGridCostFunction goal_front_costs_       // prefers trajectories that make the nose go towards (local) nose goal
MapGridCostFunction alignment_costs_        // prefers trajectories that keep the robot nose on nose path
MapGridCostFunction path_costs_             // 通过波传播的一种代价算法,更倾向于贴近全局轨迹
MapGridCostFunction goal_costs_             // 通过波传播的一种代价算法,更倾向于全局路径和局部地图的交点
TwirlingCostFunction twirling_costs_        // 减少原地打转     

通过设定的比例系数,来对各个代价进行加权得出最后的代价数值。当计算出最优轨迹后,将轨迹对应的速度下发到底盘。

11.5.1. SimpleTrajectoryGenerator轨迹创建

该类中主要的接口有两个:initialisegenerateTrajectory

  • initialise接口首先根据<x,y,th>三个加速度,根据当前速度和“控制频率”时间,计算一个时间片后的最大和最小速度;然后根据设定的采样数量对三个速度方向进行<min_vec,max_vec>范围采样,得到一堆速度(turtlebot3仿真中的参数得到了800个速度);
  • generateTrajectory接口,一个速度计算一段轨迹,轨迹中点的个数计算公式:
线速度仿真距离 = 线速度 * 采样时间;  
角速度速度仿真距离 = 角速度速度 * 采样时间;  
线速度方向个数 = 线速度仿真距离 / 线速度仿真间隔;  
角速度方向个数 = 角速度仿真距离 / 角速度仿真间隔;
总数量 = max(线速度方向个数,角速度方向个数)

11.6. MapGridCostFunction代价计算

有四种代价都是通过本类实现的,这里只关注了两个主要的:贴近全局轨迹和贴近全局轨迹与局部地图的交点。
这个类主要的接口有两个:prepare()scoreTrajectory()

  • prepare():其中调用的逻辑是由MapGrid类实现的,需要提前调用,生成代价数据表来加速代价查询。该函数有两个作用:
    一个是提前算好局部网格地图(注意是网格地图)中每个网格点距离全局路径在局部地图中的单位长度,如图,其中0是全局路径占用的网格,其他网格数据通过一个扩散的算法实现的(不是欧式距离),这里1 2 3代表离0的一个相对距离:
3 2 1 0 1 2 3 
3 2 1 0 1 2 3
2 1 0 1 1 2 3
1 0 1 2 3 4 5
1 0 1 2 4 4 5

另一个是计算每个网格到全局路径和局部地图交点的单位长度,也是通过同样的扩散算法实现的,这里0是目标点:

- 2 1 0 1 2 -
- 3 2 1 2 3 -
- 4 3 2 3 4 -
  • scoreTrajectory():这个函数很简单,就是直接查询代价表,来通过三种策略计算轨迹的代价值:
Last:默认是这个,只保留最后一个轨迹点距离全局轨迹的相对距离,来作为最终的代价;
Sum:所有点相对距离的累加;
Product:所有点相对距离的累乘。

11.7. OscillationCostFunction代价计算

本代价是为了减少车身的晃动。逻辑非常简单,总体来说就是AGV往前行驶一段距离的过程中,每次创建轨迹并进行打分时,都会考虑这些轨迹的速度和初始速度的正负关系,保证<x,y,th>都和初始速度方向一致。行驶一段距离后会重置初始的速度方向,重新开始统计。
关键的接口有:

  • updateOscillationFlags() : 每次计算出最优轨迹时调用,如果超出了设定的距离,会重置检测标记;
  • scoreTrajectory() : 对某个轨迹进行打分,就是看看轨迹的<x, y, th>速度方向是否和初始设置的一致。

11.8. 目标点到达控制(LatchedStopRotateController)

  • isPositionReached(): 只判断XY是否到达,不判断角度是否到达。
  • isGoalReached(): 判断xy和朝向角都在误差范围、且会通过里程计信息判断<x,y,th>速度是满足到达误差。此函数会在CONTROLLING状态下每次控制频率到后都会调用,以此来切换控制状态。其中有个标志latch_xy_goal_tolerance_可以对xy判断进行锁存,意思是说如果如果该标记为true且曾经满足当前位置和目标位置的xy在误差范围内,那么后续再调用本接口时,不再判断xy是否满足误差范围,只判断角度和速度是否满足误差范围,这样到达目标点(xy到达)后调整角度过程中,如果xy偏离了也不关心。核心代码如下:
//这个if条件中的||是关键,当前两者为true时,后面那个xy距离判断将不再起作用。
if ((latch_xy_goal_tolerance_ && xy_tolerance_latch_) ||
      base_local_planner::getGoalPositionDistance(global_pose, goal_x, goal_y) <= xy_goal_tolerance) {
    if (latch_xy_goal_tolerance_ && ! xy_tolerance_latch_) {
      xy_tolerance_latch_ = true; //这里是上面||后面条件起作用进入的
    }
    if (fabs(angle) <= limits.yaw_goal_tolerance) { //角度满足误差
      if (base_local_planner::stopped(base_odom, theta_stopped_vel, trans_stopped_vel)) {//速度满足误差
        return true;
      }
    }
return false; //如果旋转过程中不锁存xy,一旦xy超出误差那么上面角度误差判定就进入了,直接返回false!
  • computeVelocityCommandsStopRotate() : 该函数的进入条件为xy已经到了,然后判断角度是否到了,如果到了那么直接发送0速度来强行停止(如果第一次到达xy并且角度也满足,这样做太粗暴了;如果角度不满足,这里就是旋转过程中控制停止的条件,是可以的)。如果没到那么会检查是否速度<x,y,th>已经满足停止条件:
    • 满足:此时可以认为机器人已经停下了,则进行旋转操作rotateToGoal(),这里会根据最大最小限速及和目标角度的夹角计算角速度,这里注意当离目标角度越近的时候,速度计算会直接采用这个距离,也就是旋转过程离目标点越近旋转速度越慢,并下发下去,进行下次循环,继续在computeVelocityCommandsStopRotate中判断是否角度到了发送0速度;
    • 不满足:则进行减速操作,通过加速度计算下个仿真周期减速后的<x,y,th>方向的速度,这里会调用轨迹检查接口,不用关心该调用。发送的速度计算:v-at,如果为负的,那么就是0。

这个目标点到达控制如果在到达目标点且角度也一样时,会强行停止,比如在行驶速度特别大的时候,可能会出现急停滑行的问题等等,实际应用的话还需要改进。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ROS(11)move_base详解 的相关文章

  • 解决Vmware虚拟机无法打开Ubuntu的问题

    1 xff0c 问题 很多同学会在Window PC机上使用Vmware虚拟机来搭建Linux开发环境 xff08 如Ubuntu xff09 xff0c 使用过程中难免会出现Ubuntu崩溃 异常关闭等现象 xff0c 此时 xff0c

随机推荐

  • antd 表单动态添加表单项编辑回显数据

    在做一些后台管理会用到很多的表单 xff0c 比如动态项表单 xff0c 如下图这样的 话不多说 xff0c 上代码 创建修改版本 import React from 34 react 34 import Form Notification
  • 二进制流文件下载

    在做一些文件下载的时候 xff0c 后端返回的二进制流文件 xff0c 这里前端的兄弟姐妹就需要处理一下了 直接上代码 xff1a 下载 export function download id return request url 96 r
  • ES6数组reduce的妙用

    定义和用法 reduce 方法接收一个函数作为累加器 xff0c 数组中的每个值 xff08 从左到右 xff09 开始缩减 xff0c 最终计算为一个值 reduce 可以作为一个高阶函数 xff0c 用于函数的 compose 注意 r
  • element 去掉form表单的某一项单个form-Item校验

    在执行完相应的方法 xff0c 立即触发移除校验 this nextTick 61 gt this refs 39 form 39 clearValidate 39 name 39 this refs 39 form 39 clearVal
  • element表单多行数据自定义校验以及自定义传参

    场景说明 如下图 在form表单中迁移table表格 每行数据都要能编辑 单独校验 注释 此处的资源下拉框校验 还需要走异步请求获取结果 然后再对比校验 nbsp 话不多 上代码说明 1 首先获取的接口数据如下 form vmDataLis
  • Hbuilder修改项目git提交路径

    在git的使用中 xff0c 经常会出现git服务器IP地址变更的现象 xff0c 一旦服务器的IP地址有变化 xff0c 本地仓库的代码就和服务器失去了联系 xff0c 无法同步服务器的代码 这里说明一下 xff0c 如何修改git提交路
  • css3的clip-path方法剪裁实现(三角形,多边形,圆,椭圆)

    本例讲解如何通过clip path 把一个div xff08 元素 xff0c 可以是图片等 xff09 裁切成不同的形状 xff0c 这里以一个div为例宽高均为300px 注意 xff1a 不支持IE和Firefox xff0c 支持w
  • layui表格(table)排序

    layui表格本身提供sort排序 xff0c 但是只能排序当前一页 xff1b 如果后台返回几十页数据 xff0c 需要排序显示 xff0c 该如何做呢 xff0c 这里闲心大神提供了一个sort监听方法 xff1a 通过监听排序的列 x
  • Liunx下修改MySQL字符集

    Liunx下修改MySQL字符集 1 查找MySQL的cnf文件的位置 color 61 green find iname 39 cnf 39 print color color 61 olive usr share mysql my in
  • vue刷新当前页面,重载页面数据

    业务场景 xff1a 在管理后台 xff0c 在执行完 xff0c 增 xff0c 删 xff0c 改 xff0c 操作的时候 我们需要刷新一下页面 xff0c 重载数据 在JQ中我们会用到location reload 方法 xff0c
  • layui动态渲染生成左侧3级菜单(根据后台返回数据)

    声明 xff1a 这里非常感谢闲心大神 xff0c 开源了非常好用的前端UI框架 xff0c layui xff0c 如有侵权请联系我 当然闲心在2 0版本的layuiAdmin已经支持了 xff0c 不过是收费版的 xff0c 需要的同学
  • layui加载数据显示loading加载完成loading消失

    项目中 xff0c 向后台请求数据 xff0c 经常会出现较长的等待时间 xff0c 这时我们需要一个loading转圈圈 xff0c 接收到后台的数据时 xff0c 让loading消失 这layui中使用方法如下 xff1a 以表格为例
  • 信号量,消息邮箱的运用

    1 信号量的用途 1 xff09 共享资源的保护 xff0c 例如需要共用一段内存 xff0c 初始信号量的计数值为1 task1 xff1a task2 pend信号量 pend信号量 共享资源 共享资源 post信号量 post信号量
  • istio 部署及调用链显示

    选择版本号下载 https github com istio istio releases 下载 wget https github com istio istio releases download 1 13 2 istio 1 13 2
  • Poco Application 框架学习(1)

    基本的功能 提供了一个 int run int argc char argv 方法用于执行app run 方法会调用 类的 void initialize Application amp self 与 int main const std
  • Poco Application 框架学习(3)配置文件,日志

    配置文件及日志 配置文件 xff1a 配置文件初始化 一般应用程序都会有配置文件 xff0c Application 框架也不例外 通过一下接口来读取配置文件信息 当前 Poco支持的格式有 ini xml json properties
  • openssl 使用 未定义的引用

    ubuntu 下使用 openssl 3des 加密编译报错 tmp ccsIK1Cj o xff1a 在函数 main 中 xff1a test cpp text 43 0x218 xff1a 对 DES set key unchecke
  • openssl 使用 未定义的引用

    ubuntu 下使用 openssl 3des 加密编译报错 tmp ccsIK1Cj o xff1a 在函数 main 中 xff1a test cpp text 43 0x218 xff1a 对 DES set key unchecke
  • poco JSON 的使用

    三个例子 第一个是解析一个简单的 json 第二个是在构造一个 json 对象并且加入数据 第三个是解析带数组的 json对象 这三个场景基本上满足大部分需求了 span class hljs variable include span s
  • ROS(11)move_base详解

    11 move base详解 11 1 move base配置参数解读 参考链接 xff1a https blog csdn net banzhuan133 article details 90239252 https wenku baid