diff --git a/demos/imu2d_static_init.yaml b/demos/imu2d_static_init.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c45b9666696c20010a8c967ac6608c1ee3f7a98d --- /dev/null +++ b/demos/imu2d_static_init.yaml @@ -0,0 +1,12 @@ +type: "ProcessorImu2d" # This must match the KEY used in the SensorFactory. Otherwise it is an error. + +time_tolerance: 0.0025 # Time tolerance for joining KFs +unmeasured_perturbation_std: 0.00001 + +keyframe_vote: + voting_active: true + voting_aux_active: false + max_time_span: 1.0 # seconds + max_buff_length: 20000 # motion deltas + dist_traveled: 2.0 # meters + angle_turned: 0.2 # radians (1 rad approx 57 deg, approx 60 deg) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d16b4a3857c88316a48fa5cc79f77a6bc4f7b40d..70ad9b2240b17448306eb5579c9313d212301a70 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -37,6 +37,9 @@ target_link_libraries(gtest_feature_imu ${PLUGIN_NAME} ${wolf_LIBRARY}) wolf_add_gtest(gtest_factor_imu2d gtest_factor_imu2d.cpp) target_link_libraries(gtest_factor_imu2d ${PLUGIN_NAME} ${wolf_LIBRARY}) +wolf_add_gtest(gtest_imu2d_static_init gtest_imu2d_static_init.cpp) +target_link_libraries(gtest_imu2d_static_init ${PLUGIN_NAME} ${wolf_LIBRARY}) + wolf_add_gtest(gtest_imu_mocap_fusion gtest_imu_mocap_fusion.cpp) target_link_libraries(gtest_imu_mocap_fusion ${PLUGIN_NAME} ${wolf_LIBRARY}) diff --git a/test/gtest_imu2d_static_init.cpp b/test/gtest_imu2d_static_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9283b56e3160fd128dbf2a2e5f12f4b2f00c224f --- /dev/null +++ b/test/gtest_imu2d_static_init.cpp @@ -0,0 +1,277 @@ +#include <core/ceres_wrapper/solver_ceres.h> +#include <core/utils/utils_gtest.h> +#include "imu/internal/config.h" + +#include "imu/factor/factor_imu2d.h" +#include "imu/math/imu2d_tools.h" +#include "imu/sensor/sensor_imu2d.h" +#include "core/capture/capture_void.h" +#include <core/factor/factor_relative_pose_2d.h> + +using namespace Eigen; +using namespace wolf; + +class ProcessorImu2dStaticInitTest : public testing::Test +{ + + public: //These can be accessed in fixtures + wolf::ProblemPtr _problem_ptr; + wolf::SensorBasePtr sensor_ptr; + wolf::ProcessorMotionPtr processor_motion; + wolf::TimeStamp t; + wolf::TimeStamp t0; + double mti_clock, tmp; + double dt; + bool second_frame; + Vector6d data; + Matrix6d data_cov; + VectorComposite x0c; // initial state composite + VectorComposite s0c; // initial sigmas composite + std::shared_ptr<wolf::CaptureImu> C; + FrameBasePtr last_frame_; + + //a new of this will be created for each new test + void SetUp() override + { + using namespace Eigen; + using std::shared_ptr; + using std::make_shared; + using std::static_pointer_cast; + using namespace wolf::Constants; + + std::string wolf_root = _WOLF_IMU_ROOT_DIR; + + // Wolf problem + _problem_ptr = Problem::create("POV", 2); + Vector3d extrinsics = (Vector3d() << 0,0, 0).finished(); + sensor_ptr = _problem_ptr->installSensor("SensorImu2d", "Main Imu", extrinsics, wolf_root + "/demos/sensor_imu2d.yaml"); + ProcessorBasePtr processor_ptr = _problem_ptr->installProcessor("ProcessorImu2d", "Imu pre-integrator", "Main Imu", wolf_root + "/demos/imu2d_static_init.yaml"); + processor_motion = std::static_pointer_cast<ProcessorMotion>(processor_ptr); + + // Time and data variables + second_frame = false; + dt = 0.01; + t0.set(0); + t = t0; + data = Vector6d::Random(); + data_cov = Matrix6d::Identity(); + last_frame_ = nullptr; + + // Create one capture to store the Imu data arriving from (sensor / callback / file / etc.) + C = make_shared<CaptureImu>(t, sensor_ptr, data, data_cov, Vector3d::Zero()); + } + +}; + +//// Input odometry data and covariance +//Matrix6d data_cov = 0.1*Matrix6d::Identity(); +//Matrix5d delta_cov = 0.1*Matrix5d::Identity(); +// +//// Jacobian of the bias +//MatrixXd jacobian_bias((MatrixXd(5,3) << 1, 0, 0, +// 0, 1, 0, +// 0, 0, 1, +// 1, 0, 0, +// 0, 1, 0 ).finished()); +////preintegration bias +//Vector3d b0_preint = Vector3d::Zero(); +// +//// Problem and solver +//ProblemPtr _problem_ptr_ptr = Problem::create("POV", 2); +//SolverCeres solver(problem_ptr); +// +//// Two frames +//FrameBasePtr frm0 = problem_ptr->emplaceFrame(TimeStamp(0), Vector5d::Zero()); +//FrameBasePtr frm1 = problem_ptr->emplaceFrame(TimeStamp(1), Vector5d::Zero()); +// +//// Imu2d sensor +//SensorBasePtr sensor = std::make_shared<SensorImu2d>( Vector3d::Zero(), ParamsSensorImu2d() ); // default params: see sensor_imu2d.h +// +////capture from frm1 to frm0 +//auto cap0 = CaptureBase::emplace<CaptureImu>(frm0, 0, sensor, Vector6d::Zero(), data_cov, Vector3d::Zero(), nullptr); +//auto cap1 = CaptureBase::emplace<CaptureImu>(frm1, 1, sensor, Vector6d::Zero(), data_cov, Vector3d::Zero(), cap0); +// +//TEST(imu2d_static_init, check_tree) +//{ +// ASSERT_TRUE(problem_ptr->check(0)); +//} +// +// +//TEST(imu2d_static_init, solve_b0) +//{ +// for(int i = 0; i < 50; i++){ +// // Random delta +// Vector5d delta_biased = Vector5d::Random() * 10; +// delta_biased(2) = pi2pi(delta_biased(2)); +// +// // Random initial pose +// Vector5d x0 = Vector5d::Random() * 10; +// x0(2) = pi2pi(x0(2)); +// +// //Random Initial bias +// Vector3d b0 = Vector3d::Random(); +// +// //Corrected delta +// Vector5d delta_step = jacobian_bias*(b0-b0_preint); +// Vector5d delta = imu2d::plus(delta_biased, delta_step); +// +// // x1 groundtruth +// Vector5d x1; +// x1 = imu2d::compose(x0, delta, 1); +// +// // Set states +// frm0->setState(x0); +// frm1->setState(x1); +// frm0->getV()->setZero(); +// frm0->getV()->fix(); +// frm1->getV()->setZero(); +// frm1->getV()->fix(); +// cap0->getStateBlock('I')->setState(b0); +// cap1->getStateBlock('I')->setState(b0); +// //WOLF_INFO("states set"); +// +// // feature & factor with delta measurement +// auto fea1 = FeatureBase::emplace<FeatureImu2d>(cap1, delta_biased, delta_cov, b0_preint, jacobian_bias); +// FactorBase::emplace<FactorImu2d>(fea1, fea1, cap0, nullptr, false); +// +// // Fix frm1, perturb frm0 +// frm0->fix(); +// cap0->unfix(); +// frm1->fix(); +// cap1->fix(); +// cap0->perturb(0.1); +// +// //do static init stuff on frm1 +// Eigen::VectorXd zero_motion = Eigen::VectorXd::Zero(3); +// //WOLF_INFO("zero_motion created"); +// for (auto frm_pair = problem_ptr->getTrajectory()->begin(); +// frm_pair != problem_ptr->getTrajectory()->end(); +// frm_pair++) +// { +// //WOLF_INFO("entered for"); +// if (frm_pair->second == frm1) +// break; +// auto capture_zero = CaptureBase::emplace<CaptureVoid>(frm1, frm1->getTimeStamp(), nullptr); +// auto feature_zero = FeatureBase::emplace<FeatureBase>(capture_zero, +// "FeatureZeroOdom", +// zero_motion, +// Eigen::MatrixXd::Identity(3,3) * 0.01); +// FactorBase::emplace<FactorRelativePose2d>(feature_zero, +// feature_zero, +// frm_pair->second, +// nullptr, +// false, +// TOP_MOTION); +// +// } +// +// // solve +// std::string report = solver.solve(SolverManager::ReportVerbosity::BRIEF); +// +// ASSERT_POSE2d_APPROX(cap0->getStateVector(), b0, 1e-6); +// //WOLF_INFO(cap0->getStateVector()); +// +// // remove feature (and factor) for the next loop +// fea1->remove(); +// } +//} + +TEST_F(ProcessorImu2dStaticInitTest, static) +{ + Vector2d pos; + // Set the origin + x0c['P'] = Vector2d(0, 0); + x0c['O'] = Vector1d(0); + x0c['V'] = Vector2d(0, 0); + + data_cov *= 1e-3; + dt = 0.5; + auto KF0 = _problem_ptr->setPriorFix(x0c, t0, dt/2); + processor_motion->setOrigin(KF0); + + data = Vector6d::Random(); + WOLF_INFO("Data is: ", data); + int size = 3; + second_frame = false; + FrameBasePtr first_frame = nullptr; + + + for(t = t0+dt; t <= t0 + 4 + dt/2; t+=dt){ + if(first_frame) WOLF_INFO("The first frame is ", first_frame, " and it's currently estimated bias is: ", first_frame->getCaptureOf(sensor_ptr)->getStateBlock('I')->getState()); + WOLF_INFO("Last frame is: ", last_frame_); + WOLF_INFO("Current state is: ", processor_motion->getState().vector("POV")); + WOLF_INFO("second_frame is: ", second_frame); + WOLF_INFO("Currently estimated bias is: ", C->getStateBlock('I')->getState()); + WOLF_INFO("The current problem is:"); + _problem_ptr->print(4); + C->setTimeStamp(t); + C->setData(data); + C->setDataCovariance(data_cov); + C->process(); + if(second_frame){ + //ASSERT_MATRIX_APPROX(processor_motion->getState().vector("POV"), Vector5d::Zero(), 1e-9); + } + if (not last_frame_) + { + last_frame_ = processor_motion->getOrigin()->getFrame(); + first_frame = last_frame_; + + // impose zero velocity + last_frame_->getV()->setZero(); + last_frame_->getV()->fix(); + + // impose zero odometry + //processor_motion_->setOdometry(sensor_ptr->getProblem()->stateZero(processor_motion_->getStateStructure())); + } + else + { + assert(processor_motion->getOrigin() && "SubscriberImuEnableable::callback: nullptr origin"); + assert(processor_motion->getOrigin()->getFrame() && "SubscriberImuEnableable::callback: nullptr origin frame"); + + // new frame + if (last_frame_ != processor_motion->getOrigin()->getFrame()) + { + second_frame = true; + last_frame_ = processor_motion->getOrigin()->getFrame(); + + // impose zero velocity + last_frame_->getV()->setZero(); + last_frame_->getV()->fix(); + + // impose zero odometry + //processor_motion_->setOdometry(sensor_ptr->getProblem()->stateZero(processor_motion_->getStateStructure())); + + // add zero displacement and rotation capture & feature & factor with all previous frames + assert(sensor_ptr->getProblem()); + Eigen::VectorXd zero_motion = Eigen::VectorXd::Zero(size); + for (auto frm_pair = sensor_ptr->getProblem()->getTrajectory()->begin(); + frm_pair != sensor_ptr->getProblem()->getTrajectory()->end(); + frm_pair++) + { + if (frm_pair->second == last_frame_) + break; + auto capture_zero = CaptureBase::emplace<CaptureVoid>(last_frame_, last_frame_->getTimeStamp(), nullptr); + auto feature_zero = FeatureBase::emplace<FeatureBase>(capture_zero, + "FeatureZeroOdom", + zero_motion, + Eigen::MatrixXd::Identity(size,size) * 0.01); + + FactorBase::emplace<FactorRelativePose2d>(feature_zero, + feature_zero, + frm_pair->second, + nullptr, + false, + TOP_MOTION); + + } + } + } + } +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + // ::testing::GTEST_FLAG(filter) = "FactorImu2d.no_bias_fixed"; // Test only this one + return RUN_ALL_TESTS(); +}