轨迹优化 | 基于LBFGS优化器的无约束路径平滑(附ROS C++仿真)

news2025/7/12 9:27:18

目录

  • 0 专栏介绍
  • 1 LBFGS优化器
    • 1.1 拟牛顿法框架
    • 1.2 `LBFGS-Lite`库
  • 2 基于LBFGS的轨迹优化
  • 3 ROS C++仿真

0 专栏介绍

🔥课设、毕设、创新竞赛必备!🔥本专栏涉及更高阶的运动规划算法轨迹优化实战,包括:曲线生成、碰撞检测、安全走廊、优化建模(QP、SQP、NMPC、iLQR等)、轨迹优化(梯度法、曲线法等),每个算法都包含代码实现加深理解

🚀详情:运动规划实战进阶:轨迹优化篇


1 LBFGS优化器

1.1 拟牛顿法框架

在数值优化 | 详解拟牛顿法之SR1、DFP、BFGS、L-BFGS(附案例分析与Python实现)中,我们介绍了拟牛顿法(quasi-Newton method)框架,有助于解决经典牛顿法计算Hessian矩阵的逆矩阵 H k ( x ) \boldsymbol{H}_k\left( \boldsymbol{x} \right) Hk(x)复杂度高、数值稳定性较差的问题

在这里插入图片描述

L-BFGS算法是一种用于求解大规模无约束优化问题的拟牛顿法。它是BFGS算法的内存优化版本,适用于高维问题(如机器学习、轨迹优化等)。具体而言,L-BFGS算法仅保留最近 m m m步的中间结果来近似Hessian矩阵的逆矩阵 H k ( x ) \boldsymbol{H}_k\left( \boldsymbol{x} \right) Hk(x)

H k + 1 = ( V k T ⋯ V k − m + 1 T ) H 0 ( V k − m + 1 ⋯ V k )    + ( V k T ⋯ V k − m + 2 T ) ρ k − m + 1 s k − m + 1 s k − m + 1 T ( V k − m + 2 ⋯ V k )    + ⋯    + ρ k s k s k T \begin{aligned}\boldsymbol{H}_{k+1}&=\left( \boldsymbol{V}_{k}^{T}\cdots \boldsymbol{V}_{k-m+1}^{T} \right) \boldsymbol{H}_0\left( \boldsymbol{V}_{k-m+1}\cdots \boldsymbol{V}_k \right) \\\,\, &+\left( \boldsymbol{V}_{k}^{T}\cdots \boldsymbol{V}_{k-m+2}^{T} \right) \rho _{k-m+1}\boldsymbol{s}_{k-m+1}\boldsymbol{s}_{k-m+1}^{T}\left( \boldsymbol{V}_{k-m+2}\cdots \boldsymbol{V}_k \right) \\\,\, &+\cdots \\\,\, &+\rho _k\boldsymbol{s}_k\boldsymbol{s}_{k}^{T}\end{aligned} Hk+1=(VkTVkm+1T)H0(Vkm+1Vk)+(VkTVkm+2T)ρkm+1skm+1skm+1T(Vkm+2Vk)++ρkskskT

因此在L-BFGS算法中无需保留完整的 H k \boldsymbol{H}_k Hk,只需存储向量序列 { s i } i = k − m k \left\{ \boldsymbol{s}_i \right\} _{i=k-m}^{k} {si}i=kmk { y i } i = k − m k \left\{ \boldsymbol{y}_i \right\} _{i=k-m}^{k} {yi}i=kmk,占用存储空间 2 m n 2mn 2mn,空间复杂度为 O ( n ) O(n) O(n),下降了一个量级.更详细的推导请参考数值优化 | 详解拟牛顿法之SR1、DFP、BFGS、L-BFGS(附案例分析与Python实现)

1.2 LBFGS-Lite

浙江大学FAST-LAB开源的L-BFGS算法库提供了一个轻量级 L-BFGS 算法实现,支持用户自定义目标函数和梯度计算,专为高效、易用和嵌入式优化设计。它基于 C++ 实现,适用于机器人、自动驾驶等领域的实时优化问题。

下面简单介绍LBFGS-Lite的使用方法:

  • 定义目标函数和梯度

    举例而言,设优化目标为
    f ( x ) = ( 1 − x 1 ) 2 + 100 ( x 2 − x 1 2 ) 2 f(\boldsymbol{x})=(1-x_1)^2+100(x_2-x_1^2)^2 f(x)=(1x1)2+100(x2x12)2

    则梯度
    { ∂ f ( x ) ∂ x 1 = − 2 ( 1 − x 1 + 200 x 1 ( x 2 − x 1 2 ) ) ∂ f ( x ) ∂ x 2 = 200 ( x 2 − x 1 2 ) \begin{cases} \frac{\partial f\left( \boldsymbol{x} \right)}{\partial x_1}=-2\left( 1-x_1+200x_1\left( x_2-x_{1}^{2} \right) \right)\\ \frac{\partial f\left( \boldsymbol{x} \right)}{\partial x_2}=200\left( x_2-x_{1}^{2} \right)\\ \end{cases} {x1f(x)=2(1x1+200x1(x2x12))x2f(x)=200(x2x12)

    对应的C++代码为

    static double costFunction(void *instance,
                                   const Eigen::VectorXd &x,
                                   Eigen::VectorXd &g)
    {
        const int n = x.size();
        double fx = 0.0;
        for (int i = 0; i < n; i += 2)
        {
            const double t1 = 1.0 - x(i);
            const double t2 = 10.0 * (x(i + 1) - x(i) * x(i));
            g(i + 1) = 20.0 * t2;
            g(i) = -2.0 * (x(i) * g(i + 1) + t1);
            fx += t1 * t1 + t2 * t2;
        }
        return fx;
    }
    
  • 给定初始解并优化求解

    /* Set the initial guess */
    for (int i = 0; i < N; i += 2)
    {
        x(i) = -1.2;
        x(i + 1) = 1.0;
    }
    
    /* Set the minimization parameters */
    lbfgs::lbfgs_parameter_t params;
    params.g_epsilon = 1.0e-8;
    params.past = 3;
    params.delta = 1.0e-8;
    
    /* Start minimization */
    int ret = lbfgs::lbfgs_optimize(x,
                                    finalCost,
                                    costFunction,
                                    nullptr,
                                    monitorProgress,
                                    this,
                                    params);
    

2 基于LBFGS的轨迹优化

为了使用LBFGS-Lite进行轨迹优化,我们首先需要定义一个无约束的优化问题:选择优化变量为二维的路径序列 X = { x i = ( x i , y i ) ∣ i ∈ [ 1 , N ] } \mathcal{X} =\left\{ \boldsymbol{x}_i=\left( x_i,y_i \right) |i\in \left[ 1,N \right] \right\} X={xi=(xi,yi)i[1,N]},并基于此设计优化目标函数

f ( X ) = w o P o b s ( X ) + w κ P c u r ( X ) + w s P s m o ( X ) f\left( \mathcal{X} \right) =w_oP_{\mathrm{obs}}\left( \mathcal{X} \right) +w_{\kappa}P_{\mathrm{cur}}\left( \mathcal{X} \right) +w_sP_{\mathrm{smo}}\left( \mathcal{X} \right) f(X)=woPobs(X)+wκPcur(X)+wsPsmo(X)

其中:

  • 障碍目标函数

P o b s ( X ) = ∑ x i ∈ X σ o ( ∥ x i − o min ⁡ ∥ 2 − d max ⁡ ) P_{\mathrm{obs}}\left( \mathcal{X} \right) =\sum_{\boldsymbol{x}_i\in \mathcal{X}}^{}{\sigma _o\left( \left\| \boldsymbol{x}_i-\boldsymbol{o}_{\min} \right\| _2-d_{\max} \right)} Pobs(X)=xiXσo(xiomin2dmax)

  • 曲率目标函数

P c u r ( X ) = ∑ x i ∈ X σ κ ( Δ ϕ i ∥ Δ x i ∥ 2 − κ max ⁡ ) P_{\mathrm{cur}}\left( \mathcal{X} \right) =\sum_{\boldsymbol{x}_i\in \mathcal{X}}^{}{\sigma _{\kappa}\left( \frac{\varDelta \phi _i}{\left\| \varDelta \boldsymbol{x}_i \right\| _2}-\kappa _{\max} \right)} Pcur(X)=xiXσκ(Δxi2Δϕiκmax)

  • 平滑目标函数

P s m o ( X ) = ∑ x i ∈ X ∥ Δ x i − Δ x i + 1 ∥ 2 2 P_{\mathrm{smo}}\left( \mathcal{X} \right) =\sum_{\boldsymbol{x}_i\in \mathcal{X}}^{}{\left\| \varDelta \boldsymbol{x}_i-\varDelta \boldsymbol{x}_{i+1} \right\| _{2}^{2}} Psmo(X)=xiXΔxiΔxi+122

由于LBFGS-Lite需要用户显式地定义目标函数梯度,因此需要进一步计算

  • 障碍目标函数梯度

∂ P o b s ( x i ) ∂ x i = = 2 ( ∥ x i − o min ⁡ ∥ 2 − d max ⁡ ) x i − o min ⁡ ∥ x i − o min ⁡ ∥ 2 \frac{\partial P_{\mathrm{obs}}\left( \boldsymbol{x}_i \right)}{\partial \boldsymbol{x}_i}==2\left( \left\| \boldsymbol{x}_i-\boldsymbol{o}_{\min} \right\| _2-d_{\max} \right) \frac{\boldsymbol{x}_i-\boldsymbol{o}_{\min}}{\left\| \boldsymbol{x}_i-\boldsymbol{o}_{\min} \right\| _2} xiPobs(xi)==2(xiomin2dmax)xiomin2xiomin

  • 曲率目标函数梯度

∂ κ i ∂ x i = 1 ∥ Δ x i ∥ 2 − 1 1 − cos ⁡ 2 Δ ϕ ( − p 1 − p 2 ) − Δ ϕ i Δ x i ∥ Δ x i ∥ 2 3 \begin{aligned} \frac{\partial \kappa _i}{\partial \boldsymbol{x}_i}&=\frac{1}{\left\| \varDelta \boldsymbol{x}_i \right\| _2}\frac{-1}{\sqrt{1-\cos ^2\varDelta \phi}}\left( -\boldsymbol{p}_1-\boldsymbol{p}_2 \right) -\frac{\varDelta \phi _i\varDelta \boldsymbol{x}_i}{\left\| \varDelta \boldsymbol{x}_i \right\| _{2}^{3}}\\\end{aligned} xiκi=Δxi211cos2Δϕ 1(p1p2)Δxi23ΔϕiΔxi

  • 平滑目标函数梯度

∂ P s m o ( x i ) ∂ x i = 2 ( x i − 2 − 4 x i − 1 + 6 x i − 4 x i + 1 + x i + 2 ) \frac{\partial P_{\mathrm{smo}}\left( \boldsymbol{x}_i \right)}{\partial \boldsymbol{x}_i}=2\left( \boldsymbol{x}_{i-2}-4\boldsymbol{x}_{i-1}+6\boldsymbol{x}_i-4\boldsymbol{x}_{i+1}+\boldsymbol{x}_{i+2} \right) xiPsmo(xi)=2(xi24xi1+6xi4xi+1+xi+2)

上述目标函数的具体定义和梯度推导和轨迹优化 | 基于ESDF的共轭梯度优化算法(附ROS C++/Python仿真)是一致的,感兴趣的同学可以参考

3 ROS C++仿真

代价函数和梯度计算的核心代码如下所示

double LBFGSOptimizer::costFunction(void* ptr, const Eigen::VectorXd& x, Eigen::VectorXd& g)
{
  auto instance = reinterpret_cast<LBFGSOptimizer*>(ptr);
  const auto& origin_path = instance->path_opt_;

  int points_num = static_cast<int>(origin_path.size());
  int var_num = points_num - 4;
  double cost = 0.0;
  Eigen::Matrix2Xd grad;
  grad.resize(2, var_num);
  grad.setZero();

  // update opt-path during optimization
  Eigen::Matrix2Xd path_opt;
  path_opt.resize(2, points_num);
  path_opt(0, 0) = origin_path[0].x();
  path_opt(1, 0) = origin_path[0].y();
  path_opt(0, 1) = origin_path[1].x();
  path_opt(1, 1) = origin_path[1].y();
  path_opt.block(0, 2, 1, var_num) = x.head(var_num).transpose();
  path_opt.block(1, 2, 1, var_num) = x.tail(var_num).transpose();
  path_opt(0, points_num - 2) = origin_path[points_num - 2].x();
  path_opt(1, points_num - 2) = origin_path[points_num - 2].y();
  path_opt(0, points_num - 1) = origin_path[points_num - 1].x();
  path_opt(1, points_num - 1) = origin_path[points_num - 1].y();

  // obstacle term
  double obstacle_cost = 0.0;
  const auto& obstacle_grad = _calObstacleTerm(instance, path_opt, obstacle_cost);
  grad += obstacle_grad;
  cost += obstacle_cost;

  // smooth term
  double smooth_cost = 0.0;
  const auto& smooth_grad = _calSmoothTerm(instance, path_opt, smooth_cost);
  grad += smooth_grad;
  cost += smooth_cost;

  // curvature term
  double curvature_cost = 0.0;
  const auto& curvature_grad = _calCurvatureTerm(instance, path_opt, curvature_cost);
  grad += curvature_grad;
  cost += curvature_cost;

  g.setZero();
  g.head(var_num) = grad.row(0).transpose();
  g.tail(var_num) = grad.row(1).transpose();

  return cost;
}

优化过程的核心代码如下所示

bool LBFGSOptimizer::optimize(const Points3d& waypoints)
{
  // first two and last two points are constant (to keep start and end direction)
  int var_num = static_cast<int>(waypoints.size()) - 4;
  Eigen::VectorXd opt_var(2 * var_num);
  for (int i = 2; i < static_cast<int>(waypoints.size()) - 2; ++i)
  {
    opt_var(i - 2) = waypoints[i].x();
    opt_var(i - 2 + var_num) = waypoints[i].y();
  }
  path_opt_ = waypoints;

  // optimizer parameters
  lbfgs::lbfgs_parameter_t lbfgs_params;
  lbfgs_params.mem_size = 256;
  lbfgs_params.past = 3;
  lbfgs_params.min_step = 1.0e-32;
  lbfgs_params.g_epsilon = 0.0;
  lbfgs_params.delta = 0.01;

  // optimization
  double min_cost = 0.0;
  int ret =
      lbfgs::lbfgs_optimize(opt_var, min_cost, &LBFGSOptimizer::costFunction, nullptr, nullptr, this, lbfgs_params);

  // parse solution
  if (ret >= 0)
  {
    for (int i = 0; i < var_num; ++i)
    {
      path_opt_[i + 2].setX(opt_var(i));
      path_opt_[i + 2].setY(opt_var(i + var_num));
    }
  }
  else
  {
    R_WARN << "LBFGS Optimization failed: " << lbfgs::lbfgs_strerror(ret);
    return false;
  }

  return true;
}

轨迹优化的效果如下,其中橙色为优化后的路径,蓝色为原始路径

在这里插入图片描述

全局演示

在这里插入图片描述

局部演示

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


🔥 更多精彩专栏

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

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

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

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

相关文章

Vue2到Vue3:无痛升级之路

为什么要从 Vue2 升级到 Vue3 Vue 3 带来了众多令人瞩目的改进和新特性&#xff0c;这些优势使得升级到 Vue 3 对项目的长期发展具有重要意义。 性能显著提升&#xff1a;Vue 3 采用了基于 Proxy 的响应式系统&#xff0c;相比 Vue 2 使用的 Object.defineProperty&#xff0c…

第28篇 基于ARM A9处理器用C语言实现中断<四>

Q&#xff1a;可以改变上一期实验工程里红色LED计数的速率吗&#xff1f; A&#xff1a;在按键中断服务程序中使HPS Timer 0停止计数&#xff0c;修改定时器中使用的预设计数值&#xff0c;然后重启定时器&#xff1b;所有的修改都是在按键中断服务程序中完成。主程序和其他…

时间序列分析(四)——差分运算、延迟算子、AR(p)模型

此前篇章&#xff1a; 时间序列分析&#xff08;一&#xff09;——基础概念篇 时间序列分析&#xff08;二&#xff09;——平稳性检验 时间序列分析&#xff08;三&#xff09;——白噪声检验 一、差分运算 差分运算的定义&#xff1a;差分运算是一种将非平稳时间序列转换…

《深度学习》——调整学习率和保存使用最优模型

调整学习率 在使用 PyTorch 进行深度学习训练时&#xff0c;调整学习率是一个重要的技巧&#xff0c;合适的学习率调整策略可以帮助模型更好地收敛。 PyTorch 提供了多种调整学习率的方法&#xff0c;下面将详细介绍几种常见的学习率调整策略及实例代码&#xff1a; torch.opt…

零风险把数据盘挂载给根分区,给生产环境服务器扩容

背景 刚买服务器时&#xff0c;用户量不大&#xff0c;所以结合预算不多情况下&#xff0c;都是默认买个小点的系统盘挂载到服务器上&#xff0c;&#xff08;或者默认服务器的40G&#xff09;&#xff0c;等到某一天业务量上来之后&#xff0c;发现抓肘见襟给自己一手措不及防…

在vscode中拉取gitee里的项目并运行

拉取项目: 方法一:vscode点击查看--->终端(或者直接通过快捷键ctrol+ `打开) 在终端内通过cd命令定位到你想存放项目的文件夹 例如:cd h: 通过命令:git clone 地址 例如:git clone newbee-mall-vue-app: 前端代码 等待拉取完成即可在对应文件夹下看到项目啦 方…

IDEA通过Contince接入Deepseek

Deepseek 的出色表现&#xff0c;上期【Deepseek得两种访问方式与本地部署】 安装Continue插件 第一步、下载插件 在编辑栏【File】->设置【Settiings】或快捷键【CtrlAltS】,弹窗的左侧导航树&#xff0c;选择【plugins】,在marketplace 搜索【Continue】&#xff0c;点…

数据结构------单向链表。

一.实现单向链表的头插&#xff0c;头删&#xff0c;尾插&#xff0c;尾删&#xff0c;按位置插&#xff0c;按位置删&#xff0c;按位置修改&#xff0c;按元素查找&#xff0c;按元素修改&#xff0c;按元素删除&#xff0c;单链表的逆置&#xff0c;查找倒数第几个元素&…

算法——结合实例了解Minimax算法(极小化极大算法)

计算机科学中最有趣的事情之一就是编写一个人机博弈的程序。有大量的例子&#xff0c;最出名的是编写一个国际象棋的博弈机器。但不管是什么游戏&#xff0c;程序趋向于遵循一个被称为Minimax算法&#xff0c;伴随着各种各样的子算法在一块。本篇将简要介绍 minimax 算法&#…

cornerstone3D学习笔记-MPR

最近在研究如何利用cornerstone3D (v1.70.13) 来实现MPR功能&#xff0c;找到它的一个demo -- volumeBasic, 运行效果如下图 看了下主程序的示例代码&#xff0c;非常简单&#xff0c;可以说corestone3D这个库把很多细节都封装起来了&#xff0c;使得调用者可以很简单的快速实…

C++ Primer 函数匹配

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

Dav_笔记14:优化程序提示 HINTs -4

指定全局表提示 指定表的提示通常是指发生提示的DELETE&#xff0c;SELECT或UPDATE查询块中的表&#xff0c;而不是指语句引用的任何视图中的表。 如果要为显示在视图中的表指定提示&#xff0c;Oracle建议使用全局提示&#xff0c;而不是在视图中嵌入提示。 您可以使用包含具…

桥接模式 Bridge Pattern

桥接模式Abstraction 和 Implementor 的理解 在图书馆看到一本 通过电商项目真正实战《贯穿设计模式》。拿起来翻到了 桥接模式&#xff0c;感觉味道不对&#xff0c;和我印象中不一样。 感谢这位同学提供的源码 贯穿设计模式-适配器模式桥接模式_-CSDN博客GitHub - WeiXiao…

Ubuntu 安装 OpenCV (C++)

版本详情&#xff1a; Ubuntu: 22.04 5.15.0-133-generic gcc: 11.4.0 g: 11.4.0 OpenCV: 4.7.0 1. 卸载 OpenCV 进入原先编译 opencv 的 build 目录&#xff0c;在该目录下打开终端&#xff0c;执行以下代码&#xff08;如果 build 已经删除了&#xff0c;可以重新编译一…

前端模板引擎

前言 正常渲染拿到数据后渲染&#xff0c;三步走&#xff1a;格式化数据、编译模板、渲染数据 如下例 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice…

长尾词SEO优化软件:企业官网流量提升的软件【实测】

搜索引擎流量中68%来自长尾关键词&#xff08;数据来源&#xff1a;Ahrefs 2025&#xff09;&#xff0c;但83%企业仍困于「高价值长尾词难挖掘内容生产跟不上」的双重困境。当同行用智能工具批量布局「孕妇防辐射服哪个牌子好」等精准词时&#xff0c;手动分析数据的你可能还在…

用自己的数据训练yolov11目标检测

文章目录 概要理论知识整体架构流程架构优化多任务支持多参数体量 操作实操环境配置数据准备数据标注数据放置路径 训练预测 概要 YOLOv11 是 Ultralytics 团队于 2024 年 9 月 30 日发布的最新目标检测模型&#xff0c;延续了 YOLO 系列实时推理特性&#xff0c;同时通过架构优…

gsoap实现webservice服务

gsoap实现webservice服务 在实现Web服务时&#xff0c;使用gSOAP是一个很好的选择&#xff0c;因为它提供了强大的工具和库来创建SOAP和RESTful服务。gSOAP是一个C和C语言开发的库&#xff0c;它支持SOAP协议的各种版本&#xff0c;包括SOAP 1.1和SOAP 1.2。下面是如何使用gSO…

项目2 数据可视化--- 第十五章 生成数据

数据分析是使用代码来探索数据内的规律和关联。 数据可视化是通过可视化表示来 探索和呈现数据集内的规律。 好的数据可视化&#xff0c;可以发现数据集中未知的规律和意义。 一个流行的工具是Matplotlib&#xff0c;他是一个数据绘图库&#xff1b; 还有Plotly包&#xff…

QT (四)模型/视图 QFileSystemModel,QStringListModel,QStandardItemModel

思考&#xff1a;QTableWidget 在某种程度上可以等价为QStandardItemModel&#xff0c;同理&#xff0c;其他的功能也有类似的等价&#xff0c;但是以当前的QTableWidget 和QStandardItemModel为例的话&#xff0c;两者都是用于实现建立表格的相关组件&#xff0c;只不过QStand…