曲线生成 | 图解Reeds-Shepp曲线生成原理(附ROS C++/Python/Matlab仿真)

目录

  • 0 专栏介绍
  • 1 什么是Reeds-Shepp曲线?
  • 2 Reeds-Shepp曲线的运动模式
  • 3 Reeds-Shepp曲线算法原理
    • 3.1 坐标变换
    • 3.2 时间翻转(time-flip)
    • 3.3 反射变换(reflect)
    • 3.4 后向变换(backwards)
  • 4 仿真实现
    • 4.1 ROS C++实现
    • 4.2 Python实现
    • 4.3 Matlab实现

0 专栏介绍

🔥附C++/Python/Matlab全套代码🔥课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索、采样法、智能算法等);局部规划(DWA、APF等);曲线优化(贝塞尔曲线、B样条曲线等)。

🚀详情:图解自动驾驶中的运动规划(Motion Planning),附几十种规划算法


1 什么是Reeds-Shepp曲线?

Reeds-Shepp曲线是一种用于描述在平面上从一个点到另一个点最优路径的数学模型。这种曲线是由美国数学家 J. A. Reeds 和 L. A. Shepp 在1990年提出的,它被广泛应用于路径规划和运动规划问题中。Reeds-Shepp曲线的很多原理和Dubins曲线类似,可以先学习曲线生成 | 图解Dubins曲线生成原理(附ROS C++/Python/Matlab仿真)

在这里插入图片描述

Reeds-Shepp曲线具有以下特点:

  • 最优性:Reeds-Shepp曲线是连接两个点的最短路径之一,通常是沿着曲线长度最短的路径。相比于Dubins曲线只允许车辆向前运动,RS曲线同时允许车辆前向、后向运动,使得在某些情况下可以得出比 Dubins 曲线更优的解
  • 约束性:曲线遵循机器人或车辆的运动学约束,例如最大转角、最大速度等。
  • 多样性:存在不同类型的Reeds-Shepp曲线,例如直线-圆弧-直线(L-S-L)、直线-圆弧-反向圆弧-直线(L-S-R-S)等,以适应不同场景下的路径规划需求。

通过计算和生成Reeds-Shepp曲线,可以帮助机器人或车辆高效地规划路径并完成复杂的运动任务。

2 Reeds-Shepp曲线的运动模式

经过证明,RS曲线从起点到终点的最短路径一定是下面的组合之一

{ C ∣ C ∣ C , C C ∣ C , C ∣ C C , C S C , C C β ∣ C β C , C ∣ C β C β ∣ C , C ∣ C π / 2 S C , C S C π / 2 ∣ C , C ∣ C π / 2 S C π / 2 ∣ C } \left\{ \begin{array}{c} C|C|C, CC|C, C|CC, CSC, CC_{\beta}|C_{\beta}C, C|C_{\beta}C_{\beta}|C,\\ C|C_{{{\pi}/{2}}}SC, CSC_{{{\pi}/{2}}}|C, C|C_{{{\pi}/{2}}}SC_{{{\pi}/{2}}}|C\\\end{array} \right\} {CCC,CCC,CCC,CSC,CCβCβC,CCβCβC,CCπ/2SC,CSCπ/2C,CCπ/2SCπ/2C}

其中 C C C表示圆弧运动, S S S表示直线运动,|表示车辆运动朝向发生改变。带 π / 2 \pi/2 π/2下标表示该段轨迹弧长对应的角度为 π / 2 \pi/2 π/2,带 β \beta β下标表示相邻两段轨迹弧长对应的角度相等。将上述组合完整展开后对应如表所示的48种运动模式,其中+代表前行,-代表倒车。后续经过证明, ( L − R + L − ) \left( L^-R^+L^- \right) (LR+L) ( R − L + R − ) \left( R^-L^+R^- \right) (RL+R)两种序列是多余的。

在这里插入图片描述

RS曲线在实现上的复杂度远远高于只有6种组合的Dubins曲线,考虑到序列间的对称关系,引入下面的变换简化曲线求解过程。

3 Reeds-Shepp曲线算法原理

3.1 坐标变换

类似Dubins曲线的思想进行坐标变换。在全局坐标系 x O y xOy xOy中,设机器人起始位姿 p s \boldsymbol{p}_s ps、终止位姿 p g \boldsymbol{p}_g pg、最小转弯半径分别为 ( x s , y s , α ) \left( x_s,y_s,\alpha \right) (xs,ys,α) ( x g , y g , β ) \left( x_g,y_g,\beta \right) (xg,yg,β) R R R。以 p s \boldsymbol{p}_s ps为新坐标系原点,位姿角 α \alpha α方向为 x ′ x' x轴,垂直方向为 y ′ y' y轴建立新坐标系 ,同样考虑归一化最小转弯半径

p s ′ = [ 0 0 0 ] , p g ′ = [ ( x g cos ⁡ β + y g sin ⁡ β ) R ( − x g sin ⁡ β + y g cos ⁡ β ) R β − α ] \boldsymbol{p}_{s}^{'}=\left[ \begin{array}{c} 0\\ 0\\ 0\\\end{array} \right] , \boldsymbol{p}_{g}^{'}=\left[ \begin{array}{c} \left( x_g\cos \beta +y_g\sin \beta \right) R\\ \left( -x_g\sin \beta +y_g\cos \beta \right) R\\ \beta -\alpha\\\end{array} \right] ps= 000 ,pg= (xgcosβ+ygsinβ)R(xgsinβ+ygcosβ)Rβα

3.2 时间翻转(time-flip)

将计算曲线的运动方向全部取反,得到的新曲线与原曲线具有时间翻转关系。如图所示,以 L − R + S + L + ↔ L + R − S − L − L^-R^+S^+L^+\leftrightarrow L^+R^-S^-L^- LR+S+L+L+RSL为例解释时间翻转:设实现了对 L − R + S + L + L^-R^+S^+L^+ LR+S+L+的计算 f ( x , y , ϕ ) f\left( x,y,\phi \right) f(x,y,ϕ),若用同样的函数计算 f ( − x , y , − ϕ ) f\left( -x,y,-\phi \right) f(x,y,ϕ),并将各段路径取反,则等价于以轨迹 L + R − S − L − L^+R^-S^-L^- L+RSL到达 ( x , y , ϕ ) \left( x,y,\phi \right) (x,y,ϕ)

在这里插入图片描述

3.3 反射变换(reflect)

将计算曲线的圆周运动类型全部取反,得到的新曲线与原曲线具有反射变换关系。如图所示,以 L − R + S + L + ↔ R − L + S + R + L^-R^+S^+L^+\leftrightarrow R^-L^+S^+R^+ LR+S+L+RL+S+R+为例解释仿射变换:设实现了对 L − R + S + L + L^-R^+S^+L^+ LR+S+L+的计算 f ( x , y , ϕ ) f\left( x,y,\phi \right) f(x,y,ϕ),若用同样的函数计算 f ( x , − y , − ϕ ) f\left( x,-y,-\phi \right) f(x,y,ϕ),并将圆弧段类型取反,则等价于以轨迹 R − L + S + R + R^-L^+S^+R^+ RL+S+R+到达 ( x , y , ϕ ) \left( x,y,\phi \right) (x,y,ϕ)

在这里插入图片描述

3.4 后向变换(backwards)

将计算曲线的轨迹段逆序,得到的新曲线与原曲线具有后向变换关系。如图所示,以 L − R + S + L + ↔ L + S + R + L − L^-R^+S^+L^+\leftrightarrow L^+S^+R^+L^- LR+S+L+L+S+R+L为例解释后向变换:设实现了对 L − R + S + L + L^-R^+S^+L^+ LR+S+L+的计算 f ( x , y , ϕ ) f\left( x,y,\phi \right) f(x,y,ϕ),若用同样的函数计算 f ( x cos ⁡ ϕ + y sin ⁡ ϕ , x sin ⁡ ϕ − y cos ⁡ ϕ , ϕ ) f\left( x\cos \phi +y\sin \phi ,x\sin \phi -y\cos \phi ,\phi \right) f(xcosϕ+ysinϕ,xsinϕycosϕ,ϕ),并将计算曲线逆序,则等价于以轨迹 L + S + R + L − L^+S^+R^+L^- L+S+R+L到达 ( x , y , ϕ ) \left( x,y,\phi \right) (x,y,ϕ)

在这里插入图片描述

4 仿真实现

4.1 ROS C++实现

核心代码如下所示

Points2d ReedsShepp::generation(Pose2d start, Pose2d goal)
{...// coordinate transformation...// select the best motionRSPath best_path({ REEDS_SHEPP_MAX }, { REEDS_SHEPP_NONE });_update(SCS(x, y, dyaw), best_path);_update(CCC(x, y, dyaw), best_path);_update(CSC(x, y, dyaw), best_path);_update(CCCC(x, y, dyaw), best_path);_update(CCSC(x, y, dyaw), best_path);_update(CCSCC(x, y, dyaw), best_path);if (best_path.len() == REEDS_SHEPP_MAX)return path;// interpolationint points_num = int(best_path.len() / step_) + 6;int i = 0;for (size_t j = 0; j < best_path.size(); j++){int m;double seg_length;best_path.get(j, seg_length, m);// path incrementdouble d_l = seg_length > 0.0 ? step_ : -step_;double x = path_x[i];double y = path_y[i];double yaw = path_yaw[i];// current path lengthdouble l = d_l;while (fabs(l) <= fabs(seg_length)){i += 1;std::tie(path_x[i], path_y[i], path_yaw[i]) = interpolate(m, l, { x, y, yaw });l += d_l;}i += 1;std::tie(path_x[i], path_y[i], path_yaw[i]) = interpolate(m, seg_length, { x, y, yaw });}// remove unused data...// coordinate transformation...return path;
}

4.2 Python实现

核心代码如下所示

def generation(self, start_pose: tuple, goal_pose: tuple):sx, sy, syaw = start_posegx, gy, gyaw = goal_pose# coordinate transformation...# select the best motionplanners = [self.SCS, self.CCC, self.CSC, self.CCCC, self.CCSC, self.CCSCC]best_path, best_cost = None, float("inf")for planner in planners:paths = planner(x, y, dyaw)for path in paths:if path.path_length < best_cost:best_path, best_cost = path, path.path_length# interpolationpoints_num = int(best_cost / self.step) + len(best_path.lengths) + 3x_list = [0.0 for _ in range(points_num)]y_list = [0.0 for _ in range(points_num)]yaw_list = [0.0 for _ in range(points_num)]i = 0for mode_, seg_length in zip(best_path.ctypes, best_path.lengths):# path incrementd_length = self.step if seg_length > 0.0 else -self.stepx, y, yaw = x_list[i], y_list[i], yaw_list[i]# current path lengthlength = d_lengthwhile abs(length) <= abs(seg_length):i += 1x_list[i], y_list[i], yaw_list[i] = self.interpolate(mode_, length, (x, y, yaw))length += d_lengthi += 1x_list[i], y_list[i], yaw_list[i] = self.interpolate(mode_, seg_length, (x, y, yaw))# failed...# remove unused data...# coordinate transformation...return best_cost / self.max_curv, best_path.ctypes, x_list_, y_list_, yaw_list_

在这里插入图片描述

4.3 Matlab实现

核心代码如下所示

function [x_list, y_list, yaw_list] = generation(start_pose, goal_pose, param)  % coordinate transformation...% select the best motionplanners = ["SCS", "CCC", "CSC", "CCCC", "CCSC", "CCSCC"];best_cost = inf;best_path = [];for i=1:length(planners)planner = str2func(planners(i));paths = planner(x, y, dyaw);for j=1:length(paths)if paths(j).len < best_costbest_path = paths(j);best_cost = paths(j).len;endendend% interpolationpoints_num = floor(best_cost / param.step) + length(best_path.segs) + 3;x_list_ = zeros(points_num);y_list_ = zeros(points_num);yaw_list_ = zeros(points_num);i = 1;for j = 1:length(best_path.segs)m = best_path.ctypes(j);seg_length = best_path.segs(j);% path incrementif seg_length > 0.0d_length = param.step;elsed_length = -param.step;endx = x_list_(i); y = y_list_(i); yaw = yaw_list_(i);% current path lengthl = d_length;while abs(l) <= abs(seg_length)i = i + 1;new_pt = interpolate(m, l, [x, y, yaw], param);x_list_(i) = new_pt(1); y_list_(i) = new_pt(2); yaw_list_(i) = new_pt(3);l = l + d_length;endi = i + 1;new_pt = interpolate(m, seg_length, [x, y, yaw], param);x_list_(i) = new_pt(1); y_list_(i) = new_pt(2); yaw_list_(i) = new_pt(3);end% remove unused data...% coordinate transformation...
end

在这里插入图片描述

完整工程代码请联系下方博主名片获取


🔥 更多精彩专栏

  • 《ROS从入门到精通》
  • 《Pytorch深度学习实战》
  • 《机器学习强基计划》
  • 《运动规划实战精讲》

👇源码获取 · 技术交流 · 抱团学习 · 咨询分享 请联系👇

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何利用社媒群组如何高效开发国外客户

现在社媒营销也是越来越流行了&#xff0c;很多外贸人都开始做社媒营销。社媒营销相对来说是比较有温度的一个营销&#xff0c;因为大部分社媒平台都支持在线聊天&#xff0c;触达的即时性是比较高的&#xff0c;效果也比传统的一些方法要好一些。 当然做社媒也是有难度的&…

西藏实景三维技术研讨交流会成功举办

2024年3月21-22日&#xff0c;西藏自治区“实景三维技术研讨交流会”在拉萨成功举办。 本次会议由西藏自治区自然资源厅、自然资源部重庆测绘院指导&#xff0c;西藏自治区测绘学会、西藏自治区地理信息产业协会主办&#xff0c;武汉大势智慧科技有限公司&#xff08;后简称“…

数据库-索引快速学

索引 当表中数据量庞大时&#xff0c;往往搜索一条数据就会耗费很长的时间等待 索引是帮助数据库高效获取数据的数据结构 create index 索引名 on 数据表名&#xff08;字段名&#xff09;;为该表下的某一字段创建索引&#xff0c;检索耗时会大大的减小 索引的优缺点 优点&…

【Python BUG】CondaHTTPError解决记录

问题描述 CondaHTTPError: HTTP 429 TOO MANY REQUESTS for url https://mirrors.ustc.edu.cn/anaconda/pkgs/free/win-64/current_repodata.json Elapsed: 00:26.513315 解决方案 找到用户路径下的 .condarc文件&#xff0c;建议用这个方法前和我一样做个备份&#xff0c;方…

python中类的导入与使用

1、类的介绍 与C中面向对象思想类似&#xff0c;有时候为了方便&#xff0c;需要专门创建一个类&#xff0c;将相关的函数全部写入到该类中&#xff0c;方便后续创建对象&#xff0c;再使用类中函数。那么如何创建完类&#xff0c;在其他文件中使用类中函数&#xff0c;这是这篇…

Python Flask框架 -- flask-migrate迁移ORM模型

# 之前使用的这个db.create_all()很有局限性&#xff0c;它不能把在class里修改的东西同步上数据库&#xff0c;所以不用了 # with app.app_context(): # 请求应用上下文 # db.create_all() # 把所有的表同步到数据库中去 例如&#xff0c;在User类中增加一个email字段&…

STM32和GD32内部时钟与外部时钟讲解

STM32F103为例: 1. 当 HSI 被用作 PLL 时钟输入时,可以实现的最大系统时钟频率为 64 MHz。 2. 要使 USB 功能可用,必须同时启用 HSE 和 PLL,并使 USBCLK 运行在 48 MHz。 3. 要实现 ADC 转换时间为 1 s,APB2 必须为 14 MHz、28 MHz 或 56 MHz。 ①. HSE = 高速外部时钟信号…

[linux初阶][vim-gcc-gdb] OneCharter: vim编辑器

一.vim编辑器基础 目录 一.vim编辑器基础 ①.vim的语法 ②vim的三种模式 ③三种模式的基本切换 ④各个模式下的一些操作 二.配置vim环境 ①手动配置(不推荐) ②自动配置(推荐) vim是vi的升级版,包含了更加丰富的功能. ①.vim的语法 vim [文件名] ②vim的三种模式 命令…

爬取搜狗翻译项目实例

视频中讲解的是百度翻译&#xff0c;但是视频中的方法现在已经不适用了&#xff0c;因为他们对 URL 的参数进行了修改&#xff0c;导致没法直接修改参数来爬取对应的翻译结果&#xff0c;这里我使用搜狗翻译来做演示&#xff0c;原理是一样的。 我们搜索的关键字会返回在 URL 中…

家用超声波清洗机高端品牌推荐!4款值得入手的热门超声波清洗机

急着洗眼镜的朋友先不要慌&#xff0c;虽然洗眼镜是日常生活中最常见的操作&#xff0c;但是在清洗眼镜方面也是有讲究的&#xff0c;不是随随便便把眼镜擦一下就算清洁干净了&#xff01;因为我们拿眼镜布擦眼镜的时候&#xff0c;布料粗糙的微粒就会跟砂纸一样打磨着镜片&…

【python】flask模板渲染引擎Jinja2中的模板继承,简化前端模块化开发

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

什么是Prompt Tuning?

本文是观看视频What is Prompt Tuning?后的笔记。 大语言模型&#xff08;如ChatGPT &#xff09;是基础模型&#xff0c;是经过互联网上大量知识训练的大型可重用模型。 他们非常灵活&#xff0c;同样的模型可以分析法律文书或撰写文章。 但是&#xff0c;如果我们需要用其解…

cocos3.0 关于UI组件学习

Sprite 图片&#xff1a;官方文档 Size Mode: 1.Raw&#xff1a;原始大小 2.TRIMMED: 默认&#xff0c;会裁切原始图片透明像素 3.Custom&#xff1a;自定义&#xff0c;只要修改ContentSize&#xff0c;会自动设置 Type 1.Simple:普通,会铺满&#xff0c;一张图。 2.Sliced…

力扣热门算法题 89. 格雷编码,92. 反转链表 II,93. 复原 IP 地址

89. 格雷编码&#xff0c;92. 反转链表 II&#xff0c;93. 复原 IP 地址&#xff0c;每题做详细思路梳理&#xff0c;配套Python&Java双语代码&#xff0c; 2024.03.24 可通过leetcode所有测试用例。 目录 89. 格雷编码 解题思路 完整代码 Python Java 92. 反转链表…

苹果智能戒指专利获批,Find My功能为智能穿戴提供智能防丢

根据美国商标和专利局&#xff08;USPTO&#xff09;近日公示的清单&#xff0c;苹果公司获得了一项关于智能戒指的专利&#xff0c;展示了多种交互手势&#xff0c;不仅支持捏合、画圈等&#xff0c;而且支持玩“石头剪刀布”游戏。 这项新专利名为“皮肤间接触检测”&#xf…

南京观海微电子---Vitis HLS设计流程介绍——Vitis HLS教程

1. 传统的FPGA设计流程 传统的RTL设计流程如下图所示&#xff1a; 传统的FPGA RTL设计流程主要是采用VHDL、VerilogHDL或System Verilog进行工程的开发&#xff0c;同时也是通过硬件描述语言来编写测试案例&#xff08;Test Bench&#xff09;对开发的工程进行仿真验证。 随后…

基于单片机热电偶智能体温检测系统设计

**单片机设计介绍&#xff0c;基于单片机热电偶智能体温检测系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机热电偶智能体温检测系统设计概要 一、引言 本系统旨在通过单片机实现对人体体温的智能检测&#…

一文教你学会用群晖NAS配置WebDAV服务结合内网穿透实现公网同步Zotero文献库

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件&#xff0c;能轻易的部署微服务。它支持多种后端 (D…

电缆故障测试仪的原理和组成部件分别是什么?

电缆故障测试仪是专为检测电缆线路中的各种故障而设计制造的精密电子设备&#xff0c;广泛应用于电力、通信、石油化工、航空航天等领域。这类仪器的工作原理和组成相对复杂&#xff0c;下面将详细阐述。 电缆故障测试仪的工作原理 电缆故障测试仪的核心原理通常涉及电磁波反…

【C语言】 gets()puts()fgets()fputs()字符串输入输出函数的用法

文章目录 C语言中的字符串输入输出函数&#xff1a;gets、puts、fgets与fputsgets函数puts函数fgets函数fputs函数 C语言中的字符串输入输出函数知识点总结结语 C语言中的字符串输入输出函数&#xff1a;gets、puts、fgets与fputs 在C语言中&#xff0c;处理字符串的输入和输出…