- 夹角。若没特别指明,文中夹角指的是机器人偏航角和路径之间角度。路径角度是以路径的起点和终点生成一条直线,该直线在坐标系的角度。
- 对笔直,可归纳为两种处理。一是要去方向没有障碍物,这情况称不拐弯,这时给个较大linear_x,angular_z则是有个弥补夹角速度。二是要去方向有障碍物,这情况称拐弯,因为有障碍物,想着先拐出个“较大”弯,使机器人平行窄道。拐弯angular_z同样要弥补夹角。对linear_x,则使用一个只等于0.01(ROS_RID_PRESSURE_LINEAR_X)的值。
- 对可能须要调头,可归纳为三种处理:是用同一个方向的持续拐弯(UTurn),还是后退,还是根据障物障情况、走一步是一步。
- 两次theta判断。adjust_traj_backward后退时,可认为线速度是个固定值,角速度可能是两种。一是转出的角度能减少夹角,二是0,即径直后退。把依次判断这两种速度的操作称为两次theta判断。
- adjust_traj_backward后退时,线速度固定是-0.12米/秒。有种情况会例外,发现前面顶着障碍物时,此时如果不能用-0.12,还要判断-0.1、-0.08、-0.06,这么做的目的是先摆脱前面障碍物。
窄道判断后,会得到此刻正处于哪种路况,笔直、可能须要调头、还是其它。
路况 | 判断变量 | 备注 |
笔直 | straight_ward_=true, maybe_uturn_=false | use_negative_vel=false表示笔直向前,否则笔直向后 |
可能须要调头 | straight_ward_=false, maybe_uturn_=true | |
其它 | straight_ward_=false, maybe_uturn_=false |
straight_ward_和maybe_uturn_不可能同时true。
接下要根据哪种路况,计算此次要发送到底盘的速度cmd_vale。这过程,可归纳为四次计算。分别是第一次findBestPath、笔直调整、调头调整和adjust_traj_backward。
过程中可能会有两次findBestPath,第一次是有第一步。第二次是在调头调整,如果那里没通过半圈检查、而且背后没有障碍物,会触发。
一、第一次findBestPath
findBestPath会枚举所有可能速度,然后给出个最好速度。
base_local_planner::Trajectory DWAPlanner::findBestPath( const geometry_msgs::PoseStamped& global_pose, const geometry_msgs::PoseStamped& global_vel, geometry_msgs::Twist& cmd_vel, bool use_negative_vel, bool straight_ward, bool path_all_back) { ... if (use_negative_vel) { limits.min_vel_x = -ros::min_moveable_vel_x; // -0.08 limits.max_vel_x = -0.02; if (straight_ward) { limits.min_vel_x = -0.12; limits.max_vel_theta = ros::min_moveable_vel_theta; } else { limits.max_vel_theta = ros::min_moveable_vel_theta;
窄道判断后,如果use_negative_vel=true,那一定是straight_ward=true,所以第一次findBestPath不会进这入口。要能进这入口,是发生在“调头调整”中的findBestPath。
}
use_negative_vel=true,顾名思义,此时只能使用<0的负linear_x。
} else { if (maybe_uturn) { vsamples[0] = 1; limits.min_vel_x = 0.00; // 0.02 limits.max_vel_x = 0.00; // 0.02 limits.min_vel_trans = 0.03; // 0.52333 limits.min_vel_theta = DEG2RAD(30); // DEG2RAD(30)[0.52333] DEG2RAD(35)[0.6109] // limits.max_vel_theta = DEG2RAD(35); // 0.6109
调头调整可能会有两次findBestPath,这是第一次。
} else { // must use Positive velocity limits.min_vel_x = 0.02; // if (straight_ward) { limits.max_vel_theta = ros::min_moveable_vel_theta; } } } ... }
use_negative_vel=true时,会用一个负速度,并且都只有一个限制在[-min_moveable_vel_theta, min_moveable_vel_theta]的小拐弯。
二、笔直调整(straight_ward_=true)
要进入笔直调整,是有条件的,条件是此次路况是笔直。
笔直走,第一次findBestPath只是判断有没有路能通,只要判断出有路能通,就要新算出一个速度,覆盖掉findBestPath算出的速度。
那自已的速度是什么呢?分两种情况。
- 前面或后面没有障碍物,把这情况称不拐弯。不拐弯时,angular_z都有个弥补夹角速度。对linear_x,前进是“ros::min_moveable_vel_x + 0.06”,后退是“ ros::min_moveable_vel_x + 0.04”。
- 前面或后面有障碍物,把这情况称拐弯。因为有障碍物,想着先拐出个“较大”弯,使机器人平行窄道。拐弯angular_z同样要弥补夹角。对linear_x,则使用一个只等于0.01(ROS_RID_PRESSURE_LINEAR_X)的值。
三、掉头调整(maybe_uturn_=true)
要进入掉头调整,是有条件的,条件是此次路况是可能须要掉头。
此时所有路径点夹角都超过60度,认为目标点在机器人背后,这时机器人要做决定,怎么调头。是用同一个方向的持续拐弯(UTurn)、还是后退,还是根据障物障情况,走一步是一步?
3.1 同一个方向的持续拐弯(UTurn)
进行半圈检测,即模拟转半圈。模拟不是180度都试一遍,只是查45、60、75、90、105、130、145、160,看机器人是不可能转到这此个角度。如果都可能,通过半圈检测,那此次要第一次findBestPath得到的速度。这备战以着个正速度的转法,称为UTurn。
如果半圈检测失败,认为再以findBestPath得到的速度转的话,迟早会碰到障碍物。那得用自算速度了,这速度是啥,要根据背后是否有障碍物,分两种情况。
3.2 后退
背后没有障碍物。执行策略:后退。至于选择何样后退速度,由第二次findBestPath决定。在调用findBestPath前,会把use_negative_vel_置为true,maybe_uturn_置为false。这么做的原因是,既然现在这点上不能UTurn,估计是一侧或两侧有障碍,不如做点后退,可能会退到个空点地方,那时再UTurn。
3.3 根据障物障情况,走一步是一步
背后有障碍物。此时,原地UTurn,迟早会碰到障碍物。背后有障碍,又不能后退,怎么办?——用一个只有0.01(ROS_RID_PRESSURE_LINEAR_X)线速度,向左转或向右转。这种思路,只能说是转一次,可能会有新出路。那是向左还是向右?按以下优先级给速度。
- 前方,左侧没障碍、右侧有。——向左转,转30度。
- 前方,左侧有障碍、右侧没有。——向右转,转30度。
- 之前UTurn过,继续之前UTurn方向转30度,没问题。——继续之前UTurn方向转30度。
- 如果第一次findBestPath成功,用findBestPath算出的theta。
- 连第一次findBestPath都失败。——主观给一个给弥补夹的30度。
四、adjust_traj_backward
三种路况都会调用adjust_traj_backward,但此时或负速度(use_negative_vel_),或笔直(straight_ward_),或maybe_uturn_,它们只是把next_traj_backword_置为false。也就是说,对上面二、三做出的调整,adjust_traj_backward不会再做修改。
4.1 为什么要adjust_traj_backward
原因1:前向移动,只能是一个小速度时
这种情况类比倒车。因为速度很小,认为再向前走的话,可能已走不通了,不如后退,同时转个小角度,这角度会让减少夹角。
有个问题,如何判断小速度?——没用速度值,而是用这速度能移动出的距离。如果移动出的距离小于0.09米(dist_threshold),认为这个速度就是小速度。
原因2:前面顶到障碍物了
既然前面碰到障碍物,机器人自然得后退。代码用front_pressure=true表示这种情况。
原因3:须要二次后退
二次后退指的是经过一次后退,下一次继续后退。让看两种场景。一是前面顶着障碍物时,已经成功向后移动了一次,但只移动一次还是有点危险,须要有二次后退。二是出了小速度,而且夹角有点大,在[70, 110]之间,认为有二次后退能更快减少夹角。
next_traj_backword_=true表示此个adjust_traj_backward是处在二次后退中。
在二次后退时,两次theta判断都没法得到一个有效速度后,它不是使用之前findBestPath得到的小速度,而是用一个linear.x为0、theta能减少夹角的速度。这么做的原因是为避免前后拉扯。设想下此时机器人前面正顶着障碍物。
- 用adjust_traj_backward执行一次后退,同时让next_traj_backword_=true。
- 因为next_traj_backword_=true,进入二次后退时的adjust_traj_backward。但两次theta判断失败。如果就用上小速度的话,这个小速度极可能操作机器人向前移动。
- 步骤1的向后、步骤2的向前,导致机器人出现了前后拉扯。
- 为避免前后拉扯,在步骤2时,虽然两次theta判断失败,但还是使用一个只有角速度的速度。因为有步骤1的后退,此时应该已脱离和障碍物接触,机器人再经过这个速度拐弯后,可能再向前就不会碰到障碍物了。
二次后退时,不是继续后退,就是原地转一个能减少夹角的角度。
4.2 后退速度
adjust_traj_backward后退时,可认为线速度是个固定值,像-0.12,角速度可能是两种。一是转出的角度能弥合夹角,二是0,即径直后退。在这两次theta判断中,得出第一个可用速度就是要用于操作机器人后退的速度。
线速度固定选-0.12米/秒。有种情况会例外,发现前面顶着障碍物时,除-0.12外,还要再判断-0.1、-0.08、-0.06,这么做的目的是先摆脱前面障碍物。
如果出现两次theta判断都没法得到一个有效速度,则使用之前findBestPath得到的小速度。当然,二次后退时除外。