自动驾驶-轨迹拼接

news2024/11/26 21:37:21

在进行自动驾驶的规划之前,要确定当前帧轨迹规划的起点,这个起点常被误认为是当前车辆的位置,即每次以车辆的当前位置进行轨迹规划;其实不是这样的,直观上,这会导致本次次规划的轨迹同上次规划的轨迹之间是不连续的,这个不连续传递到控制模块,由于轨迹规划出的轨迹对于控制而言就是参考线,那么由于参考线是不连续的,对控制器而言就是朝令夕改。

轨迹重规划

上述所讲的直接以当前位置进行规划起点,进行本次轨迹规划的方法,其实称为轨迹重规划,即当前位置与上一帧的参考轨迹差距过大,需要重新规划轨迹;对于这种情况,apollo也做了一定优化,根据自车当前实际位置状态信息,通过车辆运动学推导0.1s后的位置状态信息,作为规划起始点状态,向后推导0.1s,这主要是为了减少执行机构的响应延迟问题,将未来的状态作为执行器的参考输入。

参考链接:apollo轨迹拼接

轨迹拼接

轨迹拼接的核心思想是将当前的规划起点,设置在上次(上一帧)规划出轨迹上,从而保证轨迹的连续性,提升控制效果。
上述思想的实现,需要得到当前自车状态,在上一帧轨迹中的匹配点,匹配点的确定有两种方式:

  1. 相对时间匹配
    根据当前时间戳和上一帧轨迹起点的时间戳对比,计算当前时间自车在上一帧轨迹中的时间匹配点(下图中的绿色点)及该匹配点在上一帧轨迹中对应的索引值t_index。
  2. 相对里程匹配
    结合自车的定位信息与上一帧轨迹信息,将自车信息从笛卡尔坐标系→Frenet坐标(s,d),得到当前的位置s,根据当前的s在上一帧的轨迹中,即可查询到在里程维度上的匹配点(下图中的蓝色点)。
    轨迹拼接根据index,选取min{时间匹配点,里程匹配点}作为当前车辆在上一帧映射的匹配点。如上图所示,由于绿色点索引更小,故即选择绿色点为匹配点。

在选择完规划起点后,为缓解执行机构的延时,同样向前预测del_t时间,以del_t时刻的点,作为起点,进行当前时刻的轨迹规划,并在上一帧帧的轨迹上截取出matched_index往前n个点开始,至forward_rel_time的一段轨迹,作为stitching_trajectory。
在这里插入图片描述现在的疑问是为何要生成一个stitch trajectory呢?即使不选择,也是和直接的轨迹是平滑与连续的啊?
但是规划起点的选择是明晰的。
参考链接:轨迹拼接

轨迹拼接apollo代码

/* Planning from current vehicle state if:
1. the auto-driving mode is off
(or) 2. we don't have the trajectory from last planning cycle
(or) 3. the position deviation from actual and target is too high
*/
std::vector<TrajectoryPoint> TrajectoryStitcher::ComputeStitchingTrajectory(
const VehicleState& vehicle_state, const double current_timestamp,
const double planning_cycle_time, const size_t preserved_points_num,
const bool replan_by_offset, const PublishableTrajectory* prev_trajectory,
std::string* replan_reason) {
    //a.是否使能轨迹拼接
    if (!FLAGS_enable_trajectory_stitcher) {
        *replan_reason = "stitch is disabled by gflag.";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    //b.上一帧是否生成轨迹
    if (!prev_trajectory) {
        *replan_reason = "replan for no previous trajectory.";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    //c.是否处于自动驾驶模式
    if (vehicle_state.driving_mode() != canbus::Chassis::COMPLETE_AUTO_DRIVE) {
        *replan_reason = "replan for manual mode.";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    //d.上一帧是否存在轨迹点 
    size_t prev_trajectory_size = prev_trajectory->NumOfPoints();
    if (prev_trajectory_size == 0) {
        *replan_reason = "replan for empty previous trajectory.";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    const double veh_rel_time = current_timestamp - prev_trajectory->header_time();
    size_t time_matched_index = prev_trajectory->QueryLowerBoundPoint(veh_rel_time);

    //e.判断当前时间相对于上一帧的相对时间戳是否小于上一帧起点相对时间戳
    if (time_matched_index == 0 &&
        veh_rel_time < prev_trajectory->StartPoint().relative_time()) {
        *replan_reason =
            "replan for current time smaller than the previous trajectory's first "
            "time.";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }
    
    //f.判断时间匹配点是否超出上一帧轨迹点范围
    if (time_matched_index + 1 >= prev_trajectory_size) {
        *replan_reason =
            "replan for current time beyond the previous trajectory's last time";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    auto time_matched_point = prev_trajectory->TrajectoryPointAt(
    static_cast<uint32_t>(time_matched_index));

    //g.判断时间匹配点处是否存在path_point
    if (!time_matched_point.has_path_point()) {
        *replan_reason = "replan for previous trajectory missed path point";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    size_t position_matched_index = prev_trajectory->QueryNearestPointWithBuffer(
    {vehicle_state.x(), vehicle_state.y()}, 1.0e-6);

    //计算实际位置点和匹配点的横纵向偏差
    auto frenet_sd = ComputePositionProjection(
    vehicle_state.x(), vehicle_state.y(),
    prev_trajectory->TrajectoryPointAt(
    static_cast<uint32_t>(position_matched_index)));

    //h.判断横纵向偏差
    if (replan_by_offset) {
        auto lon_diff = time_matched_point.path_point().s() - frenet_sd.first;
        auto lat_diff = frenet_sd.second;
        //h.1:横向偏差不满足条件
        if (std::fabs(lat_diff) > FLAGS_replan_lateral_distance_threshold) {
            const std::string msg = absl::StrCat(
            "the distance between matched point and actual position is too "
            "large. Replan is triggered. lat_diff = ",
            lat_diff);
            *replan_reason = msg;
            return ComputeReinitStitchingTrajectory(planning_cycle_time,
            vehicle_state);
    	}
        //h.2:纵向偏差不满足条件
        if (std::fabs(lon_diff) > FLAGS_replan_longitudinal_distance_threshold) {
            const std::string msg = absl::StrCat(
            "the distance between matched point and actual position is too "
            "large. Replan is triggered. lon_diff = ",
            lon_diff);
            *replan_reason = msg;
            return ComputeReinitStitchingTrajectory(planning_cycle_time,
            vehicle_state);
    	}
    } else {
        ADEBUG << "replan according to certain amount of lat and lon offset is "
        "disabled";
    }

    //计算当前时刻后T时刻的时间,并计算其在上一帧轨迹中对应的索引值
    double forward_rel_time = veh_rel_time + planning_cycle_time;
    size_t forward_time_index =
    prev_trajectory->QueryLowerBoundPoint(forward_rel_time);

    ADEBUG << "Position matched index:\t" << position_matched_index;
    ADEBUG << "Time matched index:\t" << time_matched_index;

    //选择时间匹配索引和位置匹配索引中的较小索引作为匹配点索引
    auto matched_index = std::min(time_matched_index, position_matched_index);

    //构建拼接轨迹,<匹配索引点前n个点,当前时刻后的T时刻所对应的匹配点>
    std::vector<TrajectoryPoint> stitching_trajectory(
    prev_trajectory->begin() +
    std::max(0, static_cast<int>(matched_index - preserved_points_num)),
    prev_trajectory->begin() + forward_time_index + 1);

    const double zero_s = stitching_trajectory.back().path_point().s();
    for (auto& tp : stitching_trajectory) {
        if (!tp.has_path_point()) {
            *replan_reason = "replan for previous trajectory missed path point";
            return ComputeReinitStitchingTrajectory(planning_cycle_time,
            vehicle_state);
        }
        //适配时间和s值
        tp.set_relative_time(tp.relative_time() + prev_trajectory->header_time() -
        current_timestamp);
        tp.mutable_path_point()->set_s(tp.path_point().s() - zero_s);
    }
    return stitching_trajectory;
}

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

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

相关文章

如何计算服务需要部署多少台机器?

写在前面 遇到流量激增的性能问题&#xff0c;相信绝大多数人的第一反应不是优化代码而是加机器&#xff01;比如隔壁微博一旦出现爆炸性吃瓜&#xff0c;就会紧急扩机器&#xff0c;防止自己服务被打挂&#xff08;虽然经常被打挂 这篇文章我们就来讲一下如何 计算出一个服务…

项目配置说明

文章目录 一、下载 vscode 并安装相应扩展1.1 下载 vscode1.2 安装扩展 二、git 项目三、git 提交流程3.1 确定要提交的代码 四、git 拉新流程 一、下载 vscode 并安装相应扩展 1.1 下载 vscode vscode 我已经发群里了&#xff0c;或者自己去官网下载也行 1.2 安装扩展 打开…

四舵轮车辆中的舵轮角度计算

对于四舵轮车辆&#xff0c;或者对角线安装的双舵轮车辆来说&#xff0c;当同时存在线速度与角速度的时候&#xff0c;它的两个轮子的角度值是不一样的&#xff0c;而它的角度值与其当时的瞬心相关&#xff08;机器人模型与ICR(Instantaneous Center of Rotation)&#xff09;。…

IP6537_C_30W20V--移动设备快充的得力助手,集成 14 种快充协议的降压 SoC

IP6537_C_30W20V是一款集成同步开关的降压转换器、支 持 14 种输出快充协议、支持 Type-C 输出和 USB PD2.0/PD3.0(PPS)协议的 SoC&#xff0c;为车载充电器、 快充适配器、智能排插提供完整的解决方案。 IP6537_C_30W20V支持 USB Type-C 或者 USB A 输出&#xff0c; 5V 输出功…

火语言RPA流程组件介绍--模拟键盘输入

&#x1f6a9;【组件功能】&#xff1a;在浏览器网页中使用键盘操作模拟输入值 配置预览 配置说明 按键间隔(ms) 支持T或# 输入仅支持整型 两次输入按键的间隔,单位毫秒 输入内容 支持T或# 默认FLOW输入项 需要输入的内容 超时时间 支持T或# 输入仅支持整型 输入的超时时…

我们的赞赏码

每一位粉丝的认可&#xff0c;都是我们前进的动力。欢迎为我们点赞、转发和分享&#xff0c;让我们一起传递美好与快乐&#xff01; 我们真诚地邀请您来赞赏我们&#xff0c;您的认可是我们前进的动力&#xff01; 赞赏我们只要0.99&#xff0c;让我们一起在CSDN增长知识&…

OpenAI 开发者大会!实时语音功能有API了,GPT-4o支持多模态微调,上下文cache功能上线

家人们&#xff01;十一假期第1天&#xff0c; OpenAI一年一度的开发者大会又来了惹&#xff01;今年的开发者大会分成三部分分别在美国、英国、新加坡三个地点举办&#xff0c;刚刚结束的是第一场。 去年的OpenAI开发者大会公布了GPT-4 Turbo和GPTs&#xff0c;今年没有大更新…

【硬件模块】SG90舵机模块

SG90舵机模块实物图 180度舵机&#xff1a;可以控制旋转角度、有角度定位。上电后舵机自动复位到0度&#xff0c;通过一定参数的脉冲信号控制它的角度。 360舵机&#xff1a;不可控制角度&#xff0c;只能控制顺时针旋转、逆时针旋转、停止和调节转速。 如图所示为&#xff1a;…

仅用pygame+python实现植物大战僵尸-----完成比完美更重要

前言 其实这个项目再我上半年就想着做一下的&#xff0c;但是一直拖到现在&#xff0c;我现在深刻的理解到&#xff0c;不要想那么多&#xff0c;先做&#xff0c;因为永远不可能准备好&#xff0c;都是边做边学便准备的&#xff0c;完成比完美更重要&#xff1b;使用python&a…

【YOLO学习】YOLOv2详解

文章目录 1. 概述2. Better2.1 Batch Normalization&#xff08;批归一化&#xff09;2.2 High Resolution Classifier&#xff08;高分辨率分类器&#xff09;2.3 Convolutional With Anchor Boxes&#xff08;带有Anchor Boxes的卷积&#xff09;2.4 Dimension Clusters&…

每日一题|1928. 规定时间内到达终点的最小花费|动态规划、最小路径

本题需要使用动态规划进行解决。 分析&#xff1a; 求解最小值而且每一次的状态是由上一次的状态推导出来的&#xff0c;用动态规划。 难点&#xff1a;dp数组的定义和更新。 1、dp数组的定义 在时刻t&#xff0c;位置i处&#xff0c;此时的花费可以表示为如下的形式&#…

CNN卷积神经网络算法原理

全连接神经网络概述 输入层在左点自外&#xff0c;相应的输出层在右点之外&#xff0c; 这就像一个函数&#xff0c;yf(x)&#xff0c;x即输入&#xff0c;f即隐藏层&#xff0c;y即输出&#xff0c;或者是ymodel(x) 全连接神经网络的结构单元 主要是从单元到整体&#xff0c…

杀疯啦!yolov11+strongsort的目标跟踪实现

目录 yolov11介绍——实时端到端物体检测 概述 主要特征 支持的任务和模式 性能指标 总结 strongsort介绍 指标图 系统定位 效果展示 训练与预测 UI设计 界面其他功能展示 完整代码实现UI界面 yolov11介绍——实时端到端物体检测 概述 YOLO11 是 Ultralytics Y…

基于yolov5 无人机检测包含:数据集➕训练好的代码模型训练了300轮 效果看下图 map97%以上

基于yolov5 无人机检测包含:数据集➕训练好的代码模型训练了300轮 效果看下图 map97%以上 基于YOLOv5的无人机检测项目 项目名称 基于YOLOv5的无人机检测 (Drone Detection with YOLOv5) 项目概述 该项目使用YOLOv5模型进行无人机目标检测。数据集包含大量带有标注的无人机…

wsl中安装ubuntu,vscode访问这个ubuntu

WSL1升级为WSL2 wsl --set-default-version 2 wsl --set-version Ubuntu-22.04 2在windows商店中也可以安装ubuntu&#xff0c;在这个ubuntu中windows的c盘在/mnt/c中

国庆刷题(day2)

C语言刷题&#xff1a; C刷题&#xff1a;

数据结构与算法——Java实现 27.双端队列

很多人觉得做一件事付出了10分的努力&#xff0c;却只得到5分的汇报。 其实剩下的五分&#xff0c;是在填补你过往的懒惰。 只有将过往的懒惰填满&#xff0c; 努力才会有正向结果 —— 24.10.3 一、概述 双端队列、队列、栈对比&#xff1a; 队列 一端删除&#xff08;头&am…

计算机毕业设计 基于Python的个性化旅游线路推荐系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

C++基础补充(02)C++其他控制语句break continue goto等

文章目录 1. break2. continue 语句3. goto 语句goto的存在 4. 跳出多重循环4.1 goto 直接跳转4.2 C11及其后版本的 return 语句4.3 使用标志变量 在C中&#xff0c;控制语句用于管理程序的执行流程。常见有 break、continue 和 goto。 1. break break语句主要用于在循环或者s…

【GEE学习第一期】GEE介绍、注册及基本使用

【GEE学习第一期】GEE介绍、注册及基本使用 GEE基本介绍GEE架构编辑语言&#xff1a;JavaScript GEE注册GEE平台界面GEE编辑器API区详解 GEE环境配置本地Python环境配置在线Python环境配置 参考 GEE基本介绍 地球引擎代码编辑器&#xff08;Google Earth Engine, GEE&#xff…