纯跟踪(Pure Pursuit)路径跟踪算法研究(2)
纯跟踪(Pure Pursuit)路径跟踪算法研究(2)
下午进行了简单的公式推导,理论推导部分是没有问题的


下面的博客提供了在实车上用 GPS 实现纯跟踪控制的一些思路和注意点
Pure Pursuit(纯追踪算法)ROS实践
并不急于在实车上实现,第一步实现 CarSim 于 Simulink 的联合仿真
下面几篇博客主要是用Python模拟,读着稍微有点困难
无人驾驶汽车系统入门(十八)——使用pure pursuit实现无人车轨迹追踪
无人驾驶运动控制----pure pursuit算法实践和理解
自主跟随学习笔记(一)使用纯跟踪(pure pursuit)算法跟随目标
下面的博客介绍了纯跟踪的原理以及在开源框架 Autoare 中的实现
自动驾驶Motion Planning—Pure Pursuit算法原理及实现

Pure Pursuit算法的基本思想是:参考人类驾驶的行为,通过计算车辆当前位置到预瞄点(goal point)的曲率,使车辆沿着经过预瞄点的圆弧行驶,从而实现轨迹跟踪(如图1)。因此,该算法的核心在于通过设计合理的预瞄距离,从而计算出轨迹跟踪的控制曲率

Pure Pursuit本质上是一个基于横向误差控制的比例控制器
预瞄点(goal point)的选择
如何从路径点中选择预瞄点并且保证预瞄点在行驶方向的前方而不是反方向,还不清楚


预瞄距离(Ld)的选择

Pure Pursuit的效果强依赖于预瞄距离的选择,可根据车速动态的调整预瞄距离,从而增强系统的控制鲁棒性
下面的代码是基于上面的 Python 代码,用 MATLAB 实现了下,但代码并不完整
自动驾驶—基于运动学模型约束的纯跟踪控制算法 Pure Pursiut
纯跟踪算法是一种基于运动学约束的算法,对该算法的学习可以更好地理解车辆运动学模型。根据上一文档的讲解,我们可以建立后轮速度、前轮偏角和车辆大地坐标系下的位置、航向角的关系,那么我们在忽略轮胎力学、执行机构特性等情况下,就能根据后轮速度和前轮偏角任意控制车辆的速度、位置。本文只讨论横向控制,假设后轮速度恒定,也就是只控制前轮偏角
首先也应当实现当车辆后轮速度恒定,即车辆纵向速度恒定下的纯跟踪控制
纯跟踪算法提出“预瞄距离”的概念,根据预瞄距离寻找目标轨迹中符合条件的目标路径点,判断逻辑就是寻找目标轨迹上哪个点和当前车辆位置(图中的当前后轮位置)的相对距离等于预瞄距离(可以以当前位置为圆心,预瞄距离为半径,画圆,寻找与目标轨迹的交点),则该点就是当前时刻的目标点(图中的目标后轮位置)。控制目标则是计算多大的前轮偏角,可以使当前后轮位置运动到目标后轮位置

恒定后轮速度,恒定前轮偏角,那么后轮的运动轨迹将是一个圆,即车辆绕着转动中心做圆周运动,如下图所示:

基于这个现象,可以认为在每个运行周期内(速度恒定,前轮偏角恒定),车辆绕转动中心做圆周运动。那么控制目标就可以简化为两点:①是怎样的圆周运动轨迹可以将后轮从当前位置运动至目标位置?②如何控制前轮偏角实现这个圆周运动?

下面的博客并没有给出具体的 Simulink 实现,但对预瞄控制的解释还是很生动的
Pure Pursuit(纯跟踪算法)与Simulink实现

如上图所示,A点是车辆后轴中心(也是图中坐标系的原点,图中这种坐标系我们一般称之为:车辆坐标系),B点是车辆要达到的目标点(预瞄点),L是AB之间的距离(预瞄距离),O点是假设存在的圆心使得车辆从位置A以转弯半径r可以达到位置B。圆心位置O的坐标与转弯半径r就是计算目标。此图颇有遗憾,因为AO线段看上去比BO线段长,但二者应该是相等的,都是转弯半径
纯跟踪控制算法就是一种**基于几何关系计算车辆转弯半径**的方法

纯跟踪算法核心计算部分是非常简洁的,不过实际应用时还有两块工作要做:1,从期望轨迹中找预瞄点B,方法是从期望轨迹上找距离A点等于预瞄距离L的点。2,A点与B点坐标可能都是基于某个全局坐标系,所以需要将B点坐标从全局坐标系转换至车辆坐标系上。这两部分计算是使用纯跟踪算法的准备工作
📌 上面所说的两个问题确实是比较关键的问题
全局坐标系到车辆坐标系的变换或许可以参考下面的代码
自动驾驶Motion Planning—Pure Pursuit算法原理及实现

float32_t PurePursuit::compute_points_distance_squared(const TrajectoryPoint & point1,const TrajectoryPoint & point2)
{using autoware::common::types::float64_t;const float64_t diff_x = point1.pose.position.x - point2.pose.position.x;const float64_t diff_y = point1.pose.position.y - point2.pose.position.y;return static_cast<float32_t>((diff_x * diff_x) + (diff_y * diff_y));
}
std::pair<float32_t, float32_t> PurePursuit::compute_relative_xy_offset(const TrajectoryPoint & current,const TrajectoryPoint & target) const
{const auto diff_x = target.pose.position.x - current.pose.position.x;const auto diff_y = target.pose.position.y - current.pose.position.y;const auto yaw = ::motion::motion_common::to_angle(current.pose.orientation);const auto cos_pose = std::cos(yaw);const auto sin_pose = std::sin(yaw);const auto relative_x = static_cast<float32_t>((cos_pose * diff_x) + (sin_pose * diff_y));const auto relative_y = static_cast<float32_t>((-sin_pose * diff_x) + (cos_pose * diff_y));const std::pair<float32_t, float32_t> relative_xy(relative_x, relative_y);return relative_xy;
}
float32_t PurePursuit::compute_steering_rad(const TrajectoryPoint & current_point)
{// Compute the steering angle by arctan(curvature * wheel_distance)// link: https://www.ri.cmu.edu/pub_files/2009/2/// Automatic_Steering_Methods_for_Autonomous_Automobile_Path_Tracking.pdfconst float32_t denominator = compute_points_distance_squared(current_point, m_target_point);const float32_t numerator = compute_relative_xy_offset(current_point, m_target_point).second;constexpr float32_t epsilon = 0.0001F;// equivalent to (2 * y) / (distance * distance) = (2 * sin(th)) / distanceconst float32_t curvature = (denominator > epsilon) ? ((2.0F * numerator) / denominator) : 0.0F;const float32_t steering_angle_rad = atanf(curvature * m_config.get_distance_front_rear_wheel());return steering_angle_rad;
}
车辆当前位置和预瞄点间连线与车辆轴线(前进方向)夹角可以参考下面的公式
《基于纯追踪算法和樽海鞘优化算法的无人驾驶路径跟踪算法研究》


纯跟踪算法的轨迹跟随效果,与参数:预瞄距离关系很大。就像人开车时眼睛往前看多远,看的太近了,到了弯道才慌忙打方向盘;看的太远了,又容易导致最近一段的轨迹跟随效果不好
最后谈一下纯跟踪算法的硬伤:纯跟踪算法可以缩小车辆与期望轨迹的位置偏差,但是对角度偏差束手无策,因为数学原理上根本就没有考虑角度偏差
下面的博客用 MATLAB 跟踪了圆形轨迹,并且测试了大预瞄距离和小预瞄距离的情况
路径跟踪之Pure Pursuit控制算法



减小前视距离,仿真结果如下图所示,可以看出跟踪结果出现了一定程度的震荡,这是因为前视距离减小后,近似P控制器的比例系数增加,从而造成动态响应出现超调和震荡

同时讨论了朝向角 𝛼 == 90度和朝向角 𝛼 > 90度的情况
如果预瞄点如下图所示,那么𝛼大于90度,车辆后轮的运行轨迹应该是大圆,绕了一个大圈,是在向后跟踪,此时的前轮转角计算公式仍然不变

𝛼等于90度的情况,车辆后轮的运行轨迹应该是右上那个半圆

通过以上分析,不难发现,三种情况下的前轮转角计算公式均适用,同样“近似P控制器”这个结论在上述三种情况下也都成立
下面的方法简要分析了 Pure Pursuit、Stanley、MPC 这几种轨迹跟踪控制方法,可以作为后面继续研究的开展
横向自动控制方法:Purepursuit, Stanley, MPC对比
下面的博客给出了 Pure Pursuit 的仿真实现,可以参考学习下,实测可以跑
PurePursuit纯追踪算法MATLAB程序个人总结
Pure Pursuit纯跟踪算法Python/Matlab算法实现
%% 纯跟踪算法跟随效果与预瞄距离关系很大。就像人开车时眼睛往前看多远,看的太近了,到了弯道才慌忙打方向盘;看的太远了,又容易导致最近一段的轨迹跟随效果不好。%% initialization
k = 0.1; % look forward gain 前向预测距离所用增益
Kp = 1.0 ; % speed propotional gain
Lfc = 1; % 基础预瞄距离
dt = 0.1; % [s]
L = 2.9 ; % [m] wheel base of vehicle
cx = 0:0.1:50; %每0.1长度取一次预瞄点的x值for i = 1:length(cx) %全局路径c(y)生成 路径初始化cy(i) = cos(cx(i)/5)*cx(i)/4;
endi = 1;
target_speed = 10/3.6; %设定速度 如果实际自动驾驶,这个就是设定要到达的速度,%附加:目前这里没有规划,如果有规划,就在过弯的时候给出横向加速度,所以车身方向速度就会减小。
T = 500;
lastIndex = length(cx); %返回cx的向量长度 有501个预瞄点x值 有501个序号
x = 0; y = 4; yaw = 0; v = 0; %车辆初始位置
time = 0;
Ld = k * v + Lfc; %初始速度为0时的预瞄距离Ld=Lfcfigure(1);
while T > time target_index = calc_target_index(x,y,cx,cy); %输出距离车辆当前最近的点的位置ai = PIDcontrol(target_speed,v,Kp); %Ld = k * v + Lfc ;delta = pure_pursuit_control(x,y,yaw,v,cx,cy,target_index,k,Lfc,L,Ld); %前轮要转的角度[x,y,yaw,v] = update(x,y,yaw,v, ai, delta,dt,L); %更新车辆状态time = time + dt; %时间过完一周期
% pause(0.1)plot(cx,cy,'b',x,y,'r-*') %将预瞄点位置用蓝色表示,当前位置用红色表示drawnowhold onendfunction [x, y, yaw, v] = update(x, y, yaw, v, ai, delta,dt,L) %更新车辆状态的函数x = x + v * cos(yaw) * dt;y = y + v * sin(yaw) * dt;yaw = yaw + v / L * tan(delta) * dt;v = v + ai * dt;
endfunction [a] = PIDcontrol(target_v, current_v, Kp) %计算加速度的函数
a = Kp * (target_v - current_v);
endfunction [delta] = pure_pursuit_control(x,y,yaw,v,cx,cy,ind,k,Lfc,L,Ld) %纯追踪控制器前轮转角方程的函数tx = cx(ind); %距离车辆当前最近的点的位置对应的cx值 ind是距离车辆当前最近的点的位置ty = cy(ind); %距离车辆当前最近的点的位置对应的cy值alpha = atan((ty-y)/(tx-x))-yaw; %该处定义向左转为alpha=beta-Fai,所以向右转就输出-alphaLd = k * v + Lfc ; % 预瞄距离Ld与车速成线性关系 delta = atan(2*L * sin(alpha)/Ld) ; %前轮转角
endfunction [ind] = calc_target_index(x,y, cx,cy) %计算找到距车辆当前位置最近点的序号 输出最近点的函数
N = length(cx); %N = 501
Distance = zeros(N,1); % 501行 1列的矩阵for i = 1:N
Distance(i) = sqrt((cx(i)-x)^2 + (cy(i)-y)^2); %每一个预瞄点到初始位置的距离
end[~, location]= min(Distance); %找出最近的距离对应的位置
ind = location;
ind = ind + 5
end

实际上 MATLAB 本身也提供了 Pure Pursuit 工具箱
MATLAB Pure Pursuit Controller

GitHub 上也有相关的基于 Gazebo 的仿真
https://github.com/NeXTzhao/planning
相关文章:
纯跟踪(Pure Pursuit)路径跟踪算法研究(2)
纯跟踪(Pure Pursuit)路径跟踪算法研究(2) 下午进行了简单的公式推导,理论推导部分是没有问题的 下面的博客提供了在实车上用 GPS 实现纯跟踪控制的一些思路和注意点 Pure Pursuit(纯追踪算法)ROS实践 并不急于在实车…...
前后端分离------后端创建笔记(02)
本文章转载于【SpringBootVue】全网最简单但实用的前后端分离项目实战笔记 - 前端_大菜007的博客-CSDN博客 仅用于学习和讨论,如有侵权请联系 源码:https://gitee.com/green_vegetables/x-admin-project.git 素材:https://pan.baidu.com/s/…...
Webpack5 Preload/Prefetch技术
文章目录 什么是Preload/Prefetch技术一、Preload:确保必需资源的快速获取二、Prefetch:预加载未来可能使用的资源三、使用注意事项四、Prefetch:总结 什么是Preload/Prefetch技术 在现代Web开发中,页面加载速度对于用户体验至关…...
PHP原生类
什么是php原生类 原生类就是php内置类,不用定义php自带的类,即不需要在当前脚本写出,但也可以实例化的类 我们可以通过脚本找一下php原生类 <?php $classes get_declared_classes(); foreach ($classes as $class) {$methods get_clas…...
QGIS3.28的二次开发八:显示shp的属性表
这里实现两个基本的 GIS 软件需求:矢量图层的属性表显示,以及根据属性筛选要素。 具体需求如下: 加载一个矢量图层并打开其属性表;输入筛选条件确认无误后,画布上和属性表中均只显示筛选后的要素。 QGIS 提供了若干…...
虚拟机安装 Ubuntu桌面版,宿主机无法访问虚拟机 ufw 防火墙简单使用
虚拟机安装 Ubuntu桌面版,宿主机无法访问虚拟机 问题处理安装ssh服务ufw防火墙 放行ssh服务ufw 常用命令 问题 本次安装使用的 ubuntu-22.04.2-desktop-amd64 ,网络连接使用的是桥接,查看ubuntu的ip是正常的,与宿主机在同一个网段…...
jquery发送ajax练习
jquery发送ajax练习 工具代码运行结果 工具 HBuilder X 代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>通过ajax进行图片的提取和显示</title><style>div{background-color: beige;color: red;font-s…...
adb用法,安卓的用户CA证书放到系统CA证书下
设备需root!!设备需root!!设备需root!! 测试环境:redmi 5 plus、miui10 9.9.2dev(安卓8.1)、已root win下安装手机USB驱动(过程略,…...
【LVS-NAT配置】
配置 node1:128(客户端) node2:135(调度器) RS: node3:130 node4:132 node2添加网络适配器(仅主机模式) [rootnode2 ~]# nmtui[rootnode2 ~]#…...
时序预测 | MATLAB实现BO-GRU贝叶斯优化门控循环单元时间序列预测
时序预测 | MATLAB实现BO-GRU贝叶斯优化门控循环单元时间序列预测 目录 时序预测 | MATLAB实现BO-GRU贝叶斯优化门控循环单元时间序列预测效果一览基本介绍模型搭建程序设计参考资料 效果一览 基本介绍 MATLAB实现BO-GRU贝叶斯优化门控循环单元时间序列预测。基于贝叶斯(bayes)…...
注意:阿里云服务器随机分配可用区说明
阿里云服务器如有ICP备案需求请勿选择随机可用区,因为当前地域下的可用区可能不支持备案,阿里云百科分享提醒大家,如果你的购买的云服务器搭建网站应用,网站域名需要使用这台云服务器备案的话,不要随机分配可用区&…...
【Vue】使用print.js插件实现打印预览功能,超简单
目录 一、实现效果 二、实现步骤 【1】安装插件 【2】在需要打印的页面导入 【3】在vue文件中需要打印的部分外层套一层div,给div设置id。作为打印的区域 【4】在打印按钮上添加打印事件 【5】在methods中添加点击事件 三、完整代码 一、实现效果 二、实现步…...
3.5 Spring MVC参数传递
Spring MVC的Controller接收请求参数的方式有多种,本节主要介绍Spring MVC下的HttpServletRequest、基本数据类型、Java Bean、数组、List、Map、JSON参数传递方式,同时解决POST请求中文乱码问题。 1. HttpServletRequest参数传递 Controller RequestM…...
linux程序保护机制gcc编译选项
预备知识: 计算机内存的结构通常包括以下几个主要部分: 1.代码段(Code Segment):也称为文本段,存储程序的可执行指令。代码段是被标记为可执行的,程序从代码段中获取指令并执行。 2.数据段(Data Segment):…...
指针与引用:C语言中的内存魔法
开始本篇文章之前先推荐一个好用的学习工具,AIRIght,借助于AI助手工具,学习事半功倍。欢迎访问:http://airight.fun/。 也把我学习过程中搜集的资料分享给大家,希望可以帮助大家少走弯路,链接:h…...
docker desktop搭建 nginx
【docker 桌面版】windows 使用 docker 搭建 nginx 拉取 nginx 镜像 docker pull nginx运行容器 docker run -d -p 80:8081 --name nginx nginx本地磁盘创建 nginx 目录 D:\DockerRep\nginx复制 docker 中的 nginx 配置文件 查看运行的容器 docker ps -a docker cp 9f0f82d66dd…...
Redis缓存雪崩、击穿、穿透?
我们谈谈Redis在实际项目中用作缓存时经常碰到的,也是经常面试的三大问题:缓存穿透、缓存击穿、缓存雪崩,以及这些问题的常用解决方法。 在介绍这三大问题之前,我们需要先了解Redis作为一个缓存中间件,在项目中是如何…...
Kettle系列(一)下载安装与基础配置
Kettle系列(一)下载安装与基础配置 说明一、下载二、目录结构三、基础配置(1)环境变量(2)kettle配置 四、连接mysql8五、连接其他数据库六、总结 说明 更新时间:2023/08/13 17:47 本文记录了wi…...
MuMu模拟器运行一段时间后Device.Present耗时突然上升
1)MuMu模拟器运行一段时间后Device.Present耗时突然上升 2)如何在运行过程中获得温度信息 3)Input System鼠标更换主按键的Bug 4)如何禁止Unity向https://config.uca.cloud.unity3d.com发送设备信息 这是第347篇UWA技术知识分享…...
14-矩阵相乘及其运算法则
矩阵与向量的乘法 在这一篇文章中我们就将基于上一篇重新审视矩阵的这个视点来理解矩阵的乘法,那么在这一篇,我们主要来看一下矩阵和向量的乘法。这里这个线性方程组是上一小节给大家举的模拟的一个非常简单的小型经济系统的例子,我们可以把…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
