当前位置: 首页 > news >正文

GTSAM中先验位姿(Prior Factor)详解应用

GTSAM先验位姿的值应该是什么


1. 先验位姿的来源

在因子图优化里,通常需要给第一个位姿节点 X0 加一个 PriorFactor(先验因子),防止图在优化中漂移。
这个先验的值是你人为指定的,比如:

poseNoise = noiseModel::Diagonal::Sigmas(Vector6::Constant(1e-6));
graph.add(PriorFactor<Pose3>(0, Pose3(), poseNoise));

这里 Pose3() 是默认构造函数,确实是单位矩阵(平移为零,旋转为单位旋转)。
这就意味着 如果你没有特别指定,单位矩阵会作为第一个位姿的先验


2. 为什么常用单位矩阵作为先验?

  • 因为第一帧通常设为坐标系原点(世界坐标系)。
  • 这样后续优化结果是相对于第一帧的世界坐标输出的,方便可视化与处理。
  • 如果你输入的先验不是单位矩阵,整个优化结果会相对于你给的初始先验发生刚体变换。

3. 可以不是单位矩阵

  • 如果你的第一帧并不是坐标系原点,比如用 GPS/其他定位系统给出了初始估计:
Pose3 init_pose(Rot3::RzRyRx(yaw, pitch, roll), Point3(x, y, z));
graph.add(PriorFactor<Pose3>(0, init_pose, poseNoise));
  • 优化会以这个先验作为参考原点,而不是单位矩阵。

4. 注意事项

  • 如果完全不加先验位姿因子(PriorFactor),因子图会有自由度,优化结果会漂移(整个图的绝对位置/朝向不确定)。
  • 如果第一帧已经被其他强约束(如 GPS 因子)锁定,也可以不加单位矩阵先验。

5.小结

在 GTSAM 中,“先验位姿”并不是固定单位矩阵,但大多数 SLAM / LiDAR-IMU 系统为了简化,会把第一帧的先验设为 单位矩阵 Pose3(),这样优化结果就是相对第一帧的坐标系。
总结一句就是:在 GTSAM 中,优化时的“先验位姿”是否是单位矩阵,取决于你的因子图建模方式,并不是固定为单位矩阵。


GTSAM中添加先验位姿

GTSAM 中添加先验位姿(Prior Factor),其实就是往因子图 NonlinearFactorGraph 里插入一个 PriorFactor<Pose3>


1. 先验位姿在 GTSAM 中的意义

  • 因子图优化 本质上需要一个参考系原点,否则问题是“悬空的”(无绝对参考),优化会出现无穷多解(例如整体平移、旋转自由度)。

  • 先验位姿(Prior Factor) 就是给某个节点(通常是第一帧)加一个绝对约束,定义它在全局坐标系下的位置和姿态。

  • 数学形式:

    fprior(Xi)=∥Xi−Xprior∥Σ f_{\text{prior}}(X_i) = \| X_i - X_{prior} \|_{\Sigma} fprior(Xi)=XiXpriorΣ

    其中:

    • XiX_iXi 是第 iii 个位姿变量(Pose3)
    • XpriorX_{prior}Xprior 是已知先验位姿
    • Σ\SigmaΣ 是噪声协方差矩阵(噪声模型)

2. 添加先验位姿的基本步骤

2.1 准备数据结构

#include <gtsam/slam/PriorFactor.h>
#include <gtsam/geometry/Pose3.h>
#include <gtsam/nonlinear/NonlinearFactorGraph.h>
#include <gtsam/nonlinear/Values.h>
#include <gtsam/noiseModel/Diagonal.h>

1.2 创建因子图与变量

gtsam::NonlinearFactorGraph graph;
gtsam::Values initialEstimate;

2.3 定义先验噪声模型

auto priorNoise = gtsam::noiseModel::Diagonal::Sigmas((gtsam::Vector(6) << 0.1, 0.1, 0.1, // 平移方向 x,y,z 方差(米)0.1, 0.1, 0.1  // 旋转方向 roll, pitch, yaw 方差(弧度)).finished()
);
  • 注意这里的单位:

    • 平移单位:米
    • 旋转单位:弧度

2.4 创建先验位姿并加入因子图

假设我们要对 第 0 个节点 添加先验:

gtsam::Pose3 priorPose(gtsam::Rot3::RzRyRx(0.0, 0.0, 0.0), // yaw, pitch, rollgtsam::Point3(0.0, 0.0, 0.0)        // x, y, z
);graph.add(gtsam::PriorFactor<gtsam::Pose3>(0, priorPose, priorNoise));
  • 第一个参数 0 是变量的 Key(位姿 ID)。
  • priorPose 是已知的先验位姿。
  • priorNoise 控制先验约束的权重。

2.5 给变量一个初始值

initialEstimate.insert(0, gtsam::Pose3(gtsam::Rot3::RzRyRx(0.05, -0.02, 0.01), // 初始估计值(稍微有偏差)gtsam::Point3(0.1, -0.1, 0.05)
));

2.6 完整优化示例

#include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h>
#include <iostream>int main() {gtsam::NonlinearFactorGraph graph;gtsam::Values initialEstimate;auto priorNoise = gtsam::noiseModel::Diagonal::Sigmas((gtsam::Vector(6) << 0.1, 0.1, 0.1, 0.1, 0.1, 0.1).finished());gtsam::Pose3 priorPose(gtsam::Rot3::RzRyRx(0, 0, 0),gtsam::Point3(0, 0, 0));graph.add(gtsam::PriorFactor<gtsam::Pose3>(0, priorPose, priorNoise));initialEstimate.insert(0, gtsam::Pose3(gtsam::Rot3::RzRyRx(0.05, -0.02, 0.01),gtsam::Point3(0.1, -0.1, 0.05)));gtsam::LevenbergMarquardtOptimizer optimizer(graph, initialEstimate);gtsam::Values result = optimizer.optimize();std::cout << "优化结果:\n" << result.at<gtsam::Pose3>(0) << std::endl;
}

3. 常见坑点

  1. 只能加一个强先验

    • 通常只在第一个节点加先验,如果给多个节点加强先验,可能会导致系统过约束或优化失败。
  2. 噪声不要太小

    • 如果噪声过小(权重过大),优化会强行锁定该节点,导致误差无法被传播修正。
  3. 注意 Key 对应的节点存在性

    • 必须先 insert 或在优化前确保 Key 存在,否则会报错。
  4. 单位换算

    • 平移是米,旋转是弧度。经常有人把角度直接放进去导致优化结果异常。

GTSAM删除多余的先验位姿

GTSAM 里,“删除多余的先验位姿” 本质上是移除因子图里的多余 PriorFactor,因为先验是作为一个因子加入 NonlinearFactorGraph 的。

下面我们分为两种情况说明:


1. 如果是自己代码里误加了多余先验

最简单的方法:

  • 不要往因子图里添加多余的 PriorFactor,或者在添加时用条件判断只加一次。

示例:

if (pose_id == 0) { // 只在第一帧加先验graph.add(PriorFactor<Pose3>(0, Pose3(), poseNoise));
}

这样根本不会有多余的先验进入因子图。


2. 如果因子图已经有多余先验(运行中动态删除)

NonlinearFactorGraph 中,每个因子都有索引,可以按条件删除。

#include <gtsam/slam/PriorFactor.h>for (size_t i = 0; i < graph.size(); ++i) {auto factor = boost::dynamic_pointer_cast<gtsam::PriorFactor<gtsam::Pose3>>(graph[i]);if (factor && factor->key() != 0) { // 只保留第一个先验graph.remove(i); // 移除这个先验}
}

注意:

  • graph.remove(i) 会把对应因子移除(实际是置空 nullptr,不影响索引)。
  • 如果你要彻底压缩索引,可以用 graph.erase(std::remove(...)) 方式,但一般没必要。

3. 为什么要删除多余先验?

  • 多余先验 会过度约束图(尤其是多机器人、多传感器融合时),可能导致优化发散或强制对齐错误位置。
  • LiDAR-IMU 系统中,一般只对第一个时间节点加先验,其他位置的绝对参考用回环约束、GPS因子等替代。

4. 实战建议

如果是 LiDAR-Inertial-Mapping 或 SLAM:

  • 在建图时,只在第一帧(或地图初始关键帧)添加一个先验
  • 其他帧的绝对位置约束,用回环检测、GPS、地图匹配等因子实现。
  • 如果后处理要移除某个先验,建议在保存因子图(graph.save())前就清理。

http://www.dtcms.com/a/333298.html

相关文章:

  • STC8单片机驱动I2C屏幕:实现时间、日期与温湿度显示
  • 单片机闪烁灯实验
  • 健身房预约系统SSM+Mybatis实现(二、增删改查的具体实现)
  • 大模型——如何让 AI 绘图的中文呈现更稳定和准确
  • 墨水屏电子桌牌:企业数字化转型的绿色入口
  • Amazon SageMaker:让AI开发变得简单与高效
  • 【数据分享】上市公司创新韧性数据(2007-2023)
  • UDP与TCP协议的Python实现详解
  • C# 中的 string / StringBuilder / 值类型 / 引用类型 / CLR 总结
  • Vue模板引用(Template Refs)全解析1
  • ​​数字化时代的身份安全基石:4A平台如何重构企业访问控制体系​
  • excel中批量写sql时,选中日期列由数字转yyyy-mm-dd
  • es7.x中分片和节点关系以及查看节点数
  • Flink中基于时间的合流--双流联结(join)
  • MySQL(多表查询练习)
  • C++宏展开规则
  • 【数据可视化-90】2023 年城镇居民人均收入可视化分析:Python + pyecharts打造炫酷暗黑主题大屏
  • PyTorch 训练神经网络模型,并集成到springboot项目中
  • JavaScript 原型机制详解:从概念到实战(附个人学习方法)
  • 科普:Pygame 中,`pg.Surface` v.s. `screen`
  • 使用Docker容器化Python测试Pytest项目并配置GitHub Actions CI/CD流程
  • IgH初始化--未接从站
  • 一站式学会——进制转换与位运算符详解(通俗易懂)
  • ElasticSearch不同环境同步索引数据
  • 20250815在荣品RD-RK3588-MID开发板的Android13下调通TP芯片FT8206
  • linux安装docker-compose
  • STM32在使用DMA发送和接收时的模式区别
  • 使用C# 高效实现 Word 文档内容查找与替换的6种方法
  • Java 调用 Python 脚本:实现 HelloWorld
  • 数据驱动测试提升自动化效率