My Project 1.0
Holistic Fusion: A Generic Framework for Multimodal Sensor Fusion
Loading...
Searching...
No Matches
HolisticFusion.cpp
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// C++
9#include <chrono>
10#include <stdexcept>
11
12// Implementation
14
15// Workspace
18
19namespace holistic_fusion {
20
21// Public -----------------------------------------------------------
24 REGULAR_COUT << GREEN_START << " HolisticFusion-Constructor called." << COLOR_END << std::endl;
25}
26
29 // Properly stop the optimizeGraphThread_ before destruction to avoid std::terminate.
31 if (optimizeGraphThread_.joinable()) {
33 }
34}
35
36void HolisticFusion::setup(const std::shared_ptr<GraphConfig> graphConfigPtr, const std::shared_ptr<StaticTransforms> staticTransformsPtr) {
37 REGULAR_COUT << GREEN_START << " HolisticFusion-Setup called." << COLOR_END << std::endl;
38
39 // Check if setup has been called before
40 if (graphConfigPtr == nullptr || staticTransformsPtr == nullptr) {
41 throw std::runtime_error("setup() of inheriting classes did not has not been called before.");
42 } else {
43 graphConfigPtr_ = graphConfigPtr;
44 staticTransformsPtr_ = staticTransformsPtr;
45 }
46
47 if (!graphConfigPtr_->staticAtStartup_) {
48 graphConfigPtr_->gyroBiasPrior_.setZero();
49 throw std::logic_error("HolisticFusion: initialization_params.static_at_startup=false: in-motion initialization is not implemented.");
50 }
51
52 if (graphConfigPtr_->additionalOptimizationIterations_ < 0) {
53 throw std::invalid_argument("HolisticFusion: additionalOptimizationIterations must be nonnegative.");
54 }
55 if (graphConfigPtr_->createStateEveryNthImuMeasurement_ < 1) {
56 throw std::invalid_argument("HolisticFusion: createStateEveryNthImuMeasurement must be positive.");
57 }
58
59 // Imu Buffer
60 // Initialize IMU buffer
61 coreImuBufferPtr_ = std::make_shared<holistic_fusion::ImuBuffer>(graphConfigPtr_);
62
63 // Graph Manager
64 std::cout << "HolisticFusion: Creating GraphManager." << std::endl;
66 std::make_shared<GraphManager>(graphConfigPtr_, staticTransformsPtr_->getImuFrame(), staticTransformsPtr_->getWorldFrame());
67 std::cout << "HolisticFusion: GraphManager created." << std::endl;
68
71 REGULAR_COUT << " Initialized thread for optimizing the graph in parallel." << std::endl;
72}
73
74// Trigger functions -----------------------
75bool HolisticFusion::optimizeSlowBatchSmoother(int maxIterations, const std::string& savePath, const bool saveCovarianceFlag) {
76 return graphMgrPtr_->optimizeSlowBatchSmoother(maxIterations, savePath, saveCovarianceFlag);
77}
78
79std::optional<BatchOptimizationResult> HolisticFusion::optimizeSlowBatchSmoother(int maxIterations, const bool computePoseCovarianceFlag) {
80 return graphMgrPtr_->optimizeSlowBatchSmoother(maxIterations, computePoseCovarianceFlag);
81}
82
83bool HolisticFusion::logRealTimeNavStates(const std::string& savePath) {
84 // String of time without line breaks: year_month_day_hour_min_sec
85 std::ostringstream oss;
86 std::time_t now_time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
87 std::tm now_tm = *std::localtime(&now_time_t);
88 oss << std::put_time(&now_tm, "%Y_%m_%d_%H_%M_%S");
89 // Convert stream to string
90 std::string timeString = oss.str();
91 // Return
92 return graphMgrPtr_->logRealTimeNavStates(savePath, timeString);
93}
94
95// Getter functions -----------------------
99
103
105 return initedGraphFlag_;
106}
107
108// Initialization -----------------------
109bool HolisticFusion::initYawAndPositionInWorld(const double yaw_fixedFrame_frame1, const Eigen::Vector3d& fixedFrame_t_fixedFrame_frame2,
110 const std::string& frame1, const std::string& frame2) {
111 // Locking
112 const std::lock_guard<std::mutex> initYawAndPositionLock(initYawAndPositionMutex_);
113
114 // Different Modes
115 if (!alignedImuFlag_) { // Case 1: IMU not yet aligned --> wait for IMU callback to align roll and pitch of IMU
116
117 REGULAR_COUT << RED_START << " Tried to set initial yaw, but initial attitude is not yet set." << COLOR_END << std::endl;
118 return false;
119
120 } else if (!areYawAndPositionInited()) { // Case 2: Imu is aligned, but roll and pitch not yet --> do it
121 // Transform yaw to imu frame
122 REGULAR_COUT << " Pre-integrated state before init: " << preIntegratedNavStatePtr_->getT_O_Ik_gravityAligned().matrix() << std::endl;
123
124 const gtsam::Rot3 yawR_W_frame1 = gtsam::Rot3::Yaw(yaw_fixedFrame_frame1);
125 REGULAR_COUT << GREEN_START << " Setting yaw of " << frame1 << " frame in " << staticTransformsPtr_->getWorldFrame() << " frame."
126 << COLOR_END << std::endl;
127 const double yaw_W_I0_ =
128 (yawR_W_frame1 *
129 gtsam::Pose3(staticTransformsPtr_->rv_T_frame1_frame2(frame1, staticTransformsPtr_->getImuFrame()).matrix()).rotation())
130 .yaw();
131 // Set Yaw
132 preIntegratedNavStatePtr_->updateYawInWorld(yaw_W_I0_, graphConfigPtr_->odomNotJumpAtStartFlag_);
133
134 // Transform position to imu frame
135 Eigen::Matrix3d R_W_I0 = preIntegratedNavStatePtr_->getT_W_Ik().rotation().matrix();
136 // TODO: fixedFrame not necessarily world
137 Eigen::Vector3d W_t_W_I0 =
138 W_t_W_Frame1_to_W_t_W_Frame2_(fixedFrame_t_fixedFrame_frame2, frame2, staticTransformsPtr_->getImuFrame(), R_W_I0);
139 // Set Position
140 preIntegratedNavStatePtr_->updatePositionInWorld(W_t_W_I0, graphConfigPtr_->odomNotJumpAtStartFlag_);
141
142 REGULAR_COUT << " Preintegrated state after init: " << preIntegratedNavStatePtr_->getT_O_Ik_gravityAligned().matrix() << std::endl;
143
144 // Wrap Up
146 // World Frame
147 REGULAR_COUT << " --------------------" << std::endl;
148 REGULAR_COUT << GREEN_START << " Initial global yaw of from world frame to imu frame has been set to (deg) " << 180.0 * yaw_W_I0_ / M_PI
149 << "." << COLOR_END << std::endl;
150 REGULAR_COUT << GREEN_START << " Initial global position of imu frame in world frame has been set to (m) " << W_t_W_I0.transpose()
151 << "." << COLOR_END << std::endl;
152 // Odom Frame
153 const double& yaw_O_I0 = gtsam::Rot3(preIntegratedNavStatePtr_->getT_O_Ik_gravityAligned().rotation().matrix()).yaw(); // alias
154 REGULAR_COUT << " --------------------" << std::endl;
155 REGULAR_COUT << GREEN_START << " Initial global yaw of from odom frame to imu frame has been set to (deg) " << 180.0 * yaw_O_I0 / M_PI
156 << "." << COLOR_END << std::endl;
157 REGULAR_COUT << GREEN_START << " Initial global position of imu frame in odom frame has been set to (m) "
158 << preIntegratedNavStatePtr_->getT_O_Ik_gravityAligned().translation().transpose() << "." << COLOR_END << std::endl;
159 // Return
160 return true;
161 } else { // Case 3: Initial yaw and position already set --> do nothing
162 REGULAR_COUT << RED_START << " Tried to set initial yaw, but it has been set before." << COLOR_END << std::endl;
163 return false;
164 }
165}
166
168 gtsam::Pose3 T_fixedFrame_frame1(unary6DMeasurement.unaryMeasurement().matrix());
169 return initYawAndPositionInWorld(T_fixedFrame_frame1.rotation().yaw(), T_fixedFrame_frame1.translation(),
170 unary6DMeasurement.sensorFrameName(), unary6DMeasurement.sensorFrameName());
171}
172
173bool HolisticFusion::initWorldFrameToFixedFrameTransform(const Eigen::Isometry3d& T_W_F, const std::string& fixedFrame) {
174 // Set the initial transform
175 std::cout << "Setting initial transform from world frame to " << fixedFrame << " frame: " << T_W_F.matrix() << std::endl;
176 // Actually set the transform
177 return graphMgrPtr_->setInitialWorldFrameToFixedFrameTransform(T_W_F, fixedFrame);
178}
179
180// Adders --------------------------------
183 const Eigen::Vector3d& linearAcc, const Eigen::Vector3d& angularVel, double imuTimeK,
184 std::shared_ptr<SafeIntegratedNavState>& returnPreIntegratedNavStatePtr,
185 std::shared_ptr<SafeNavStateWithCovarianceAndBias>& returnOptimizedStateWithCovarianceAndBiasPtr,
186 Eigen::Matrix<double, 6, 1>& returnAddedImuMeasurements) {
187 // Setup -------------------------
188 // Increase counter
190
191 // Adapt time stamp
192 imuTimeK += graphConfigPtr_->imuTimeOffset_;
193
194 // First Iteration
195 if (preIntegratedNavStatePtr_ == nullptr) {
196 preIntegratedNavStatePtr_ = std::make_shared<SafeIntegratedNavState>();
197 preIntegratedNavStatePtr_->updateLatestMeasurementTimestamp(imuTimeK);
198 }
199
200 // Filter out imu messages with same time stamp
201 if (std::abs(imuTimeK - preIntegratedNavStatePtr_->getTimeK()) < 1e-8 && imuCallbackCounter_ > 1) {
202 REGULAR_COUT << RED_START << " Imu time " << std::setprecision(14) << imuTimeK << " was repeated." << COLOR_END << std::endl;
203 return false;
204 }
205
206 // Potentially convert to m/s^2
207 Eigen::Vector3d linearAccInMps2 = linearAcc;
208 if (graphConfigPtr_->isImuAccInG_) {
209 constexpr double gravityConst = 9.80665;
210 linearAccInMps2 *= gravityConst;
211 }
212
213 // Check the norm and spit out warning in case the acceleration is either too small or too big
214 const double accNorm = linearAccInMps2.norm();
215 if (accNorm < 2) {
216 REGULAR_COUT << RED_START << " IMU linear acceleration is too small: " << linearAccInMps2.transpose() << COLOR_END << std::endl;
217 REGULAR_COUT << RED_START << " Check whether isImuAccInG_ is not mistakenly set to false." << COLOR_END << std::endl;
218 } else if (accNorm > 90) {
219 REGULAR_COUT << RED_START << " IMU linear acceleration is too big: " << linearAccInMps2.transpose() << COLOR_END << std::endl;
220 REGULAR_COUT << RED_START << " Check whether isImuAccInG_ is not mistakenly set to true." << COLOR_END << std::endl;
221 }
222
223 // Clamp linear acceleration to 60 m/s^2 to avoid outliers
224 // constexpr double maxAcc = 60.0;
225 // if (accNorm > maxAcc) {
226 // // Iterate through each element and scale
227 // for (int i = 0; i < 3; ++i) {
228 // // If element is too big, clamp
229 // if (std::abs(linearAccInMps2(i)) > maxAcc) {
230 // linearAccInMps2(i) = (linearAccInMps2(i) > 0 ? maxAcc : -maxAcc);
231 // }
232 // }
233 // REGULAR_COUT << YELLOW_START << " Clamped IMU linear acceleration to: " << linearAccInMps2.transpose() << COLOR_END << std::endl;
234 // }
235
236 // Add measurement to buffer
237 returnAddedImuMeasurements = coreImuBufferPtr_->addToImuBuffer(imuTimeK, linearAccInMps2, angularVel);
238
239 // Locking
240 const std::lock_guard<std::mutex> initYawAndPositionLock(initYawAndPositionMutex_);
241
242 // State Machine in form of if-else statements -----------------
243 if (!alignedImuFlag_) { // Case 1: IMU not aligned
244 // Try to align
245 double imuAttitudeRoll, imuAttitudePitch = 0.0;
246 if (!alignImu_(imuAttitudeRoll, imuAttitudePitch)) { // Case 1.1: IMU alignment failed --> try again next time
247 // Print only once per second
248 if (imuCallbackCounter_ % int(graphConfigPtr_->imuRate_) == 0) {
249 REGULAR_COUT << " NOT ENOUGH IMU MESSAGES TO INITIALIZE POSE. WAITING FOR MORE..." << std::endl;
250 }
251 return false;
252 } else { // Case 1.2: IMU alignment succeeded --> continue next call iteration
253 Eigen::Matrix3d R_W_I0_attitude = gtsam::Rot3::Ypr(0.0, imuAttitudePitch, imuAttitudeRoll).matrix();
254 gtsam::Rot3 R_W_Init0_attitude(
255 R_W_I0_attitude *
256 staticTransformsPtr_->rv_T_frame1_frame2(staticTransformsPtr_->getImuFrame(), staticTransformsPtr_->getInitializationFrame())
257 .rotation()
258 .matrix());
259 // Set yaw of base frame to zero
260 // Set yaw of base frame to zero
261 R_W_Init0_attitude = gtsam::Rot3::Ypr(0.0, R_W_Init0_attitude.pitch(), R_W_Init0_attitude.roll());
262 R_W_I0_attitude =
263 R_W_Init0_attitude.matrix() *
264 staticTransformsPtr_->rv_T_frame1_frame2(staticTransformsPtr_->getInitializationFrame(), staticTransformsPtr_->getImuFrame())
265 .rotation()
266 .matrix();
267 Eigen::Isometry3d T_O_Ik_attitude = Eigen::Isometry3d::Identity();
268 T_O_Ik_attitude.matrix().block<3, 3>(0, 0) = R_W_I0_attitude;
269 Eigen::Vector3d O_t_O_Ik =
270 Eigen::Vector3d(0, 0, 0) -
271 R_W_I0_attitude *
272 staticTransformsPtr_->rv_T_frame1_frame2(staticTransformsPtr_->getImuFrame(), staticTransformsPtr_->getInitializationFrame())
273 .translation();
274 T_O_Ik_attitude.matrix().block<3, 1>(0, 3) = O_t_O_Ik;
275 REGULAR_COUT << " Setting zero position of " << staticTransformsPtr_->getInitializationFrame()
276 << ", hence iniital position of IMU is: " << O_t_O_Ik.transpose() << std::endl;
277 Eigen::Vector3d zeroPVeloctiy = Eigen::Vector3d(0, 0, 0);
278 preIntegratedNavStatePtr_ = std::make_shared<SafeIntegratedNavState>(T_O_Ik_attitude, zeroPVeloctiy, zeroPVeloctiy, imuTimeK);
279 REGULAR_COUT << GREEN_START << " IMU aligned. Initial pre-integrated state in odom frame: "
280 << preIntegratedNavStatePtr_->getT_O_Ik_gravityAligned().matrix() << COLOR_END << std::endl;
281 alignedImuFlag_ = true;
282 return false;
283 }
284 } else if (!areYawAndPositionInited()) { // Case 2: IMU aligned, but yaw and position not initialized, waiting for external
285 // initialization, meanwhile publishing initial roll and pitch
286 // Printing every second
287 if (imuCallbackCounter_ % int(graphConfigPtr_->imuRate_) == 0) {
288 REGULAR_COUT << " IMU callback waiting for initialization of global yaw and initial position." << std::endl;
289 }
290 // Publish state with correct roll and pitch, nothing has changed compared to Case 1.2
291 preIntegratedNavStatePtr_->updateLatestMeasurementTimestamp(imuTimeK);
292 returnPreIntegratedNavStatePtr = std::make_shared<SafeIntegratedNavState>(*preIntegratedNavStatePtr_);
293 return true;
294 } else if (!validFirstMeasurementReceivedFlag_) { // Case 3: No valid measurement received yet
295 if (imuCallbackCounter_ % int(graphConfigPtr_->imuRate_) == 0) {
296 REGULAR_COUT << RED_START << " IMU callback waiting for first valid measurement before initializing graph." << COLOR_END << std::endl;
297 }
298 preIntegratedNavStatePtr_->updateLatestMeasurementTimestamp(imuTimeK);
299 returnPreIntegratedNavStatePtr = std::make_shared<SafeIntegratedNavState>(*preIntegratedNavStatePtr_);
300 return true;
301 } else if (!initedGraphFlag_) { // Case 4: IMU aligned, yaw and position initialized, valid measurement received, but graph not yet
302 // initialized
303 preIntegratedNavStatePtr_->updateLatestMeasurementTimestamp(imuTimeK);
304 initGraph_(imuTimeK, returnAddedImuMeasurements.tail<3>());
305 returnPreIntegratedNavStatePtr = std::make_shared<SafeIntegratedNavState>(*preIntegratedNavStatePtr_);
306 REGULAR_COUT << GREEN_START << " ...graph is initialized." << COLOR_END << std::endl;
307 return true;
308 }
309
310 // Case 5: Normal operation, meaning predicting the next state via integration -------------
311 // Only create state every n-th measurements (or at first successful iteration)
312 bool createNewStateFlag = imuCallbackCounter_ % graphConfigPtr_->createStateEveryNthImuMeasurement_ == 0 || !normalOperationFlag_;
313 // Add IMU factor and return propagated & optimized state
314 graphMgrPtr_->addImuFactorAndGetState(*preIntegratedNavStatePtr_, returnOptimizedStateWithCovarianceAndBiasPtr, coreImuBufferPtr_,
315 imuTimeK, createNewStateFlag);
316 returnPreIntegratedNavStatePtr = std::make_shared<SafeIntegratedNavState>(*preIntegratedNavStatePtr_);
317
318 // Set to normal operation
321 }
322
323 // Return
324 return true;
325}
326
327// Ambiguous Measurements -----------------------
328bool HolisticFusion::addZeroMotionFactor(double timeKm1, double timeK, double noiseDensity) {
329 static_cast<void>(graphMgrPtr_->addPoseBetweenFactor(gtsam::Pose3::Identity(), noiseDensity * Eigen::Matrix<double, 6, 1>::Ones(),
330 timeKm1, timeK, 10, RobustNormEnum::None, 0.0));
331 graphMgrPtr_->addUnaryClassicFactor<gtsam::Vector3, 3, gtsam::PriorFactor<gtsam::Vector3>, gtsam::symbol_shorthand::V>(
332 gtsam::Vector3::Zero(), noiseDensity * Eigen::Matrix<double, 3, 1>::Ones(), timeK);
333
334 return true;
335}
336
337bool HolisticFusion::addZeroVelocityFactor(double timeK, double noiseDensity) {
338 graphMgrPtr_->addUnaryClassicFactor<gtsam::Vector3, 3, gtsam::PriorFactor<gtsam::Vector3>, gtsam::symbol_shorthand::V>(
339 gtsam::Vector3::Zero(), noiseDensity * Eigen::Matrix<double, 3, 1>::Ones(), timeK);
340
341 return true;
342}
343
344// Private ---------------------------------------------------------------
345
347bool HolisticFusion::alignImu_(double& imuAttitudeRoll, double& imuAttitudePitch) {
348 gtsam::Rot3 R_W_I_rollPitch;
349 static int alignImuCounter__ = -1;
350 ++alignImuCounter__;
351 double estimatedGravityMagnitude;
352 if (coreImuBufferPtr_->estimateAttitudeFromImu(R_W_I_rollPitch, estimatedGravityMagnitude, graphMgrPtr_->getInitGyrBiasReference())) {
353 imuAttitudeRoll = R_W_I_rollPitch.roll();
354 imuAttitudePitch = R_W_I_rollPitch.pitch();
355 if (graphConfigPtr_->estimateGravityFromImuFlag_) {
356 graphConfigPtr_->gravityMagnitude_ = estimatedGravityMagnitude;
357 REGULAR_COUT << " Attitude of IMU is initialized. Determined Gravity Magnitude: " << estimatedGravityMagnitude << std::endl;
358 } else {
359 REGULAR_COUT << " Estimated gravity magnitude from IMU is: " << estimatedGravityMagnitude << std::endl;
360 REGULAR_COUT << " This gravity is not used, because estimateGravityFromImu is set to false. Gravity set to "
361 << graphConfigPtr_->gravityMagnitude_ << "." << std::endl;
362 gtsam::Vector3 gravityVector = gtsam::Vector3(0, 0, graphConfigPtr_->gravityMagnitude_);
363 gtsam::Vector3 estimatedGravityVector = gtsam::Vector3(0, 0, estimatedGravityMagnitude);
364 gtsam::Vector3 gravityVectorError = estimatedGravityVector - gravityVector;
365 gtsam::Vector3 gravityVectorErrorInImuFrame = R_W_I_rollPitch.inverse().rotate(gravityVectorError);
366 graphMgrPtr_->getInitAccBiasReference() = gravityVectorErrorInImuFrame;
367 std::cout << YELLOW_START << "GMsf" << COLOR_END << " Gravity error in IMU frame is: " << gravityVectorErrorInImuFrame.transpose()
368 << std::endl;
369 }
370 return true;
371 } else {
372 return false;
373 }
374}
375
376// Graph initialization for roll & pitch from starting attitude, assume zero yaw
377void HolisticFusion::initGraph_(const double timeStamp_k, const Eigen::Vector3d& imuAngularVelocity) {
378 // Calculate initial attitude;
379 const gtsam::Pose3& T_W_I0 = gtsam::Pose3(preIntegratedNavStatePtr_->getT_W_Ik().matrix());
380 const gtsam::Pose3& T_O_I0 = gtsam::Pose3(preIntegratedNavStatePtr_->getT_O_Ik_gravityAligned().matrix());
381 // Print
382 REGULAR_COUT << GREEN_START << " Total initial IMU attitude is RPY (deg): " << T_W_I0.rotation().rpy().transpose() * (180.0 / M_PI)
383 << COLOR_END << std::endl;
384
385 // Gravity
386 graphConfigPtr_->W_gravityVector_ = Eigen::Vector3d(0.0, 0.0, -graphConfigPtr_->gravityMagnitude_);
387 graphMgrPtr_->initImuIntegrators(graphConfigPtr_->gravityMagnitude_);
389 graphMgrPtr_->initPoseVelocityBiasGraph(timeStamp_k, T_W_I0, T_O_I0, imuAngularVelocity);
390
391 // Read initial pose from graph for optimized pose
392 gtsam::Pose3 T_W_I0_opt = graphMgrPtr_->getOptimizedGraphState().navState().pose();
394 << " INITIAL POSE of IMU in world frame after first optimization, x,y,z (m): " << T_W_I0_opt.translation().transpose()
395 << ", RPY (deg): " << T_W_I0_opt.rotation().rpy().transpose() * (180.0 / M_PI) << COLOR_END << std::endl;
396 REGULAR_COUT << GREEN_START << " INITIAL position of IMU in odom frame after first optimization, x,y,z (m): "
397 << preIntegratedNavStatePtr_->getT_O_Ik_gravityAligned().translation().transpose() << std::endl;
398 REGULAR_COUT << " Factor graph key of very first node: " << graphMgrPtr_->getPropagatedStateKey() << std::endl;
399
400 // Set flag
401 initedGraphFlag_ = true;
402}
403
405 // While loop
406 REGULAR_COUT << " Thread for updating graph is ready." << std::endl;
407 double lastOptimizedTime = std::chrono::duration<double>(std::chrono::system_clock::now().time_since_epoch()).count();
408 double currentTime = std::chrono::duration<double>(std::chrono::system_clock::now().time_since_epoch()).count();
409 bool optimizedAtLeastOnce = false;
410 while (!stopOptimizeGraphThread_) {
411 bool optimizeGraphFlag = false;
412 // Mutex for optimizeGraph Flag
413 {
414 // Lock
415 const std::lock_guard<std::mutex> optimizeGraphLock(optimizeGraphMutex_);
416 currentTime = std::chrono::duration<double>(std::chrono::system_clock::now().time_since_epoch()).count();
417 // Optimize at most at the rate of maxOptimizationFrequency but at least every second
418 if ((optimizeGraphFlag_ && ((currentTime - lastOptimizedTime) > (1.0 / graphConfigPtr_->maxOptimizationFrequency_))) ||
419 ((currentTime - lastOptimizedTime) > (1.0 / graphConfigPtr_->minOptimizationFrequency_) && optimizedAtLeastOnce)) {
420 optimizeGraphFlag = true;
421 lastOptimizedTime = currentTime;
422 optimizedAtLeastOnce = true;
423 optimizeGraphFlag_ = false;
424 }
425 }
426
427 // Optimize
428 if (optimizeGraphFlag) {
429 graphMgrPtr_->updateGraph();
430 } // else just sleep for a short amount of time before polling again
431 else {
432 std::this_thread::sleep_for(std::chrono::milliseconds(1));
433 }
434 }
435}
436
438Eigen::Vector3d HolisticFusion::W_t_W_Frame1_to_W_t_W_Frame2_(const Eigen::Vector3d& W_t_W_frame1, const std::string& frame1,
439 const std::string& frame2, const Eigen::Matrix3d& R_W_frame2) {
440 // Static transforms
441 const Eigen::Isometry3d& T_frame2_frame1 = staticTransformsPtr_->rv_T_frame1_frame2(frame2, frame1);
442 const Eigen::Vector3d& frame1_t_frame1_frame2 = staticTransformsPtr_->rv_T_frame1_frame2(frame1, frame2).translation();
443
445 Eigen::Matrix3d R_W_frame1 = R_W_frame2 * T_frame2_frame1.rotation();
446
448 Eigen::Vector3d W_t_frame1_frame2 = R_W_frame1 * frame1_t_frame1_frame2;
449
451 return W_t_W_frame1 + W_t_frame1_frame2;
452}
453
457
458// Check whether measurement violated covariance, if yes, add to set and print once, if not, remove from set and print that returned
459bool HolisticFusion::checkAndPrintCovarianceViolation_(const std::string& measurementName, const bool violatedFlag) {
460 if (violatedFlag) {
462 measurementsWithViolatedCovariance_.insert(measurementName);
463 REGULAR_COUT << RED_START << " " << measurementName << " covariance violated. Not adding factor until not violated anymore."
464 << COLOR_END << std::endl;
465 }
466 return true;
467 } else {
469 measurementsWithViolatedCovariance_.erase(measurementName);
470 REGULAR_COUT << GREEN_START << " " << measurementName << " covariance not violated anymore." << COLOR_END << std::endl;
471 }
472 return false;
473 }
474}
475
476} // namespace holistic_fusion
#define REGULAR_COUT
#define COLOR_END
#define GREEN_START
#define RED_START
#define YELLOW_START
Eigen::Vector3d W_t_W_Frame1_to_W_t_W_Frame2_(const Eigen::Vector3d &W_t_W_frame1, const std::string &frame1, const std::string &frame2, const Eigen::Matrix3d &R_W_frame2)
Utility functions / Geometric transformation to IMU in world frame.
bool addZeroMotionFactor(double timeKm1, double timeK, double noiseDensity)
void setup(const std::shared_ptr< GraphConfig > graphConfigPtr, const std::shared_ptr< StaticTransforms > staticTransformsPtr)
std::shared_ptr< GraphConfig > graphConfigPtr_
std::shared_ptr< SafeIntegratedNavState > preIntegratedNavStatePtr_
State Containers.
bool initYawAndPositionInWorld(const double yaw_W_frame1, const Eigen::Vector3d &W_t_W_frame2, const std::string &frame1, const std::string &frame2)
std::atomic< bool > stopOptimizeGraphThread_
bool initWorldFrameToFixedFrameTransform(const Eigen::Isometry3d &T_W_F, const std::string &fixedFrame)
bool logRealTimeNavStates(const std::string &savePath)
std::shared_ptr< holistic_fusion::ImuBuffer > coreImuBufferPtr_
bool alignedImuFlag_
Flags / Initialization.
bool addZeroVelocityFactor(double timeK, double noiseDensity)
bool addCoreImuMeasurementAndGetState(const Eigen::Vector3d &linearAcc, const Eigen::Vector3d &angularVel, const double imuTimeK, std::shared_ptr< SafeIntegratedNavState > &returnPreIntegratedNavStatePtr, std::shared_ptr< SafeNavStateWithCovarianceAndBias > &returnOptimizedStateWithCovarianceAndBiasPtr, Eigen::Matrix< double, 6, 1 > &returnAddedImuMeasurements)
Main: IMU --------------------—.
bool alignImu_(double &imuAttitudeRoll, double &imuAttitudePitch)
Worker functions / Set Imu Attitude.
virtual ~HolisticFusion()
Destructor --------—.
std::shared_ptr< GraphManager > graphMgrPtr_
bool optimizeSlowBatchSmoother(int maxIterations, const std::string &savePath, const bool saveCovarianceFlag)
std::shared_ptr< StaticTransforms > staticTransformsPtr_
bool checkAndPrintCovarianceViolation_(const std::string &measurementName, const bool violatedFlag)
void initGraph_(const double timeStamp_k, const Eigen::Vector3d &imuAngularVelocity)
HolisticFusion()
Constructor --------—.
std::unordered_set< std::string > measurementsWithViolatedCovariance_
bool initYawAndPosition(const UnaryMeasurementXD< Eigen::Isometry3d, 6 > &unary6DMeasurement)
const std::string & sensorFrameName() const
Definition Measurement.h:83
Class to represent x-dimensional unary measurement in the graph.
const MEASUREMENT_TYPE & unaryMeasurement() const