ROS1 DWB 与 ROS2 DWA 比较

“DWA算法(dynamic window approach)是移动机器人在运动模型下推算(v,w)对应的轨迹,确定速度采样空间或者说是动态窗口(三种限制);在速度空间(v,w)中采样多组速度,并模拟这些速度在一定时间内的运动轨迹,通过一个评价函数对这些轨迹打分,选取最优的轨迹来驱动机器人运动”。ROS1导航中局部路径规划便可选用该方法,DWB是在DWA的基础上进行了一定的优化和扩展,被ROS2采用。

在该算法中,重要的函数主要是两个:采样轨迹生成和轨迹评分,下面结合相关源码进行简单的解读和比较。

一. DWB代码和原理简单解读
在这里插入图片描述

轨迹采样函数generateTrajectory:根据机器人当前位姿start_pose,速度start_vel和目标速度cmd_vel,在预设的采样时间内进行速度空间采样,并利用离散机器人运动学模型,生成对应的轨迹,用于后续的评分,中的computeNewVelocity会在机器人运动学约束下使得速度尽可能接近目标速度,而最终的目标速度是指机器人在采样时间段内可达最终速度。

dwb_msgs::msg::Trajectory2D StandardTrajectoryGenerator::generateTrajectory(
const geometry_msgs::msg::Pose2D & start_pose,
const nav_2d_msgs::msg::Twist2D & start_vel,
const nav_2d_msgs::msg::Twist2D & cmd_vel)
{
dwb_msgs::msg::Trajectory2D traj;
traj.velocity = cmd_vel;
// simulate the trajectory
geometry_msgs::msg::Pose2D pose = start_pose;
nav_2d_msgs::msg::Twist2D vel = start_vel;
double running_time = 0.0;
std::vector<double> steps = getTimeSteps(cmd_vel);
traj.poses.push_back(start_pose);
for (double dt : steps) {
// calculate velocities
vel = computeNewVelocity(cmd_vel, vel, dt);
// update the position of the robot using the velocities passed in
pose = computeNewPosition(pose, vel, dt);
traj.poses.push_back(pose);
traj.time_offsets.push_back(rclcpp::Duration::from_seconds(running_time));
running_time += dt;
} // end for simulation steps
if (include_last_point_) {
traj.poses.push_back(pose);
traj.time_offsets.push_back(rclcpp::Duration::from_seconds(running_time));
}
return traj;
}

评分函数:使用每一个预设加载的评分函数对轨迹进行评分,然后进行加权求和,评分越低,代表该轨迹越优。

dwb_msgs::msg::TrajectoryScore
DWBLocalPlanner::scoreTrajectory(
const dwb_msgs::msg::Trajectory2D & traj,
double best_score)
{
dwb_msgs::msg::TrajectoryScore score;
score.traj = traj;
for (TrajectoryCritic::Ptr & critic : critics_) {
dwb_msgs::msg::CriticScore cs;
cs.name = critic->getName();
cs.scale = critic->getScale();
if (cs.scale == 0.0) {
score.scores.push_back(cs);
continue;
}
double critic_score = critic->scoreTrajectory(traj);
cs.raw_score = critic_score;
score.scores.push_back(cs);
score.total += critic_score * cs.scale;
if (short_circuit_trajectory_evaluation_ && best_score > 0 && score.total > best_score) {
// since we keep adding positives, once we are worse than the best, we will stay worse
break;
}
}
return score;
}

可选加载的评分函数有:

轨迹评分:评分越低越优
base_obstacle: 将代价地图在轨迹上每个位姿处的cost值进行加和,如果碰到障碍物或者出界,则会抛出异常,轨迹被视为非法;
GoalAlign:使得机器人在导航过程中方向慢慢朝向目标方向,避免到点后再原地旋转,因为这种方式可能不稳定;
RotateToGoal:
如果不够接近目标,返回0
如果足够接近目标,且当前平移速度大于停止速度,但采样速度超过当前速度,该轨迹不行;
如果足够接近目标,且当前平移速度大于停止速度,采样速度小于当前速度,则采样轨迹终点角度越接近目标角度,速度值越小,评分越低;
如果足够接近目标,且当前平移速度小于停止速度,则有平移的速度都不行;
否则,采样轨迹终点角度越接近目标角度,评分越低;
Oscillation:
轨迹中第一个采样速度为停止(线速度和角速度有一个停止,可能需要修改判断逻辑),则路径非法
否则返回0
PathAlign
如果足够接近目标(参数:forward_point_distance),返回0
否则返回轨迹末尾位姿往前延伸forward_point_distance处的cost值

PathDist:轨迹离规划路径越接近,得分越低,它偏好更接近给定参考轨迹的轨迹;
GoalDist:找到轨迹在局部代价地图中离当前位姿最远的位姿,使得轨迹最后的位姿更接近该位姿;

ObstacleFootprintCritic:考虑了机器人形状的障碍物规避评估,该形状在局部地图中设置,即footprint

 TwirlingCritic:惩罚旋转,轨迹初始旋转速度越大,得分越高。对于差速机器人,没必要选这个,但对于全向或者接近全向的机器人,有时候机器人在去往目标的过程中,比期望的旋转太多,这个评分提供了一个方式用于惩罚纯旋转速度。

二. DWA代码和原理简单解读

bool DWAPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel) {
// dispatches to either dwa sampling control or stop and rotate control, depending on whether we have been close enough to goal
if ( ! costmap_ros_->getRobotPose(current_pose_)) {
ROS_ERROR("Could not get robot pose");
return false;
}
std::vector<geometry_msgs::PoseStamped> transformed_plan;
if ( ! planner_util_.getLocalPlan(current_pose_, transformed_plan)) {
ROS_ERROR("Could not get local plan");
return false;
}

//if the global plan passed in is empty... we won't do anything
if(transformed_plan.empty()) {
ROS_WARN_NAMED("dwa_local_planner", "Received an empty transformed plan.");
return false;
}
ROS_DEBUG_NAMED("dwa_local_planner", "Received a transformed plan with %zu points.", transformed_plan.size());
// update plan in dwa_planner even if we just stop and rotate, to allow checkTrajectory
dp_->updatePlanAndLocalCosts(current_pose_, transformed_plan, costmap_ros_->getRobotFootprint());
if (latchedStopRotateController_.isPositionReached(&planner_util_, current_pose_)) {
//publish an empty plan because we've reached our goal position
std::vector<geometry_msgs::PoseStamped> local_plan;
std::vector<geometry_msgs::PoseStamped> transformed_plan;
publishGlobalPlan(transformed_plan);
publishLocalPlan(local_plan);
base_local_planner::LocalPlannerLimits limits = planner_util_.getCurrentLimits();
return latchedStopRotateController_.computeVelocityCommandsStopRotate(
cmd_vel,
limits.getAccLimits(),
dp_->getSimPeriod(),
&planner_util_,
odom_helper_,
current_pose_,
boost::bind(&DWAPlanner::checkTrajectory, dp_, _1, _2, _3));
} else {
bool isOk = dwaComputeVelocityCommands(current_pose_, cmd_vel);
if (isOk) {
publishGlobalPlan(transformed_plan);
} else {
ROS_WARN_NAMED("dwa_local_planner", "DWA planner failed to produce path.");
std::vector<geometry_msgs::PoseStamped> empty_plan;
publishGlobalPlan(empty_plan);
}
return isOk;
}
}

DWB是DWA算法的扩展和改进,它们的不同之处在于

  1. DWA在轨迹生成器初始化和轨迹生成时,根据参数use_dwa_进行一定的选择,而DWB等同于前者use_dwa_默认为true的情况,但在初始化时并没有对第一个采样速度进行加速度约束,造成速度指令可能超出加速度上限。

  2. DWA在位置到达时,进行纯旋转调整方向,而DWB是使用RotateToGoal评分在位置到达时优先选择纯旋转轨迹;

  3. DWA的评分项中没有考虑机器人底盘(footprint)可能会落入障碍物。

三. 局限性
DWA/DWB采样时,采样速度会倾向于目标速度,这使得速度只会单调变化(如单调减少,或者单调增加),对于线速度而言没什么明显不合适,但对于旋转而言,则造成每条采样轨迹只能朝一个方向延伸,如下图所示(黑色表示不合理采样轨迹,绿色无箭头附着的表示合理轨迹,绿色有箭头附着的为想跟随的参考轨迹),不适用于Z字形连续弯道和需要频繁转向的动态避障,这也是一个值得优化的点。有点则在于算法简单高效,低动态场景下适用。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/796945.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PHP计件工资系统小程序源码

解锁高效管理新姿势&#xff01;全面了解计件工资系统 &#x1f525; 开篇&#xff1a;为什么计件工资系统成为企业新宠&#xff1f; 在这个效率至上的时代&#xff0c;企业如何精准激励员工&#xff0c;提升生产力成为了一大挑战。计件工资系统应运而生&#xff0c;它以其公…

【UE5.1 角色练习】15-枪械射击——子弹发射物

目录 效果 步骤 一、创建并发射子弹 二、优化子弹 效果 步骤 一、创建并发射子弹 1. 在前面的文章中&#xff08;【UE5.1 角色练习】06-角色发射火球-part1&#xff09;我们创建了蓝图“BP_Skill_FireBall” 这里我们复制一份命名为“BP_Ammo_5mm”&#xff0c;用于表示…

【算法】单调队列

一、什么是单调队列 单调队列是一种数据结构&#xff0c;其特点是队列中的元素始终保持单调递增或递减&#xff0c;主要用于维护队列中的最小值或最大值。 不同于普通队列只能从队头出队、队尾入队&#xff0c;单调队列为了维护其特征&#xff0c;还允许从队尾出队 不管怎么…

【每日一练】python之sum()求和函数实例讲解

在Python中&#xff0c; sum()是一个内置函数&#xff0c;用于计算可迭代对象&#xff08;如列表、元组等&#xff09;中所有元素的总和。如下实例&#xff1a; """ 收入支出统计小程序 知识点:用户输入获取列表元素添加sum()函数&#xff0c;统计作用 "&…

我的六天C++外出学习记

第一天 7月7日 星期日 早晨&#xff0c;我早早起来了&#xff0c;穿好衣服吃完饭就出发了。 我从家到学校用了1H&#xff0c;迟到了&#xff01;我急急忙忙去报到。 我们中午和晚上的饭菜虽说有点贵&#xff0c;但实在太美味了&#xff0c;和我们原本初中的饭菜相比&#…

计算机视觉领域的基础模型

参考&#xff1a;计算机视觉领域的基础模型 (qq.com) 注意&#xff1a;本文只做笔记&#xff0c;不做搬运 将CV&#xff08;Computer Vision&#xff09;分为四类&#xff1a; 传统模型&#xff1a;只有图像输入&#xff0c;使用Transformer架构和自监督学习方法。文本提示模…

力扣-排序算法

排序算法&#xff0c;一般都可以使用std&#xff1a;&#xff1a;sort&#xff08;&#xff09;来快速排序。 这里介绍一些相关的算法&#xff0c;巩固记忆。 快速排序 跟二分查找有一丢丢像。 首先选择一个基准元素&#xff0c;一般就直接选择第一个。然后两个指针&#xff0c…

Spring的AOP进阶。(AOP的通知类型、通知顺序、切入点表达式和连接点。)

3. AOP进阶 AOP的基础知识学习完之后&#xff0c;下面我们对AOP当中的各个细节进行详细的学习。主要分为4个部分&#xff1a; 通知类型通知顺序切入点表达式连接点 我们先来学习第一部分通知类型。 3.1 通知类型 在入门程序当中&#xff0c;我们已经使用了一种功能最为强大…

QT creator与VS2019 QT加载模块方法

QT creator与VS2019加载模块方法 QT creator&#xff0c;pro文件添加 VS2019 QT

c语言指针超详解——入门篇

文章目录 前言1. 内存与地址内存编址 2. 指针变量和地址取地址操作符 &指针变量和解引用操作符 *指针变量解引用操作符指针变量的大小 3. 指针变量类型的意义指针的解引用指针-整数void* 指针 4. const 修饰指针const 修饰指针指向的变量const 修饰指针变量 5. 指针运算指针…

家具展示预约小程序对线上生意有什么用

沙发、茶几、衣柜等各种家具用品是每个家庭必备的&#xff0c;尤其是新房更需要&#xff0c;且在客户消费能力方面通常预算也比较足&#xff0c;市场中大小品牌比较多&#xff0c;以商场店、独立门店、线上电商平台经营为主。 在实际经营中&#xff0c;厂商和经销商都需要找到…

浪潮天启防火墙TQ2000远程配置方法SSL-V偏、L2xx 配置方法

前言 本次设置只针对配置V偏&#xff0c;其他防火墙配置不涉及。建议把防火墙内外网都调通后再进行V偏配置。 其他配置可参考&#xff1a;浪潮天启防火墙配置手册 配置SSLVxx 在外网端口开启SSLVxx信息 开启SSLVxx功能 1、勾选 “启用SSL-Vxx” 2、设置登录端口号&#xff0…

linux宝塔负载状态100%解决办法

宝塔面板负载状态显示100% 接着使用top命令查看了一下&#xff0c;发现cpu利用率很低&#xff0c;load却很高 通过使用 ps -axjf命令查看是否存在D状态进程 D 状态是指不可中断的睡眠状态&#xff0c;该状态的进程无法被 kill&#xff0c;也无法自行退出&#xff0c;只能通过恢…

Zabbix配置JAVA JMX监控

JAVA JMX监控简介 官方文档&#xff1a;https://www.zabbix.com/documentation/current/zh/manual/concepts/java Zabbix Java gateway以 Zabbix 守护进程方式原生支持监控 JMX 应用程序。Zabbix Java gateway 的守护进程是用 Java 编写。为了在特定主机上找到 JMX 计数器的值…

【JavaScript】解决 JavaScript 语言报错:Uncaught TypeError: XYZ is not a function

文章目录 一、背景介绍常见场景 二、报错信息解析三、常见原因分析1. 变量或对象属性类型错误2. 函数名拼写错误或覆盖3. 作用域问题导致的函数未定义4. 调用未初始化的函数 四、解决方案与预防措施1. 确保变量类型正确2. 检查拼写错误3. 注意作用域4. 初始化变量 五、示例代码…

OrangePi AIpro 浅上手及AI体验

前言 很高兴&#xff0c;收到了一份新款 OrangePi AIpro 开发板&#xff0c;这是香橙派第一次与华为昇腾合作&#xff0c;使用昇腾系列 AI 处理器来设计这款高性价比的 AI 开发板。这块开发板不仅性能强大&#xff0c;还支持丰富的硬件接口&#xff0c;为AI开发者提供了一个理…

BI佐罗,居然抄袭洗稿我的文章

必须曝光此博主不当行径。 4月2日这天发表的原创文章&#xff1a;BI报表系统建设10大坑&#xff0c;因为都是切身的实际项目经验总结&#xff0c;获得了很多人的关注。 我觉得写文章要写的是亲身、真的做过的专业的项目经验&#xff0c;而不是信口开河随口忽悠。 如果有些博…

新手-前端生态

文章目录 新手的前端生态一、概念的理解1、脚手架2、组件 二、基础知识1、HTML2、css3、JavaScript 三、主流框架vue3框架 四、 工具&#xff08;特定框架&#xff09;1、uinapp 五、组件库&#xff08;&#xff09;1、uView如何在哪项目中导入uView 六、应用&#xff08;各种应…

240712_昇思学习打卡-Day24-LSTM+CRF序列标注(3)

240712_昇思学习打卡-Day24-LSTMCRF序列标注&#xff08;3&#xff09; 今天做LSTMCRF序列标注第三部分&#xff0c;同样&#xff0c;仅作简单记录及注释&#xff0c;最近确实太忙了。 Viterbi算法 在完成前向训练部分后&#xff0c;需要实现解码部分。这里我们选择适合求解…

为Linux设置GRUB密码

正文共&#xff1a;999 字 11 图&#xff0c;预估阅读时间&#xff1a;1 分钟 我们前面介绍了如何恢复root密码&#xff08;CentOS 7.9遗忘了root密码怎么办&#xff1f;&#xff09;&#xff0c;虽然简单好用&#xff0c;但是可能会被不法分子利用&#xff0c;造成root密码以及…