news 2026/2/10 7:16:11

从零学自动驾驶lattice规划(上)--参考线,frenet标架,多项式拟合 算法详细文档说...

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零学自动驾驶lattice规划(上)--参考线,frenet标架,多项式拟合 算法详细文档说...

从零学自动驾驶lattice规划(上)--参考线,frenet标架,多项式拟合 算法详细文档说明。 2种代码实现:matlab和c++

刚摸自动驾驶那会儿总被轨迹规划绕得头疼,直到遇见Lattice算法——这货居然能把复杂的路径拆成纵向横向两个维度来思考。今天咱们先搞明白前置知识:参考线怎么生成、Frenet坐标系究竟香在哪、多项式凭什么能拟合轨迹。手撸Matlab和C++两版代码,带你在坐标系转换的坑里爬出来。


一、参考线:车道线的灵魂骨架

没有参考线的规划就像没画线的马路,车子根本不知道往哪靠。实际项目中参考线通常由高精地图的车道中心线点序列生成,但咱们自己玩可以用三次样条插值:

Matlab暴力美学版

% 随便扔几个离散点 raw_points = [0,0; 2,1; 5,2; 7,0]; x = raw_points(:,1); y = raw_points(:,2); % 三次样条直接出平滑曲线 t = 1:0.1:length(x); ref_line = spline(x, y, t);

spline函数自动生成C2连续(加速度连续)的曲线,这对规划模块的舒适性至关重要。

C++实战版

#include <tk_spline.h> // 第三方库 vector<Point2d> raw_points = {{0,0}, {2,1}, {5,2}, {7,0}}; tk::spline s; s.set_points(raw_points.x(), raw_points.y()); // 采样时直接s(x_coord)获得y值

注意这里用到了开源的样条库,比手写矩阵求解省事得多。生成的参考线在x=3.5处的曲率变化率必须小于0.1,否则乘客会晕车——这是车企的硬指标。


二、Frenet坐标系:老司机的分割视角

笛卡尔坐标系下同时处理横向偏移和纵向距离简直要命,Frenet把这两个维度拆开处理:

!Frenet坐标系示意图

坐标系转换核心代码

function [s, d] = cart2frenet(x, y, ref_line) % 找最近参考点 [~, idx] = min(sum((ref_line - [x,y]).^2, 2)); s = cum_dist(ref_line(1:idx,:)); % 累计距离 vec_t = ref_line.tangent_at(idx); % 参考线切向 d = cross([vec_t,0], [x-ref_line.x(idx), y-ref_line.y(idx),0]); d = d(3); % 取z分量 end

这里有个魔鬼细节:计算最近点时直接用欧式距离会翻车,应该用投影到参考线的近似距离。C++版用Eigen库实现更高效:

struct FrenetConverter { const ReferenceLine& ref_line; FrenetPoint convert(const CartesianPoint& p) { auto proj = ref_line.FindProjection(p); return {proj.s, proj.l}; // l即横向偏移d } };

实际工程中要考虑参考线的方向,当车辆逆行驶方向时s坐标会减小,这时候需要做方向判断。


三、五次多项式:让轨迹丝滑的秘诀

横向规划常用五次多项式,因为它能满足位置、速度、加速度三阶约束:

d(s) = a0 + a1s + a2s² + a3s³ + a4s⁴ + a5*s⁵

Matlab拟合演示

% 起点终点约束 s0 = 0; d0 = 2; d0_dot = 0; d0_ddot = 0; s1 = 10; d1 = 0; d1_dot = 0; d1_ddot = 0; A = [s0^0 s0^1 s0^2 s0^3 s0^4 s0^5; 0 1 2*s0 3*s0^2 4*s0^3 5*s0^4; 0 0 2 6*s0 12*s0^2 20*s0^3; ... ]; % 构造6x6矩阵 b = [d0; d0_dot; d0_ddot; d1; d1_dot; d1_ddot]; coeffs = A\b; % 解线性方程组

C++暴力解方程

Eigen::MatrixXd A(6,6); Eigen::VectorXd b(6); // 填充约束条件... Eigen::VectorXd coeffs = A.colPivHouseholderQr().solve(b);

为什么不用三次多项式?因为车辆运动学模型中加速度变化率(jerk)影响舒适性,五次多项式可保证jerk连续。


下篇预告:如何把上面这些零件组装成完整的Lattice规划器,并解决轨迹冲突检测的玄学问题。代码仓库已准备好Matlab和CMake两套环境配置指南,需要的老铁评论区打个卡。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/7 5:57:39

PyTorch DataLoader worker_init_fn初始化函数用途

PyTorch DataLoader worker_init_fn 初始化函数用途 在现代深度学习训练中&#xff0c;数据加载早已不再是简单的“读文件、喂模型”过程。随着批大小增大、数据增强策略复杂化以及多卡分布式训练的普及&#xff0c;我们对数据管道的稳定性、效率和可复现性提出了更高要求。尤其…

作者头像 李华
网站建设 2026/2/8 10:05:45

LLMs之VF:《Asking LLMs to Verify First is Almost Free Lunch》翻译与解读

LLMs之VF&#xff1a;《Asking LLMs to Verify First is Almost Free Lunch》翻译与解读 导读&#xff1a;本研究提出了一种名为“验证优先”&#xff08;Verification-First, VF&#xff09;的创新提示策略&#xff0c;旨在以极低的成本显著提升大型语言模型&#xff08;LLM&a…

作者头像 李华
网站建设 2026/2/10 16:11:02

PyTorch Lightning与原生PyTorch对比优劣分析

PyTorch Lightning与原生PyTorch对比优劣分析 在深度学习项目开发中&#xff0c;一个常见的困境是&#xff1a;刚写完的实验代码还没来得及复现结果&#xff0c;就已经因为冗长的训练循环、设备管理混乱和日志缺失而变得难以维护。更别提当团队协作时&#xff0c;每个人都有自己…

作者头像 李华
网站建设 2026/2/5 10:44:29

Keil5 Debug调试怎么使用实现PID控制回路的图解说明

如何用Keil5调试实现PID控制回路的图解式开发&#xff1f;——从变量监控到波形可视化一个常见的工程困境&#xff1a;PID调参靠“烧录猜”你有没有过这样的经历&#xff1f;写好了温度控制程序&#xff0c;下载进STM32板子&#xff0c;启动加热后却发现&#xff1a;- 温度冲过…

作者头像 李华
网站建设 2026/2/4 0:44:13

嵌入式通信入门:CANFD与CAN的关键差异解析

嵌入式通信进阶&#xff1a;为什么CANFD正在取代CAN&#xff1f; 你有没有遇到过这样的情况&#xff1f;在调试一个车载ECU时&#xff0c;总线负载突然飙升到80%以上&#xff0c;CPU中断频繁触发&#xff0c;系统响应变慢——而你只是想传一组雷达点云数据。问题出在哪&#x…

作者头像 李华
网站建设 2026/2/10 23:37:16

2026前端突破指南:为什么理解系统比背API更重要?

2025年底,我在掘金上看到一个提问:"学了三年React,换到Vue项目组完全懵了,是不是要重新学?"这个问题下面有237条回复,大部分都在说"正常,我也是这样"。但这不正常。如果你真的理解了React,切换到Vue应该只需要2-3天,而不是"重新学"。问题出在哪…

作者头像 李华