《自动驾驶轨迹规划实战:Lattice Planner实现避障路径生成(附可运行Python代码)》—— 零基础实现基于离散优化的避障路径规划

news2025/6/5 15:47:42

《自动驾驶轨迹规划实战:Lattice Planner实现避障路径生成(附可运行Python代码)》
—— 零基础实现基于离散优化的避障路径规划


一、为什么Lattice Planner成为自动驾驶的核心算法?

在自动驾驶的路径规划领域,Lattice Planner(格子规划器)凭借其结构化采样+动态优化的特性,成为Waymo、Aptiv等头部企业的核心算法。与传统A*、RRT算法不同,Lattice Planner通过横向位移采样+纵向速度规划的复合策略,能够在10ms内生成满足车辆运动学约束的平滑轨迹。本文将手把手实现一个简化版Lattice Planner,并针对经典“避障场景”进行代码级解析。


二、算法原理精讲(附数学推导图示)

2.1 轨迹生成三要素
s(t) = s_0 + v_0 t + \frac{1}{2}a t^2 \quad \text{(纵向运动方程)}
d(s) = c_0 + c_1 s + c_2 s^2 + c_3 s^3 \quad \text{(横向多项式拟合)}
2.2 成本函数设计
评价维度权重系数计算公式
舒适性0.4∑(jerk²)
安全性0.3障碍物距离倒数
路径贴合度0.2参考线偏移量
能耗效率0.1速度变化率

三、Python代码实现(可直接运行)

3.1 环境初始化
import numpy as np
import matplotlib.pyplot as plt

class Vehicle:
    def __init__(self):
        self.width = 2.0    # 车宽
        self.length = 4.5   # 车长
        self.max_acc = 2.0  # 最大加速度(m/s²)
        self.max_jerk = 1.5 # 最大加加速度(m/s³)

obstacles = [
    {'x': 30, 'y': 1.8, 'r': 1.2},
    {'x': 45, 'y': -1.5, 'r': 0.8}
]  # 障碍物坐标及半径
3.2 轨迹采样核心函数
def generate_lattice_paths(current_state, horizon=5.0, dt=0.1):
    """
    :param current_state: 当前状态 [s, s_dot, d, d_dot]
    :param horizon: 规划时长(s)
    :return: 候选轨迹列表
    """
    paths = []
    # 纵向速度采样(3种模式)
    for s_dot_end in np.linspace(8, 12, 3):  # 8m/s~12m/s
        # 横向位移采样(5种偏移)
        for d_end in np.linspace(-1.5, 1.5, 5):  
            t = np.arange(0, horizon + dt, dt)
            # 纵向四次多项式拟合
            s_coeff = np.polyfit([0, horizon], 
                              [current_state[0], current_state[0] + s_dot_end*horizon], 4)
            # 横向五次多项式拟合
            d_coeff = np.polyfit([0, horizon], 
                              [current_state[2], d_end], 5)
            path = {
                's': np.polyval(s_coeff, t),
                'd': np.polyval(d_coeff, t),
                's_dot': np.polyval(np.polyder(s_coeff), t),
                'd_dot': np.polyval(np.polyder(d_coeff), t)
            }
            paths.append(path)
    return paths
3.3 碰撞检测与最优选择
def select_optimal_path(paths, obstacles):
    min_cost = float('inf')
    best_path = None
    for path in paths:
        # 计算舒适性成本
        jerk_cost = np.mean(np.diff(path['s_dot'])**2)
        
        # 计算安全成本
        collision_cost = 0
        for t in range(len(path['s'])):
            x = path['s'][t]
            y = path['d'][t]
            for obs in obstacles:
                dist = np.sqrt((x - obs['x'])**2 + (y - obs['y'])**2)
                if dist < (obs['r'] + 1.5):  # 1.5m为安全距离
                    collision_cost += 1 / max(dist, 0.1)
        
        # 计算总成本
        total_cost = 0.4*jerk_cost + 0.3*collision_cost
        
        if total_cost < min_cost:
            min_cost = total_cost
            best_path = path
    return best_path
3.4 可视化运行
def plot_scenario(paths, best_path, obstacles):
    plt.figure(figsize=(10, 6))
    
    # 绘制障碍物
    for obs in obstacles:
        circle = plt.Circle((obs['x'], obs['y']), obs['r'], color='r', alpha=0.3)
        plt.gca().add_patch(circle)
    
    # 绘制所有候选路径
    for path in paths:
        plt.plot(path['s'], path['d'], 'gray', alpha=0.2)
    
    # 高亮最优路径
    plt.plot(best_path['s'], best_path['d'], 'b', linewidth=2)
    
    plt.xlabel('Longitudinal Position (m)')
    plt.ylabel('Lateral Position (m)')
    plt.grid(True)
    plt.axis('equal')
    plt.show()

# 主程序
if __name__ == "__main__":
    ego_state = [20, 10, 0, 0]  # [s, s_dot, d, d_dot]
    candidate_paths = generate_lattice_paths(ego_state)
    optimal_path = select_optimal_path(candidate_paths, obstacles)
    plot_scenario(candidate_paths, optimal_path, obstacles)

完整代码

#!/usr/bin/python3
import numpy as np
import matplotlib.pyplot as plt

class Vehicle:
    def __init__(self):
        self.width = 2.0    # 车宽
        self.length = 4.5   # 车长
        self.max_acc = 2.0  # 最大加速度(m/s²)
        self.max_jerk = 1.5 # 最大加加速度(m/s³)

obstacles = [
    {'x': 30, 'y': 1.8, 'r': 1.2},
    {'x': 45, 'y': -1.5, 'r': 0.8}
]  # 障碍物坐标及半径
def generate_lattice_paths(current_state, horizon=5.0, dt=0.1):
    """
    :param current_state: 当前状态 [s, s_dot, d, d_dot]
    :param horizon: 规划时长(s)
    :return: 候选轨迹列表
    """
    paths = []
    # 纵向速度采样(3种模式)
    for s_dot_end in np.linspace(8, 12, 3):  # 8m/s~12m/s
        # 横向位移采样(5种偏移)
        for d_end in np.linspace(-1.5, 1.5, 5):  
            t = np.arange(0, horizon + dt, dt)
            # 纵向四次多项式拟合
            s_coeff = np.polyfit([0, horizon], 
                              [current_state[0], current_state[0] + s_dot_end*horizon], 4)
            # 横向五次多项式拟合
            d_coeff = np.polyfit([0, horizon], 
                              [current_state[2], d_end], 5)
            path = {
                's': np.polyval(s_coeff, t),
                'd': np.polyval(d_coeff, t),
                's_dot': np.polyval(np.polyder(s_coeff), t),
                'd_dot': np.polyval(np.polyder(d_coeff), t)
            }
            paths.append(path)
    return paths
def select_optimal_path(paths, obstacles):
    min_cost = float('inf')
    best_path = None
    for path in paths:
        # 计算舒适性成本
        jerk_cost = np.mean(np.diff(path['s_dot'])**2)
        
        # 计算安全成本
        collision_cost = 0
        for t in range(len(path['s'])):
            x = path['s'][t]
            y = path['d'][t]
            for obs in obstacles:
                dist = np.sqrt((x - obs['x'])**2 + (y - obs['y'])**2)
                if dist < (obs['r'] + 1.5):  # 1.5m为安全距离
                    collision_cost += 1 / max(dist, 0.1)
        
        # 计算总成本
        total_cost = 0.4*jerk_cost + 0.3*collision_cost
        
        if total_cost < min_cost:
            min_cost = total_cost
            best_path = path
    return best_path
def plot_scenario(paths, best_path, obstacles):
    plt.figure(figsize=(10, 6))
    
    # 绘制障碍物
    for obs in obstacles:
        circle = plt.Circle((obs['x'], obs['y']), obs['r'], color='r', alpha=0.3)
        plt.gca().add_patch(circle)
    
    # 绘制所有候选路径
    for path in paths:
        plt.plot(path['s'], path['d'], 'gray', alpha=0.2)
    
    # 高亮最优路径
    plt.plot(best_path['s'], best_path['d'], 'b', linewidth=2)
    
    plt.xlabel('Longitudinal Position (m)')
    plt.ylabel('Lateral Position (m)')
    plt.grid(True)
    plt.axis('equal')
    plt.show()

# 主程序
if __name__ == "__main__":
    ego_state = [20, 10, 0, 0]  # [s, s_dot, d, d_dot]
    candidate_paths = generate_lattice_paths(ego_state)
    optimal_path = select_optimal_path(candidate_paths, obstacles)
    plot_scenario(candidate_paths, optimal_path, obstacles)

四、运行结果分析

在这里插入图片描述

(注:实际运行后将显示包含障碍物区域和最优路径的轨迹图,灰色为候选路径,蓝色为最优避障路径)


五、工程优化建议

  1. 引入Frenet坐标系:将全局坐标转换为(s,d)坐标系,简化横向/纵向解耦计算
  2. 动态权重调整:根据场景危险程度自动调整成本函数权重(如障碍物接近时加大安全权重)
  3. 运动学约束检查:添加最大曲率、加速度边界条件校验
  4. 多线程优化:对候选轨迹的代价计算进行并行加速

六、结语

通过不到100行的Python代码,我们实现了一个完整的Lattice Planner避障规划原型系统。该代码在Python 3.8+环境下可直接运行(需安装numpy和matplotlib)。在实际自动驾驶系统中,还需融合高精地图、感知预测模块等,但核心的轨迹生成与优化思想与此文一脉相承。

技术亮点

  1. 采用多项式参数化方法保证轨迹平滑性
  2. 引入多维度加权成本函数实现最优决策
  3. 模块化设计便于功能扩展

原创声明:本文代码及算法思路均为作者原创,转载需注明出处。关注技术博客获取更多自动驾驶实战教程!

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

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

相关文章

PyTorch——卷积操作(2)

二维矩阵 [[ ]] 这里面conv2d(N,C,H,W)里面的四个是 N就是batch size也就是输入图片的数量&#xff0c;C就是通道数这只是一个二维张量所以通道为1&#xff0c;H就是高&#xff0c;W就是宽&#xff0c;所以是1 1 5 5 卷积核 reshape 第一个参数是batch size样本数量 第二个参数…

【JavaWeb】SpringBoot原理

1 配置优先级 在前面&#xff0c;已经学习了SpringBoot项目当中支持的三类配置文件&#xff1a; application.properties application.yml application.yaml 在SpringBoot项目当中&#xff0c;我们要想配置一个属性&#xff0c;通过这三种方式当中的任意一种来配置都可以&a…

ubuntu22.04安装taskfile

sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -dsudo mv ./bin/task /usr/local/bin/测试 task --version

遥感影像建筑物变化检测

文章目录 效果1、环境安装2、项目下载3、数据集下载4、模型训练5、模型推理6、推理结果7、批量推理效果 1、环境安装 参考文章 搭建Pytorch的GPU环境超详细 win10安装3DGS环境(GPU)超详细 测试GPU环境可用 2、项目下载 https://gitcode.com/gh_mirrors/ch/change_detectio…

多模态大语言模型arxiv论文略读(103)

Are Bigger Encoders Always Better in Vision Large Models? ➡️ 论文标题&#xff1a;Are Bigger Encoders Always Better in Vision Large Models? ➡️ 论文作者&#xff1a;Bozhou Li, Hao Liang, Zimo Meng, Wentao Zhang ➡️ 研究机构: 北京大学 ➡️ 问题背景&…

汇编语言基础: 搭建实验环境

环境配置 1.Visual Studio 创建空项目 创建成功 2.平台框架改为为WIN32 右键点击项目 点击属性 点击配置管理器 平台改为Win32(本文使用32位的汇编) 3.生成采用MASM 在项目属性里点击"生成依赖项"的"生成自定义" 勾选 masm 4.创建第一个汇编程序 右…

基于springboot的益智游戏系统的设计与实现

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;没有什么华丽的语言&#xff0…

第十二节:第四部分:集合框架:List系列集合:LinkedList集合的底层原理、特有方法、栈、队列

LinkedList集合的底层原理 LinkedList集合的应用场景之一 代码&#xff1a;掌握LinkedList集合的使用 package com.itheima.day19_Collection_List;import java.util.LinkedList; import java.util.List;//掌握LinkedList集合的使用。 public class ListTest3 {public static …

多模态大语言模型arxiv论文略读(104)

Talk Less, Interact Better: Evaluating In-context Conversational Adaptation in Multimodal LLMs ➡️ 论文标题&#xff1a;Talk Less, Interact Better: Evaluating In-context Conversational Adaptation in Multimodal LLMs ➡️ 论文作者&#xff1a;Yilun Hua, Yoav…

【C++高级主题】多重继承下的类作用域

目录 一、类作用域与名字查找规则&#xff1a;理解二义性的根源 1.1 类作用域的基本概念 1.2 单继承的名字查找流程 1.3 多重继承的名字查找特殊性 1.4 关键规则&#xff1a;“最近” 作用域优先&#xff0c;但多重继承无 “最近” 二、多重继承二义性的典型类型与代码示…

基于Android的一周穿搭APP的设计与实现 _springboot+vue

开发语言&#xff1a;Java框架&#xff1a;springboot AndroidJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat12开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;Maven3.6 系统展示 APP登录 A…

机器学习——使用多个决策树

使用单一决策树的弱点之一是决策树对数据中的微小变化非常敏感&#xff0c;一个使算法不那么敏感或更健壮的解决方案&#xff0c;不是建立一个决策树&#xff0c;而是要建立大量的决策树&#xff0c;我们称之为树合奏。 在这个例子中&#xff0c;我们一直在使用最好的特性来分…

C# 中的对话框与导航:构建流畅用户交互的完整指南

在现代应用程序开发中&#xff0c;良好的用户交互体验是成功的关键因素之一。作为.NET开发者&#xff0c;熟练掌握C#中的对话框与导航技术&#xff0c;能够显著提升应用程序的易用性和专业性。本文将全面探讨Windows Forms、WPF、ASP.NET Core和MAUI等平台下的对话框与导航实现…

DeepSeek - 尝试一下GitHub Models中的DeepSeek

1.简单介绍 当前DeepSeek使用的人很多&#xff0c;各大AI平台中也快速引入了DeekSeek&#xff0c;比如Azure AI Foundary(以前名字是Azure AI Studio)中的Model Catalog, HuggingFace, GitHub Models等。同时也出现了一些支持DeepSeek的.NET类库。微软的Semantic Kernel也支持…

【判断酒酒花数】2022-3-31

缘由对超长正整数的处理&#xff1f; - C语言论坛 - 编程论坛 void 判断酒酒花数(_int64 n) {//缘由https://bbs.bccn.net/thread-508634-1-1.html_int64 t n; int h 0, j 0;//while (j < 3)h t % 10, t / 10, j;//整数的个位十位百位之和是其前缀while (t > 0)h t…

【OCCT+ImGUI系列】011-Poly-Poly_Triangle三角形面片

Poly_Triangle 是什么&#xff1f; Poly_Triangle 是一个非常轻量的类&#xff0c;用于表示一个三角网格中的单个三角形面片。它是构成 Poly_Triangulation&#xff08;三角网格对象&#xff09;的基本单位之一。之后会写关于碰撞检测的相关文章&#xff0c;三角面片是非常重要…

【机器学习基础】机器学习入门核心算法:Mini-Batch K-Means算法

机器学习入门核心算法&#xff1a;Mini-Batch K-Means算法 一、算法逻辑工作流程与传统K-Means对比 二、算法原理与数学推导1. 目标函数2. Mini-Batch更新规则3. 学习率衰减机制4. 伪代码 三、模型评估1. 内部评估指标2. 收敛性判断3. 超参数调优 四、应用案例1. 图像处理 - 颜…

机器学习实战36-基于遗传算法的水泵调度优化项目研究与代码实现

大家好,我是微学AI,今天给大家介绍一下机器学习实战36-基于遗传算法的水泵调度优化项目研究与代码实现。 文章目录 一、项目介绍二、项目背景三、数学原理与算法分析动态规划模型遗传算法设计编码方案适应度函数约束处理算法参数能量消耗模型一泵房能耗二泵房能耗效率计算模…

【仿muduo库实现并发服务器】使用正则表达式提取HTTP元素

使用正则表达式提取HTTP元素 1.正则表达式2.正则库的使用3.使用正则表达式提取HTTP请求行 1.正则表达式 正则表达式它其实是描述了一种字符串匹配的模式&#xff0c;它可以用来在一个字符串中检测一个特定格式的字串&#xff0c;以及可以将符合特定规则的字串进行替换或者提取…

核心机制:流量控制

搭配滑动窗口使用的 窗口大小 窗口越大,传输速度就越快,但是也不能无限大,太大了,对于可靠性会有影响 比如发生方以非常快的速度,发送,接收方的处理速度跟不上,也就会导致有效数据被接受方丢弃(又得重传) 流量控制,就是根据接收方的处理能力(如何衡量?),干预到发送方的发送…