My Project 1.0
Holistic Fusion: A Generic Framework for Multimodal Sensor Fusion
Loading...
Searching...
No Matches
HolisticFusionDualGraph.cpp
Go to the documentation of this file.
1/*
2Copyright 2022 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
10
11namespace holistic_fusion {
12
13// Public -----------------------------------------------------------
15DualHolisticFusion::DualHolisticFusion() : HolisticFusion() {
16 std::cout << YELLOW_START << "DualGMsf" << GREEN_START << " Instance created." << COLOR_END
17 << " Waiting for setup() with graphConfiguration and staticTransforms." << std::endl;
18
19 globalGraphKeysTimestampsMapBufferPtr_ = std::make_shared<std::map<gtsam::Key, double>>();
20 fallbackGraphKeysTimestampsMapBufferPtr_ = std::make_shared<std::map<gtsam::Key, double>>();
21
22 // Wrap up ----------------------------------------------------------------
23 // Set active graph to global graph in the beginning
24 activeSmootherPtr_ = globalSmootherPtr_;
25 activeFactorsBufferPtr_ = globalFactorsBufferPtr_;
26 activeImuBufferPreintegratorPtr_ = globalImuBufferPreintegratorPtr_;
27 activeGraphValuesBufferPtr_ = globalGraphValuesBufferPtr_;
28 activeGraphKeysTimestampsMapBufferPtr_ = globalGraphKeysTimestampsMapBufferPtr_;
29}
30
31std::shared_ptr<SafeNavState> HolisticFusion::addDualOdometryMeasurementAndReturnNavState(const UnaryMeasurement6D& odometryKm1,
32 const UnaryMeasurement6D& odometryK,
33 const Eigen::Matrix<double, 6, 1>& poseBetweenNoise) {
34 // Measurement
35 const Eigen::Isometry3d T_M_Lj = odometryK.measurementPose();
36
37 // Check whether World->Map is already set
38 if (!validFirstMeasurementReceivedFlag_) {
39 Eigen::Isometry3d T_M_Ij =
40 Eigen::Isometry3d(T_M_Lj) * staticTransformsPtr_->rv_T_frame1_frame2(odometryK.frameName(), staticTransformsPtr_->getImuFrame());
41 preIntegratedNavStatePtr_->updatePoseInMap(T_M_Ij);
42 // Received
43 validFirstMeasurementReceivedFlag_ = true;
44 }
45
46 // Only take actions if graph has been initialized
47 if (!initedGraphFlag_) {
48 return nullptr;
49 }
50
52 const Eigen::Isometry3d T_Lkm1_Lk(odometryKm1.measurementPose().inverse() * odometryK.measurementPose());
53 const Eigen::Isometry3d T_Ikm1_Ik =
54 staticTransformsPtr_->rv_T_frame1_frame2(staticTransformsPtr_->getImuFrame(), odometryKm1.frameName()) * T_Lkm1_Lk *
55 staticTransformsPtr_->rv_T_frame1_frame2(odometryK.frameName(), staticTransformsPtr_->getImuFrame());
56 const gtsam::Key keyAtMeasurementK =
57 graphMgrPtr_->addPoseBetweenFactorToGlobalGraph(odometryKm1.timeK(), odometryK.timeK(), odometryK.measurementRate(), poseBetweenNoise,
58 gtsam::Pose3(T_Ikm1_Ik.matrix()), odometryK.measurementName());
59
60 // Trigger Optimization
61 {
62 // Mutex for optimizeGraph Flag
63 const std::lock_guard<std::mutex> optimizeGraphLock(optimizeGraphMutex_);
64 optimizeGraphFlag_ = true;
65 }
66
67 // Create Pseudo Unary Factor ---------------------------------------------------
68
69 if (graphMgrPtr_->globalGraphActiveFlag()) { // Case 1: Global graph --> Compute World to Map frame // Lidar State
70 // Calculate imu state of LiDAR timestamp
71 bool computeSuccessfulFlag = false;
72 Eigen::Isometry3d T_W_Ij_Graph(graphMgrPtr_->calculateActiveStateAtKey(computeSuccessfulFlag, keyAtMeasurementK).pose().matrix());
73 if (computeSuccessfulFlag) {
74 Eigen::Isometry3d T_M_Ij =
75 Eigen::Isometry3d(T_M_Lj) * staticTransformsPtr_->rv_T_frame1_frame2(odometryK.frameName(), staticTransformsPtr_->getImuFrame());
76 preIntegratedNavStatePtr_->updateWorldToMap(T_W_Ij_Graph * T_M_Ij.inverse());
77 }
78 } else if (graphMgrPtr_->fallbackGraphActiveFlag()) { // Case 1: Fallback graph --> Add pseudo unary factor to fallback graph
80 gtsam::Pose3 pseudo_T_W_Ik(
81 preIntegratedNavStatePtr_->getT_W_M() * T_M_Lj *
82 staticTransformsPtr_->rv_T_frame1_frame2(odometryK.frameName(), staticTransformsPtr_->getImuFrame()).matrix());
83 graphMgrPtr_->addPoseUnaryFactorToFallbackGraph(odometryK.timeK(), odometryK.measurementRate(), odometryK.measurementNoise(),
84 pseudo_T_W_Ik);
85 }
86
87 // Trigger Optimization
88 {
89 // Mutex for optimizeGraph Flag
90 const std::lock_guard<std::mutex> optimizeGraphLock(optimizeGraphMutex_);
91 optimizeGraphFlag_ = true;
92 }
93
94 return std::make_shared<SafeNavState>(*preIntegratedNavStatePtr_);
95}
96
97// Counter is only counted if graph switching attemptGraphSwitching is off
98void HolisticFusion::addDualGnssPositionMeasurement(const UnaryMeasurement3D& W_t_W_frame, const Eigen::Vector3d& W_t_W_frame_km1,
99 const Eigen::Vector3d& gnssCovarianceXYZ, const bool attemptGraphSwitching,
100 const bool addedYawBefore) {
101 // Check covariance
102 bool gnssCovarianceViolatedFlagThisTimestep = isGnssCovarianceViolated_(gnssCovarianceXYZ);
103 // Handle GNSS Covariance Violation
104 if (gnssCovarianceViolatedFlagThisTimestep) { // If Violated
105 // Printout
106 if (!gnssCovarianceViolatedFlag_) {
107 std::cout << YELLOW_START << "GMsf" << RED_START << " Gnss measurments now ABSENT due to too big covariance." << COLOR_END
108 << std::endl;
109 }
110 // Set Flag
111 gnssCovarianceViolatedFlag_ = true;
112 gnssNotJumpingCounter_ = 0;
113 } else { // If not violated
114 // Valid measurement received
115 if (!validFirstMeasurementReceivedFlag_) {
116 validFirstMeasurementReceivedFlag_ = true;
117 }
118 // Printout
119 if (gnssCovarianceViolatedFlag_) {
120 std::cout << YELLOW_START << "GMsf" << GREEN_START << " Gnss returned. Low covariance. Now Waiting for GNSS not jumping." << COLOR_END
121 << std::endl;
122 }
123 // Set Flag
124 gnssCovarianceViolatedFlag_ = false;
125 }
126
127 // Only take actions if graph has been initialized
128 if (!initedGraphFlag_) {
129 return;
130 }
131
132 // Gnss jumping?
133 if (!gnssCovarianceViolatedFlag_ &&
134 (W_t_W_frame_km1 - W_t_W_frame.measurementVector()).norm() < graphConfigPtr_->poseMotionOutlierThresold) {
135 ++gnssNotJumpingCounter_;
136 if (gnssNotJumpingCounter_ == REQUIRED_GNSS_NUM_NOT_JUMPED) {
137 std::cout << YELLOW_START << "GMsf" << GREEN_START << " Gnss was not jumping recently. Jumping counter valid again." << COLOR_END
138 << std::endl;
139 }
140 } else if ((W_t_W_frame_km1 - W_t_W_frame.measurementVector()).norm() >= graphConfigPtr_->poseMotionOutlierThresold) {
141 if (gnssNotJumpingCounter_ >= REQUIRED_GNSS_NUM_NOT_JUMPED) {
142 std::cout << YELLOW_START << "GMsf" << RED_START << " Gnss was jumping more than the allowed distance of "
143 << graphConfigPtr_->poseMotionOutlierThresold << "m. Reset outlier counter." << COLOR_END << std::endl;
144 }
145 gnssNotJumpingCounter_ = 0;
146 }
147
148 // Modifying graph
149 if (!gnssCovarianceViolatedFlag_) { // Case 1: Gnss is good --> Write to graph and perform logic
150 gtsam::Rot3 R_W_I_meas(preIntegratedNavStatePtr_->getT_W_Ik().rotation());
151 Eigen::Vector3d W_T_W_I = W_t_W_frame.measurementVector();
152 // Check whether yaw has been added before --> use this then for position computation
153 if (addedYawBefore) {
154 R_W_I_meas = gtsam::Rot3::Ypr(lastGnssYaw_W_I_, R_W_I_meas.pitch(), R_W_I_meas.roll());
155 W_T_W_I = W_t_W_Frame1_to_W_t_W_Frame2_(W_T_W_I, W_t_W_frame.frameName(), staticTransformsPtr_->getImuFrame(), R_W_I_meas.matrix());
156 }
157
158 // Check whether GNSS has just returned, if attempting graph switching then do it
159 // if (gnssNotJumpingCounter_ == REQUIRED_GNSS_NUM_NOT_JUMPED && attemptGraphSwitching) {
160 graphMgrPtr_->activateGlobalGraph(W_T_W_I, R_W_I_meas, W_t_W_frame.timeK());
161 // }
162 // If GNSS is not jumping already for a while, then add position measurement
163 if ((gnssNotJumpingCounter_ >= REQUIRED_GNSS_NUM_NOT_JUMPED)) {
164 addGnssPositionMeasurement(W_t_W_frame);
165 }
166 } else if (graphConfigPtr_->usingFallbackGraphFlag) { // Case 2: Gnss is bad --> Do not write to graph, switch to fallback graph
167 // Case: Gnss is bad --> Do not write to graph, set flags for odometry unary factor to true
168 graphMgrPtr_->activateFallbackGraph();
169 }
170}
171
172void GraphManager::activateGlobalGraph(const gtsam::Vector3& imuPosition, const gtsam::Rot3& imuRotation, const double measurementTime) {
173 // Mutex, such s.t. the used graph is consistent
174 const std::lock_guard<std::mutex> swappingActiveGraphLock(swappingActiveGraphMutex_);
175 if (activeSmootherPtr_ != globalSmootherPtr_) {
176 // Activate global graph
177 int smootherNumberStates = int(graphConfigPtr_->smootherLag * graphConfigPtr_->imuRate);
178 gtsam::NonlinearFactorGraph globalFactorsBuffer;
179 gtsam::Values globalGraphValues;
180 std::map<gtsam::Key, double> globalGraphKeysTimestampsMap;
181 bool optimizeGraphFlag = false;
182 gtsam::Key currentPropagatedKey;
183 double currentPropagatedTime;
184
185 // Check graph data with lock: Mutex Block 1 ------------------
186 {
187 const std::lock_guard<std::mutex> operateOnGraphDataLock(operateOnGraphDataMutex_);
188 currentPropagatedKey = propagatedStateKey_;
189 currentPropagatedTime = propagatedImuSampleTime_;
190 int lastKeyInSmoother = (--globalSmootherPtr_->timestamps().end())->first;
191
192 std::cout << YELLOW_START << "GMsf-GraphManager" << GREEN_START << " Last Key in Smoother is: " << lastKeyInSmoother
193 << ", current key is: " << currentPropagatedKey << COLOR_END << std::endl;
194 if (lastKeyInSmoother < (int(currentPropagatedKey) - smootherNumberStates)) {
195 optimizeGraphFlag = true;
196 std::cout
197 << YELLOW_START << "GMsf-GraphManager" << GREEN_START
198 << " Hence, previous global graph is too old --> previously optimized graph can not be used --> shrinking and re-optimizing..."
199 << COLOR_END << std::endl;
200
201 // Copy
202 globalFactorsBuffer = *globalFactorsBufferPtr_;
203 globalGraphValues = *globalGraphValuesBufferPtr_;
204 globalGraphKeysTimestampsMap = *globalGraphKeysTimestampsMapBufferPtr_;
205 globalFactorsBufferPtr_->resize(0);
206 globalGraphValuesBufferPtr_->clear();
207 globalGraphKeysTimestampsMapBufferPtr_->clear();
208 if (graphConfigPtr_->usingBiasForPreIntegrationFlag) {
209 globalImuBufferPreintegratorPtr_->resetIntegrationAndSetBias(optimizedGraphState_.imuBias());
210 } else {
211 globalImuBufferPreintegratorPtr_->resetIntegrationAndSetBias(gtsam::imuBias::ConstantBias());
212 }
213 } else {
214 std::cout << YELLOW_START << "GMsf-GraphManager" << GREEN_START << " Hence, previously optimized graph can be used." << COLOR_END
215 << std::endl;
216 }
217 }
218
219 if (optimizeGraphFlag) {
220 // Find closest key
221 double closestGraphTimeToGnssMeasurement;
222 gtsam::Key closestKeyToGnssMeasurement;
223 timeToKeyBuffer_.getClosestKeyAndTimestamp(closestGraphTimeToGnssMeasurement, closestKeyToGnssMeasurement, "GnssUnary",
224 graphConfigPtr_->maxSearchDeviation, measurementTime);
225
226 // Reoptimization of global graph outside of lock ---------------
227 // Add prior factor for observability
228 std::cout << YELLOW_START << "GMsf-GraphManager" << GREEN_START << " Adding prior factor for GNSS key " << closestKeyToGnssMeasurement
229 << COLOR_END << std::endl;
230 // Putting high uncertainty for pose prior because GNSS factors are added that constrain x,y,z and yaw
231 // Roll and pitch are not constrained, and correct also in fallback graph, hence lower uncertainty for these
232 // Pose
233 // gtsam::Pose3 providedPose(imuRotation, imuPosition);
234 gtsam::Pose3 providedPose(globalGraphValues.at<gtsam::Pose3>(gtsam::symbol_shorthand::X(currentPropagatedKey)).rotation(),
235 imuPosition);
236 // Set Translation To Imu Position
237 gtsam::PriorFactor<gtsam::Pose3> posePrior(
238 gtsam::symbol_shorthand::X(closestKeyToGnssMeasurement), providedPose,
239 gtsam::noiseModel::Diagonal::Sigmas((gtsam::Vector(6) << 1e-05, 1e-05, 1e-02, 1e02, 1e02, 1e02).finished()));
240 globalFactorsBuffer.add(posePrior);
241 // Velocity
242 gtsam::PriorFactor<gtsam::Vector3> velPrior(gtsam::symbol_shorthand::V(currentPropagatedKey),
243 globalGraphValues.at<gtsam::Vector3>(gtsam::symbol_shorthand::V(currentPropagatedKey)),
244 gtsam::noiseModel::Isotropic::Sigma(3, 1e-03)); // VELOCITY
245 globalFactorsBuffer.add(velPrior);
246 // Bias
247 gtsam::PriorFactor<gtsam::imuBias::ConstantBias> biasPrior(
248 gtsam::symbol_shorthand::B(currentPropagatedKey), optimizedGraphState_.imuBias(),
249 gtsam::noiseModel::Diagonal::Sigmas((gtsam::Vector(6) << 1e-03, 1e-03, 1e-03, 1e-03, 1e-03, 1e-03).finished())); // BIAS
250 globalFactorsBuffer.add(biasPrior);
251
252 // Optimize over it with good intitial guesses
253 globalSmootherPtr_ = std::make_shared<gtsam::IncrementalFixedLagSmoother>(
254 graphConfigPtr_->smootherLag, isamParams_); // std::make_shared<gtsam::ISAM2>(isamParams_);
255 addFactorsToSmootherAndOptimize(globalSmootherPtr_, globalFactorsBuffer, globalGraphValues, globalGraphKeysTimestampsMap,
256 graphConfigPtr_, 5);
257 }
258
259 {
260 const std::lock_guard<std::mutex> activelyUSingActiveGraphLock(activelyUsingActiveGraphMutex_);
261
262 // Switching of active Graph ---------------
263 activeSmootherPtr_ = globalSmootherPtr_;
264 activeFactorsBufferPtr_ = globalFactorsBufferPtr_;
265 activeImuBufferPreintegratorPtr_ = globalImuBufferPreintegratorPtr_;
266 activeGraphValuesBufferPtr_ = globalGraphValuesBufferPtr_;
267 activeGraphKeysTimestampsMapBufferPtr_ = globalGraphKeysTimestampsMapBufferPtr_;
268 {
269 const std::lock_guard<std::mutex> operateOnGraphDataLock(operateOnGraphDataMutex_);
270 sentRelocalizationCommandAlready_ = false;
271 numOptimizationsSinceGraphSwitching_ = 0;
272 }
273 }
274
275 std::cout << YELLOW_START << "GMsf-GraphManager" << GREEN_START << " Activated global graph pointer." << COLOR_END << std::endl;
276 }
277}
278
279void GraphManager::activateFallbackGraph() {
280 // Mutex, such s.t. the used graph is consistent
281 const std::lock_guard<std::mutex> swappingActiveGraphLock(swappingActiveGraphMutex_);
282 if (activeSmootherPtr_ != fallbackSmootherPtr_) {
283 {
284 const std::lock_guard<std::mutex> activelyUsingActiveGraphLock(activelyUsingActiveGraphMutex_);
285 *fallbackSmootherPtr_ = *globalSmootherPtr_;
286 std::cout << YELLOW_START << "GraphManager" << GREEN_START << " Reset fallback graph to global graph." << COLOR_END << std::endl;
287 activeSmootherPtr_ = fallbackSmootherPtr_;
288 activeFactorsBufferPtr_ = fallbackFactorsBufferPtr_;
289 activeImuBufferPreintegratorPtr_ = fallbackImuBufferPreintegratorPtr_;
290 activeGraphValuesBufferPtr_ = fallbackGraphValuesBufferPtr_;
291 activeGraphKeysTimestampsMapBufferPtr_ = fallbackGraphKeysTimestampsMapBufferPtr_;
292 // Reset counter
293 numOptimizationsSinceGraphSwitching_ = 0;
294 }
295 std::cout << YELLOW_START << "GraphManager" << GREEN_START << " Activated fallback graph pointer." << COLOR_END << std::endl;
296 }
297}
298
299void HolisticFusion::activateFallbackGraph() {
300 if (graphConfigPtr_->usingFallbackGraphFlag) {
301 graphMgrPtr_->activateFallbackGraph();
302 } else {
303 std::cout << YELLOW_START << "GMsf" << RED_START << " Not activating fallback graph, disabled in config." << COLOR_END << std::endl;
304 }
305}
306
307} // namespace holistic_fusion
#define COLOR_END
#define REQUIRED_GNSS_NUM_NOT_JUMPED
#define GREEN_START
#define RED_START
#define YELLOW_START