历史快照
本专题页写于包拆分与 FAST-LIVO2 / CustomMsg / 图像输入落地之前,反映当时的单包结构与
五前端状态。已知过时点:目录布局(apps/launch 现属 asuka_ros 包)、共享的
config_sensor.json(外参已改为各前端 odometry 配置的 sensor 块)、ROS 层 acc_scale
等描述、前端数量(现六种,新增 fastlivo)、CustomMsg 与图像输入链路、thirdparty 收纳范围(2026-09-17 起 faster_ivox / small_ivox / tsl 已移至各算法模块的 include 目录)。点类型命名(2026-09-26 起为 PointXYZITRGB,时间字段由自定义 offset 改用 stock curvature)、batchlio 的 use_imu_as_input 已恢复上游默认 false(发散根因修复)。2026-09 下旬以来:lightning / superodom 前端与 optimization_miao 后端已移除
(现五前端:fastlio / batchlio / superlio / fastlivo / srlivo;smallpointlio 已于 2026-10-23 移除,odometry/10-11 为其历史快照);
freedom 扩展已整体迁出 asuka(移入 nagisa 包);KeyFrame::stamp 统一为扫描
起始时刻;执行器新增连续失败熔断与 wait_for() 排空检测、扩展与执行器有
ok() 健康查询。
现行事实以主文档 (index / architecture / parameters / odometry 等)与源码为准。
title: "BatchLIO 数学工具与公共结构" description: >- so3.hpp 提供 SO(3) 流形运算(4KB),common.hpp/cpp 沉淀批处理所需的公共数据结构与工具函数(各约 4-5KB)。
BatchLIO 数学工具与公共结构
本页覆盖 batchlio 子目录的地基层:so3.hpp(SO(3) 流形运算,header-only)与 common.hpp/cpp(状态流形定义、测量组、平面拟合与时间分窗工具)。上一页的 43.8KB 主流程中,IMU 传播、批内去畸变、点面残差、初始协方差——每一个环节都建立在这三个文件之上。阅读顺序上建议与"BatchLIO 里程计主流程"页对照:本页回答"状态长什么样、残差怎么算、批窗口怎么切"。
一个先要分清的结构细节:数学层统一位于命名空间 asuka::batch,而主流程类位于 asuka::batchlio(batchlio::OdometryEstimation 继承 asuka::OdometryEstimation),主流程通过 batch::MeasureGroup、batch::state_input 等限定名跨命名空间引用数学层。
so3.hpp:SO(3) 流形运算
全部为 asuka::batch 命名空间下的模板函数(可同时服务 float/double 实例化),围绕 Rodrigues 公式组织:
| 函数 | 语义 | 小角度处理 |
|---|---|---|
skew_sym_mat + 宏 SKEW_SYM_MATRX |
反对称(hat)矩阵,其余函数的公共底座 | — |
exp(ang) |
旋转向量 → 旋转矩阵 | norm ≤ 1e-7 返回单位阵 |
exp(ang_vel, dt) |
角速度 × dt 积分为旋转(IMU 传播用) | 同上 1e-7 |
exp(v1, v2, v3) |
三标量入参版本 | 阈值放宽至 1e-5 |
log(R) |
旋转矩阵 → 旋转向量 | trace > 3−1e-6 判为单位旋转;|theta| < 0.001 用一阶近似 0.5·k |
rot_mat_to_euler |
ZYX 欧拉角 | sy < 1e-6 进入万向锁分支(z 置 0) |
jacobian_right_inv |
SO(3) 右雅可比逆 | norm ≤ 1e-6 返回 I |
两个值得注意的实现细节:
jacobian_right_inv的模板参数T实际未参与返回类型(固定返回Eigen::Matrix3d),且形参是非 const 引用——阅读时不要被签名误导为通用精度版本。- 末尾的
so3_exp是 inline 非模板特化版,th < 1e-11时直接返回I + k一阶线性化,比模板版阈值更紧;紧随其后的deskew_point带有源码注释:按 Point-LIWO 论文式 3.44–3.47,在恒速假设下把批窗口内 t_j 时刻采样的 body 点映射到窗口参考时刻——r_j = so3_exp(omg·dt),平移项r_iᵀ·vel·dt。它与主流程的batch_deskew开关(odometry 头文件 L171)配套,是"批量式"LIO 区别于逐点去畸变的关键算子。
common.hpp/cpp:状态、测量组与工具
依赖与命名溯源
common.hpp 一口气引入了 esekfom/esekfom.hpp(MTK 流形宏)、faster_ivox/ivox3d.h(局部地图)、core/types.hpp(共享点类型)与本地 so3.hpp。源码中的分段注释保留了上游文件名——common_lib.h、Estimator.cpp、parameters.cpp——说明这一层是从上游 batchlio(Point-LIWO 系)代码移植而来,需要对照上游实现时可按注释定位。注意 IVoxType 的 include 路径是 faster_ivox,但实际使用 fasterlio::IVox 命名空间。
流形状态定义(EKF 的骨架)
| 流形 | 维度 | 字段 | 角色 |
|---|---|---|---|
state_input |
24 | pos, rot, offset_R_L_I, offset_T_L_I, vel, bg, ba, gravity | IMU 输入模式状态 |
state_output |
30 | 上述去掉输入、加上 omg, acc | 输出模式状态(角速度/加速度提升为状态量) |
input_ikfom |
6 | acc, gyro | EKF 控制输入 |
process_noise_input |
12 | ng, na, nbg, nba | 过程噪声 |
process_noise_output |
15 | vel, ng, na, nbg, nba | 过程噪声 |
DIM_STATE=24、DIM_PROC_N=12 与 input 轨严格对应。S2<double, 98090, 10000, 1>(FastLIO 经典参数)虽被 typedef,但五个流形字段均未用到,属上游遗留的可用品。点类型别名 PointType/PointCloudXYZI/PointVector 直接复用 core/types.hpp 的 PointXYZIOffset——其 offset 字段按仓库约定存放"点相对帧起点的毫秒级时间偏移",这是下面时间分窗能工作的前提。NUM_MATCH_POINTS=5、MAX_INI_COUNT=100 等宏同样来自上游。
MeasureGroup:批处理的核心载荷
这是 synchronize() 的产出物、process() 的输入(主流程头文件 L54–55 的签名即围绕它展开):
lidar_begin_time / lidar_end_time / lidar_last_time:批窗口的时间边界;lidar:帧点云;imu:窗口内 IMU 序列;imu_initialization:初始化专用 IMU 序列(对应主流程的initializing_imu标志);imu_after_end:恰在帧结束后的那条 IMU,供窗口收尾使用。
过程模型与雅可比(common.cpp)
四个无状态自由函数,因为 esekfom 只接受自由函数回调;主流程用 static trampoline + thread_local active 指针把成员观测模型桥接进来(odometry 头文件 L74–81):
| 函数 | 维度 | 语义要点 |
|---|---|---|
get_f_input |
→24 | pos˙=vel,rot˙=gyro⊟bg,vel˙=R(acc−ba)+g |
get_f_output |
→30 | omg/acc 直接取自状态本身 |
df_dx_input |
24×24 | ∂a/∂rot=−R·hat(acc−ba),∂a/∂ba=−R,∂a/∂g=I,∂ω/∂bg=−I |
df_dx_output |
30×30 | output 版本,偏置列符号取正 |
时间分窗与平面拟合
time_compressing:按offset递增分段,返回每个时间组的点数(即主流程的time_seq成员);time_compressing_batch(cloud, win_ms):把时间量化到win_ms毫秒窗口再计数——"批"粒度的调节旋钮;空点云返回空、win_ms ≤ 0回退到逐时刻版本;estimate_norm_vector(可变点数 + 逐点残差校验)与estimate_plane(固定 5 点,输出归一化 4 维平面系数(n/|n|, 1/|n|)):两者供观测模型h_model_input/output计算点面残差,主流程的normvec、point_selected_surf、plane_thr字段与之配套。注意一个易踩的坑:前者在未归一化系数上校验残差(后再 normalize),后者在归一化后校验,同一数值阈值在两处的物理含义(点到面距离的倍率)不同,复用参数时需换算。
参数与协方差工具
so3_to_euler 是 rot_mat_to_euler 的 MTK::SO3 版(逻辑重复,双份实现需同步维护);reset_cov/reset_cov_output 给出初始协方差基线——input 轨 24×24=0.1·I、gravity 块(21,21)=1e-4、(bg,ba) 6×6 块(15,15)=1e-3;output 轨 30×30=0.01·I、其余块同理右移到 (21,21)/(24,24);time_list 按 offset 升序的排序谓词,用于点云按时间重排。
调用链与依赖图
flowchart TB
subgraph DEP["外部依赖与核心类型"]
MTK["esekfom / MTK 流形库<br/>MTK_BUILD_MANIFOLD · hat · boxminus"]
IVOX["faster_ivox<br/>fasterlio::IVox<3, DEFAULT, PointT>"]
TYPES["asuka/core/types.hpp<br/>PointT=PointXYZIOffset(offset=时间ms)<br/>ImuData · PointVectorT"]
end
subgraph MATH["batchlio 数学与公共层(namespace asuka::batch)"]
SO3["so3.hpp<br/>exp×3 · log · 欧拉角<br/>jacobian_right_inv · so3_exp · deskew_point"]
CH["common.hpp<br/>流形状态×5 · MeasureGroup<br/>类型别名/宏 · 函数声明"]
CC["common.cpp<br/>get_f_* / df_dx_*<br/>time_compressing(_batch)<br/>reset_cov(_output) · time_list"]
end
ODO["batchlio::OdometryEstimation<br/>kf_input: esekf<state_input,24> / kf_output: esekf<state_output,30><br/>ivox · h_model_* + static trampoline"]
MTK --> CH
IVOX --> CH
TYPES --> CH
SO3 --> CH
CH --> CC
CH --> ODO
关键节点解读:common.hpp 是汇聚点,把第三方流形库、局部地图与仓库共享点类型融合成 asuka::batch 的领域词汇;common.cpp 只实现声明,二者构成"声明/实现"薄层;主流程类以 batch:: 限定名消费这一切——synchronize() 填 MeasureGroup,time_seq 来自 time_compressing(_batch),kf_input/kf_output 的模板参数直接绑定流形状态,deskew_point 服务批内去畸变。头文件私有方法序列(handle_first_scan → downsample_and_window → initialize_map → run_output_loop / run_input_loop → map_incremental → emit_outputs)勾勒出 process 的骨架,其迭代内核全部落到本页这些纯函数上。
边界条件与扩展点
边界条件集中在数值稳健性:三档 exp 小角度阈值(1e-7/1e-5/1e-11)、log 的 trace 判据与一阶近似、欧拉角万向锁分支、jacobian_right_inv 的小角回退、time_compressing_batch 的空点云与 win_ms ≤ 0 回退、两个平面拟合模板的残差失败返回 false(对应观测模型中剔除该点的 point_selected_surf 机制)。
扩展点:
1. input/output 双轨:use_imu_as_input(默认 false)切换两条 EKF 轨道,数学层已备好两套 f/Jacobian/协方差,切换不需要动数学层;
2. 批处理参数:batch_dt(默认 1ms)、batch_deskew、batch_omp、win_ms 全部作为 odometry 参数存在,数学层保持纯函数、无状态,便于并行(batch_omp)与调参;
3. 修改状态维度的连带清单:MTK_BUILD_MANIFOLD、DIM_STATE/DIM_PROC_N、get_f_*/df_dx_*、reset_cov(_output)、主流程的 p_input/p_output/q_input/q_output 必须同步修改,维度在编译期由模板锁死,改漏会直接编译失败(这反而是保护);
4. 模板精度:平面拟合模板支持 float/double 双实例化,但右雅可比与 so3_exp 固定 double,混用前需确认。
Sources:
- src/asuka/include/asuka/odometry/batchlio/so3.hpp#L1-L118
- src/asuka/include/asuka/odometry/batchlio/common.hpp#L1-L155
- src/asuka/src/asuka/odometry/batchlio/common.cpp#L1-L128
- src/asuka/include/asuka/odometry/batchlio/odometry_estimation.hpp#L1-L188
- src/asuka/include/asuka/core/types.hpp#L1-L96
- src/asuka/src/asuka/odometry/batchlio/odometry_estimation.cpp#L1-L160
关联源码
src/asuka/include/asuka/odometry/batchlio/so3.hppsrc/asuka/include/asuka/odometry/batchlio/common.hppsrc/asuka/src/asuka/odometry/batchlio/common.cpp