Skip to content

Commit 9630e6b

Browse files
[ImuFactor] Add an on manifold Imu Factor
Unit testing is left to a follow up commit. The core use-facing api is found in - symforce/slam/imu_preintegration/preintegrated_imu_measurements.h - symforce/slam/imu_preintegration/imu_factor.h Unlike most other factors (/residual functions) in symforce, the ImuFactor is a functor so as to store the pre-integrated values with the function rather than in the `Values`. (There are a lot of parameters that are constant and unique to each factor). A python version of the `ImuFactor` class will come in a subsequent commit. Topic: on_manifold_imu_factor
1 parent 4c36881 commit 9630e6b

18 files changed

Lines changed: 4185 additions & 0 deletions

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ install(DIRECTORY gen/cpp/ DESTINATION include FILES_MATCHING PATTERN "*.h" PATT
280280

281281
if(SYMFORCE_BUILD_OPT)
282282
add_subdirectory(symforce/opt)
283+
add_subdirectory(symforce/slam)
283284
endif()
284285

285286
if(SYMFORCE_BUILD_CC_SYM)

gen/cpp/sym/factors/internal/imu_manifold_preintegration_update.h

Lines changed: 845 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gen/cpp/sym/factors/internal/internal_imu_factor.h

Lines changed: 2377 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

symforce/geo/matrix.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,23 @@ def transpose(self) -> Matrix:
487487
"""
488488
return Matrix(self.mat.transpose())
489489

490+
def lower_triangle(self: MatrixT) -> MatrixT:
491+
"""
492+
Returns the lower triangle (including diagonal) of self
493+
494+
self must be square
495+
"""
496+
rows, cols = self.shape
497+
if rows != cols:
498+
raise ValueError(
499+
f"Attempted to take lower triangle of non-square matrix (found shape {self.shape})"
500+
)
501+
502+
lt = self.__class__()
503+
for k in range(rows):
504+
lt[k, : k + 1] = self[k, : k + 1]
505+
return lt
506+
490507
def reshape(self, rows: int, cols: int) -> Matrix:
491508
return Matrix(self.mat.reshape(rows, cols))
492509

symforce/pybind/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
# This source code is under the Apache 2.0 license found in the LICENSE file.
44
# ----------------------------------------------------------------------------
55

6+
# ==============================================================================
7+
# Third Party Dependencies
8+
# ==============================================================================
9+
610
include(FetchContent)
711

812
find_package(pybind11 QUIET)
@@ -21,6 +25,13 @@ else()
2125
message(STATUS "pybind11 found")
2226
endif()
2327

28+
# ==============================================================================
29+
# SymForce Targets
30+
# ==============================================================================
31+
32+
# ------------------------------------------------------------------------------
33+
# cc_sym
34+
2435
pybind11_add_module(
2536
cc_sym
2637
SHARED

symforce/slam/CMakeLists.txt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# ----------------------------------------------------------------------------
2+
# SymForce - Copyright 2022, Skydio, Inc.
3+
# This source code is under the Apache 2.0 license found in the LICENSE file.
4+
# ----------------------------------------------------------------------------
5+
6+
# ==============================================================================
7+
# SymForce Targets
8+
# ==============================================================================
9+
10+
file(GLOB_RECURSE SYMFORCE_SLAM_SOURCES CONFIGURE_DEPENDS *.cc **/*.cc)
11+
file(GLOB_RECURSE SYMFORCE_SLAM_HEADERS CONFIGURE_DEPENDS *.h **/*.h *.tcc **/*.tcc)
12+
13+
add_library(
14+
symforce_slam
15+
${SYMFORCE_LIBRARY_TYPE}
16+
${SYMFORCE_SLAM_SOURCES}
17+
${SYMFORCE_SLAM_HEADERS}
18+
)
19+
target_compile_options(symforce_slam PRIVATE ${SYMFORCE_COMPILE_OPTIONS})
20+
target_link_libraries(symforce_slam
21+
symforce_gen
22+
symforce_opt
23+
${SYMFORCE_EIGEN_TARGET}
24+
)

symforce/slam/__init__.py

Whitespace-only changes.

symforce/slam/imu_preintegration/__init__.py

Whitespace-only changes.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# ----------------------------------------------------------------------------
2+
# SymForce - Copyright 2022, Skydio, Inc.
3+
# This source code is under the Apache 2.0 license found in the LICENSE file.
4+
# ----------------------------------------------------------------------------
5+
6+
from symforce import codegen
7+
from symforce import typing as T
8+
from symforce.slam.imu_preintegration.manifold_symbolic import imu_manifold_preintegration_update
9+
from symforce.slam.imu_preintegration.manifold_symbolic import internal_imu_residual
10+
11+
12+
def generate_manifold_imu_preintegration(
13+
config: codegen.CodegenConfig, output_dir: T.Openable
14+
) -> None:
15+
"""
16+
Generate the on-manifold IMU preintegration update and residual functions.
17+
"""
18+
codegen_update = codegen.Codegen.function(
19+
imu_manifold_preintegration_update,
20+
config=config,
21+
output_names=[
22+
"new_DR",
23+
"new_Dv",
24+
"new_Dp",
25+
"new_covariance",
26+
"new_DR_D_gyro_bias",
27+
"new_Dp_D_gyro_bias",
28+
"new_Dp_D_accel_bias",
29+
"new_Dv_D_gyro_bias",
30+
"new_Dv_D_accel_bias",
31+
],
32+
)
33+
codegen_update.generate_function(output_dir=output_dir, skip_directory_nesting=True)
34+
35+
codegen_residual = codegen.Codegen.function(
36+
internal_imu_residual,
37+
config=config,
38+
).with_linearization(
39+
which_args=[
40+
"pose_i",
41+
"vel_i",
42+
"pose_j",
43+
"vel_j",
44+
"accel_bias_i",
45+
"gyro_bias_i",
46+
]
47+
)
48+
codegen_residual.generate_function(output_dir=output_dir, skip_directory_nesting=True)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/* ----------------------------------------------------------------------------
2+
* SymForce - Copyright 2022, Skydio, Inc.
3+
* This source code is under the Apache 2.0 license found in the LICENSE file.
4+
* ---------------------------------------------------------------------------- */
5+
6+
#include "./imu_factor.h"
7+
8+
#include <Eigen/Cholesky>
9+
10+
#include <sym/factors/internal/internal_imu_factor.h>
11+
12+
#include "preintegrated_imu_measurements.h"
13+
14+
namespace sym {
15+
16+
template <typename Scalar>
17+
ImuFactor<Scalar>::ImuFactor(const ImuPreintegrator<Scalar>& preintegrator)
18+
: preintegrated_measurements_{preintegrator.PreintegratedMeasurements()},
19+
// NOTE(brad, chao): llt then inverse is 2x faster than inverse then llt
20+
sqrt_info_{preintegrator.Covariance().llt().matrixL().solve(
21+
Eigen::Matrix<Scalar, 9, 9>::Identity())} {}
22+
23+
template <typename Scalar>
24+
sym::Factor<Scalar> ImuFactor<Scalar>::Factor(const std::vector<Key>& keys_to_func) const {
25+
const auto begin = keys_to_func.begin();
26+
// NOTE(brad): *this is copied. Keys to optimize happen to be first 6 keys to func
27+
return sym::Factor<Scalar>::Hessian(*this, keys_to_func, std::vector<Key>(begin, begin + 6));
28+
}
29+
30+
template <typename Scalar>
31+
void ImuFactor<Scalar>::operator()(
32+
const sym::Pose3<Scalar>& pose_i, const Eigen::Matrix<Scalar, 3, 1>& vel_i,
33+
const sym::Pose3<Scalar>& pose_j, const Eigen::Matrix<Scalar, 3, 1>& vel_j,
34+
const Eigen::Matrix<Scalar, 3, 1>& accel_bias_i, const Eigen::Matrix<Scalar, 3, 1>& gyro_bias_i,
35+
const Eigen::Matrix<Scalar, 3, 1>& gravity, const Scalar epsilon,
36+
Eigen::Matrix<Scalar, 9, 1>* const res, Eigen::Matrix<Scalar, 9, 24>* const jacobian,
37+
Eigen::Matrix<Scalar, 24, 24>* const hessian, Eigen::Matrix<Scalar, 24, 1>* const rhs) const {
38+
InternalImuFactor(
39+
pose_i, vel_i, pose_j, vel_j, accel_bias_i, gyro_bias_i, preintegrated_measurements_.DR,
40+
preintegrated_measurements_.Dv, preintegrated_measurements_.Dp, sqrt_info_,
41+
preintegrated_measurements_.DR_D_gyro_bias, preintegrated_measurements_.Dv_D_accel_bias,
42+
preintegrated_measurements_.Dv_D_gyro_bias, preintegrated_measurements_.Dp_D_accel_bias,
43+
preintegrated_measurements_.Dp_D_gyro_bias, preintegrated_measurements_.accel_bias,
44+
preintegrated_measurements_.gyro_bias, gravity, preintegrated_measurements_.integrated_dt,
45+
epsilon,
46+
// outputs
47+
res, jacobian, hessian, rhs);
48+
}
49+
50+
} // namespace sym
51+
52+
template class sym::ImuFactor<double>;
53+
template class sym::ImuFactor<float>;

0 commit comments

Comments
 (0)