My Project 1.0
Holistic Fusion: A Generic Framework for Multimodal Sensor Fusion
Loading...
Searching...
No Matches
GmsfUnaryExpression.h
Go to the documentation of this file.
1/*
2Copyright 2024 by Julian Nubert, Robotic Systems Lab, ETH Zurich.
3All rights reserved.
4This file is released under the "BSD-3-Clause License".
5Please see the LICENSE file that has been included as part of this package.
6 */
7
8#ifndef GMSF_UNARY_EXPRESSION_H
9#define GMSF_UNARY_EXPRESSION_H
10
11// C++
12#include <mutex>
13
14// GTSAM
15#include <gtsam/base/types.h>
16#include <gtsam/linear/NoiseModel.h>
17#include <gtsam/navigation/NavState.h>
18#include <gtsam/nonlinear/expressions.h>
19#include <gtsam/slam/BetweenFactor.h>
20#include <gtsam/slam/PriorFactor.h>
21
22// Workspace
25
26namespace holistic_fusion {
27
29
30// Function for composing rigid body transformations with GTSAM expression factors
31inline gtsam::Pose3_ composeRigidTransformations(const gtsam::Pose3_& T_frame1_frame2, const gtsam::Pose3_& T_frame2_frame3) {
32 return gtsam::Pose3_(T_frame1_frame2, &gtsam::Pose3::transformPoseFrom, T_frame2_frame3);
33}
34
35// Function for Transposing of a Rot3
36inline gtsam::Rot3_ inverseRot3(const gtsam::Rot3_& R) {
37 return gtsam::Rot3_(&gtsam::LieGroup<gtsam::Rot3, 3>::inverse, R);
38}
39
50template <class GTSAM_MEASUREMENT_TYPE, UnaryExpressionType TYPE, char CALIBRATION_CHAR>
52 public:
53 // Type of the Template
54 using template_type = GTSAM_MEASUREMENT_TYPE;
55
56 // Constructor
57 GmsfUnaryExpression(const std::shared_ptr<UnaryMeasurement>& gmsfBaseUnaryMeasurementPtr, const std::string& imuFrameName,
58 const Eigen::Isometry3d& T_I_sensorFrame)
59 : gmsfBaseUnaryMeasurementPtr_(gmsfBaseUnaryMeasurementPtr), imuFrame_(imuFrameName), T_I_sensorFrameInit_(T_I_sensorFrame) {}
60
61 // Destructor
63
64 // Main method for creating the expression
65 gtsam::Expression<GTSAM_MEASUREMENT_TYPE> createAndReturnExpression(const gtsam::Key& closestGeneralKey,
66 DynamicDictionaryContainer& gtsamDynamicExpressionKeys,
67 const gtsam::NavState& W_imuPropagatedState,
68 const bool optimizeReferenceFramePosesWrtWorldFlag,
69 const bool centerMeasurementsAtKeyframePositionBeforeAlignmentFlag,
70 const bool optimizeExtrinsicSensorToSensorCorrectedOffsetFlag) {
71 // Measurement Pointer
72 const auto& gmsfUnaryMeasurement = *getGmsfBaseUnaryMeasurementPtr();
73
74 // A. Generate Expression for Basic IMU State in World Frame at Key --------------------------------
75 generateImuStateInWorldFrameAtKey(closestGeneralKey);
76
77 // B.A. Holistic Fusion: Optimize over reference frame poses --------------------------------------------
78 if constexpr (TYPE == UnaryExpressionType::Absolute) {
79 if (optimizeReferenceFramePosesWrtWorldFlag) {
80 transformImuStateFromWorldToReferenceFrame(gtsamDynamicExpressionKeys, W_imuPropagatedState,
81 centerMeasurementsAtKeyframePositionBeforeAlignmentFlag);
82 }
83 }
84
85 // B.B. Holistic Fusion: Create Landmark State in Dynamic Memory -------------------------------------
86 if constexpr (TYPE == UnaryExpressionType::Landmark) {
87 transformLandmarkInWorldToImuFrame(gtsamDynamicExpressionKeys, W_imuPropagatedState);
88 }
89
90 // C. Transform State to Sensor Frame -----------------------------------------------------
91 if (gmsfUnaryMeasurement.sensorFrameName() != imuFrame_) {
93 }
94
95 // D. Extrinsic Calibration: Add correction to sensor pose -----------------------------------------
96 if (optimizeExtrinsicSensorToSensorCorrectedOffsetFlag) {
98 }
99
100 // Return
101 return getGtsamExpression();
102 }
103
104 // Noise as GTSAM Datatype
105 virtual const gtsam::Vector getNoiseDensity() const = 0;
106
107 // Return Measurement as GTSAM Datatype
108 virtual const GTSAM_MEASUREMENT_TYPE getGtsamMeasurementValue() const = 0;
109
110 virtual const std::shared_ptr<UnaryMeasurement>& getGmsfBaseUnaryMeasurementPtr() { return gmsfBaseUnaryMeasurementPtr_; }
111
112 // Time
113 [[nodiscard]] double getTimestamp() const { return gmsfBaseUnaryMeasurementPtr_->timeK(); }
114
115 // New Values
116 [[nodiscard]] const gtsam::Values& getNewOnlineGraphStateValues() const { return newOnlineStateValues_; }
117
118 [[nodiscard]] const gtsam::Values& getNewOfflineGraphStateValues() const { return newOfflineStateValues_; }
119
120 // New Prior Factors
121 const std::vector<gtsam::PriorFactor<gtsam::Pose3>>& getNewOnlinePosePriorFactors() const { return newOnlinePosePriorFactors_; }
122
123 const std::vector<gtsam::PriorFactor<GTSAM_MEASUREMENT_TYPE>>& getNewOnlineDynamicPriorFactors() const {
125 }
126
127 // New Between Factors
128 const std::vector<gtsam::BetweenFactor<gtsam::Pose3>>& getNewOnlineAndOfflinePoseBetweenFactors() const {
130 }
131
132 // Get Imu to sensor frame calibration
133 [[nodiscard]] const Eigen::Isometry3d& getT_I_sensorFrameInit() const { return T_I_sensorFrameInit_; }
134
135 protected:
136 // Methods ---------------------------------------------------------------------
137 // Four cases (non-exclusive, but has to be correct order!):
138 // i) Generate Expression for Basic IMU State in World Frame at Key
139 virtual void generateImuStateInWorldFrameAtKey(const gtsam::Key& closestGeneralKey) = 0;
140
141 // ii).A Holistically optimize over fixed frames
143 const gtsam::NavState& W_currentPropagatedState,
144 const bool centerMeasurementsAtKeyframePositionBeforeAlignmentFlag) = 0;
145
146 // ii).B Adding landmark state in dynamic memory
147 virtual void transformLandmarkInWorldToImuFrame(DynamicDictionaryContainer& gtsamDynamicExpressionKeys,
148 const gtsam::NavState& W_currentPropagatedState) = 0;
149
150 // iii) Transform state to sensor frame
152
153 // iv) Extrinsic calibration
155 // Mutex because we are changing the dynamically allocated graphKeys
156 std::lock_guard<std::mutex> modifyGraphKeysLock(gtsamDynamicExpressionKeys.get<gtsam::Pose3>().mutex());
157
158 // Initial Guess
159 GTSAM_MEASUREMENT_TYPE initialGuess = GTSAM_MEASUREMENT_TYPE::Identity();
160
161 // Search for new graph key
162 bool newGraphKeyAddedFlag = false;
164 DynamicFactorGraphStateKey graphKey = gtsamDynamicExpressionKeys.get<gtsam::Pose3>().getTransformationKey<CALIBRATION_CHAR>(
165 newGraphKeyAddedFlag, gmsfBaseUnaryMeasurementPtr_->sensorFrameName(), gmsfBaseUnaryMeasurementPtr_->sensorFrameCorrectedName(),
166 gmsfBaseUnaryMeasurementPtr_->timeK(), convertToPose3(initialGuess), variableType);
167
168 // Define expression
169 gtsam::Expression<GTSAM_MEASUREMENT_TYPE> exp_C_sensorFrame_sensorFrameCorrected(graphKey.key());
170
171 // Apply calibration correction
172 this->applyExtrinsicCalibrationCorrection(exp_C_sensorFrame_sensorFrameCorrected); // Virtual method to be implemented
173
174 // If key was newly added, just add a value to the new state values to online and offline graph (as completely new)
175 if (newGraphKeyAddedFlag) {
176 // Add value to new state values of online and offline graph
177 newOnlineStateValues_.insert(graphKey.key(), initialGuess);
178 newOfflineStateValues_.insert(graphKey.key(), initialGuess);
179 // Add prior factor to online graph --> make sure it is not fully unconstrained
180 // newOnlineDynamicPriorFactors_.emplace_back(
181 // graphKey.key(), initialGuess,
182 // gtsam::noiseModel::Gaussian::Covariance(gtsam::Matrix::Identity(GTSAM_MEASUREMENT_TYPE::dimension,
183 // GTSAM_MEASUREMENT_TYPE::dimension)));
184 // New key has to be active
185 assert(graphKey.isVariableActive());
186 }
187 // If the key is inactive(), we have to activate it again and add a prior with the previous belief ONLY to the online graph
188 // TODO: Finish up
189 else if (!graphKey.isVariableActive() && graphKey.getNumberStepsOptimized() > 0) {
190 assert(graphKey.getNumberStepsOptimized() > 0);
191 REGULAR_COUT << " GmsfUnaryExpression: Transformation between " << gmsfBaseUnaryMeasurementPtr_->sensorFrameName() << " and "
192 << gmsfBaseUnaryMeasurementPtr_->sensorFrameCorrectedName()
193 << " was inactive. Activating it again and adding a prior to the online graph." << std::endl;
194 // Add prior factor
195 gtsam::Pose3 priorBelief = graphKey.getTransformationAfterOptimization(); // TODO: Does not have to be 6D
196 gtsam::Matrix66 priorCovariance = graphKey.getCovarianceAfterOptimization();
197 // Convert back to GTSAM_MEASUREMENT_TYPE
198 GTSAM_MEASUREMENT_TYPE priorBeliefConverted = convertFromPose3(priorBelief);
199 gtsam::Matrix priorCovarianceConverted = priorCovariance.bottomRightCorner<6, 6>(); // TODO: Not correct
200 // Add prior factor to online graph
201 newOnlineDynamicPriorFactors_.emplace_back(graphKey.key(), priorBeliefConverted,
202 gtsam::noiseModel::Gaussian::Covariance(priorCovarianceConverted));
203 // Add value to new state values of online graph
204 newOnlineStateValues_.insert(graphKey.key(), priorBeliefConverted);
205 // Activate key and set number of steps optimized to 0
206 graphKey.activateVariable();
207 graphKey.resetNumberStepsOptimized();
208 }
209 // If it was never optimized, we can also remove it as we will not be able to reactivate it
210 else if (!graphKey.isVariableActive() && graphKey.getNumberStepsOptimized() == 0) {
211 REGULAR_COUT << " GmsfUnaryExpression: Transformation between " << gmsfBaseUnaryMeasurementPtr_->sensorFrameName() << " and "
212 << gmsfBaseUnaryMeasurementPtr_->sensorFrameCorrectedName()
213 << " is deactivated but was never optimized. Hence, Removing it from the graph." << std::endl;
214 // Remove key
215 DynamicFactorGraphStateKey<gtsam::Pose3> keyToRemoveOrDeactivate;
216 std::ignore = gtsamDynamicExpressionKeys.get<gtsam::Pose3>().removeTransform(gmsfBaseUnaryMeasurementPtr_->sensorFrameName(),
217 gmsfBaseUnaryMeasurementPtr_->sensorFrameCorrectedName(),
218 keyToRemoveOrDeactivate);
219 }
220 }
221
223 const gtsam::Expression<GTSAM_MEASUREMENT_TYPE>& exp_C_sensorFrame_sensorFrameCorrected) = 0;
224
225 // TODO: Make clean, GTSAM_MEASUREMENT_TYPE is not always the type of our dynamic variables
226
227 virtual gtsam::Pose3 convertToPose3(const GTSAM_MEASUREMENT_TYPE& measurement) = 0;
228
229 virtual GTSAM_MEASUREMENT_TYPE convertFromPose3(const gtsam::Pose3& pose) = 0;
230
231 // Return Expression
232 virtual const gtsam::Expression<GTSAM_MEASUREMENT_TYPE> getGtsamExpression() const = 0;
233
234 // Members ---------------------------------------------------------------------
235 // Main Measurement Pointer
236 // Full Measurement Type
237 const std::shared_ptr<UnaryMeasurement> gmsfBaseUnaryMeasurementPtr_;
238
239 // Frame Name References
240 const std::string imuFrame_;
241
242 // IMU to Sensor Frame
243 Eigen::Isometry3d T_I_sensorFrameInit_;
244
245 // Containers
246 // New Values
249 // New Prior Factors
250 std::vector<gtsam::PriorFactor<gtsam::Pose3>> newOnlinePosePriorFactors_;
251 // TODO: Make this more general
252 std::vector<gtsam::PriorFactor<GTSAM_MEASUREMENT_TYPE>> newOnlineDynamicPriorFactors_;
253 // New Between Factors
254 std::vector<gtsam::BetweenFactor<gtsam::Pose3>> newOnlineAndOfflinePoseBetweenFactors_;
255};
256
257} // namespace holistic_fusion
258
259#endif // GMSF_UNARY_EXPRESSION_H
#define REGULAR_COUT
DynamicTransformDictionary< GTSAM_DYNAMIC_STATE_TYPE > & get()
const gtsam::Matrix66 & getCovarianceAfterOptimization() const
const GTSAM_TRANSFORM_TYPE & getTransformationAfterOptimization() const
const std::shared_ptr< UnaryMeasurement > gmsfBaseUnaryMeasurementPtr_
virtual void transformImuStateToSensorFrameState()=0
const std::vector< gtsam::BetweenFactor< gtsam::Pose3 > > & getNewOnlineAndOfflinePoseBetweenFactors() const
const gtsam::Values & getNewOfflineGraphStateValues() const
virtual void transformLandmarkInWorldToImuFrame(DynamicDictionaryContainer &gtsamDynamicExpressionKeys, const gtsam::NavState &W_currentPropagatedState)=0
virtual const gtsam::Vector getNoiseDensity() const =0
virtual void transformImuStateFromWorldToReferenceFrame(DynamicDictionaryContainer &gtsamDynamicExpressionKeys, const gtsam::NavState &W_currentPropagatedState, const bool centerMeasurementsAtKeyframePositionBeforeAlignmentFlag)=0
virtual void applyExtrinsicCalibrationCorrection(const gtsam::Expression< GTSAM_MEASUREMENT_TYPE > &exp_C_sensorFrame_sensorFrameCorrected)=0
std::vector< gtsam::BetweenFactor< gtsam::Pose3 > > newOnlineAndOfflinePoseBetweenFactors_
virtual GTSAM_MEASUREMENT_TYPE convertFromPose3(const gtsam::Pose3 &pose)=0
virtual gtsam::Pose3 convertToPose3(const GTSAM_MEASUREMENT_TYPE &measurement)=0
virtual void generateImuStateInWorldFrameAtKey(const gtsam::Key &closestGeneralKey)=0
GmsfUnaryExpression(const std::shared_ptr< UnaryMeasurement > &gmsfBaseUnaryMeasurementPtr, const std::string &imuFrameName, const Eigen::Isometry3d &T_I_sensorFrame)
const std::vector< gtsam::PriorFactor< gtsam::Pose3 > > & getNewOnlinePosePriorFactors() const
const std::vector< gtsam::PriorFactor< GTSAM_MEASUREMENT_TYPE > > & getNewOnlineDynamicPriorFactors() const
virtual const GTSAM_MEASUREMENT_TYPE getGtsamMeasurementValue() const =0
std::vector< gtsam::PriorFactor< GTSAM_MEASUREMENT_TYPE > > newOnlineDynamicPriorFactors_
const gtsam::Values & getNewOnlineGraphStateValues() const
virtual void transformSensorFrameStateToSensorFrameCorrectedState(DynamicDictionaryContainer &gtsamDynamicExpressionKeys)
virtual const std::shared_ptr< UnaryMeasurement > & getGmsfBaseUnaryMeasurementPtr()
virtual const gtsam::Expression< GTSAM_MEASUREMENT_TYPE > getGtsamExpression() const =0
const Eigen::Isometry3d & getT_I_sensorFrameInit() const
gtsam::Expression< GTSAM_MEASUREMENT_TYPE > createAndReturnExpression(const gtsam::Key &closestGeneralKey, DynamicDictionaryContainer &gtsamDynamicExpressionKeys, const gtsam::NavState &W_imuPropagatedState, const bool optimizeReferenceFramePosesWrtWorldFlag, const bool centerMeasurementsAtKeyframePositionBeforeAlignmentFlag, const bool optimizeExtrinsicSensorToSensorCorrectedOffsetFlag)
std::vector< gtsam::PriorFactor< gtsam::Pose3 > > newOnlinePosePriorFactors_
gtsam::Rot3_ inverseRot3(const gtsam::Rot3_ &R)
gtsam::Pose3_ composeRigidTransformations(const gtsam::Pose3_ &T_frame1_frame2, const gtsam::Pose3_ &T_frame2_frame3)
static DynamicVariableType Global(const double variableCreationTime)