diff --git a/.gitignore b/.gitignore index 3d1d237de284515d210782928bd15eb347decf99..91c5366fd823c89dcb9024788ac8c419f5337c52 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ src/examples/map_apriltag_save.yaml build_release/ IMU.found +est.csv diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 35a9d415d3016f1b4849c398d8ad9aabeff12f85..a8cf0ab798de32fa1901d03d37e307295fa2c78b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -32,3 +32,6 @@ target_link_libraries(gtest_feature_imu ${PLUGIN_NAME} ${wolf_LIBRARY}) # Maybe call an archeologist to fix this thing? # wolf_add_gtest(gtest_factor_imu gtest_factor_imu.cpp) # target_link_libraries(gtest_factor_imu ${PLUGIN_NAME} ${wolf_LIBRARY}) + +wolf_add_gtest(gtest_processor_motion_intrinsics_update gtest_processor_motion_intrinsics_update.cpp) +target_link_libraries(gtest_processor_motion_intrinsics_update ${PLUGIN_NAME} ${wolf_LIBRARY}) diff --git a/test/gtest_processor_motion_intrinsics_update.cpp b/test/gtest_processor_motion_intrinsics_update.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4dbac962133c7d8da9f76e152a09e0749c1f2e71 --- /dev/null +++ b/test/gtest_processor_motion_intrinsics_update.cpp @@ -0,0 +1,264 @@ +#include <fstream> + +#include "imu/internal/config.h" +#include "core/utils/utils_gtest.h" +#include "core/utils/logging.h" + +#include "core/common/wolf.h" +#include "core/problem/problem.h" +#include <core/ceres_wrapper/solver_ceres.h> +#include "imu/sensor/sensor_imu.h" +#include "imu/processor/processor_imu.h" +#include "imu/capture/capture_imu.h" + +using namespace wolf; +using namespace Eigen; + + + +/** +Simplified test rolling along x axis only: +Delta_x = 2*pi*R*(ticks/ticks_per_wheel_revolution) + +If we take ticks_per_wheel_revolution = 2*pi, even simpler formulat: +Delta_x = R*ticks + +**/ + +Vector10d integrateX(double ax, double dt){ + Vector10d x; x << 0.5*ax*pow(dt,2),0,0, 0,0,0,1, ax*dt,0,0; + return x; +} + +class ProcessorImuTest : public testing::Test +{ + public: + ParamsSensorImuPtr intr_; + SensorImuPtr sensor_; + ParamsProcessorImuPtr params_; + ProcessorImuPtr processor_; + ProblemPtr problem_; + SolverCeresPtr solver_; + FrameBasePtr KF0_; + double radius; + + void SetUp() override + { + problem_ = Problem::create("POV", 3); + solver_ = std::make_shared<SolverCeres>(problem_); + + Vector4d q_init; q_init << 0,0,0,1; + VectorComposite x_origin("POV", {Vector3d::Zero(), q_init, Vector3d::Zero()}); + VectorComposite std_origin("POV", {0.001*Vector3d::Ones(), 0.001*Vector3d::Ones(), 0.001*Vector3d::Ones()}); + + // ground truth of wheels radius + radius = 1; + // make a sensor first + intr_ = std::make_shared<ParamsSensorImu>(); + intr_->a_noise = 0.001; + intr_->w_noise = 0.001; + intr_->ab_initial_stdev = 0.001; + intr_->wb_initial_stdev = 0.001; + intr_->ab_rate_stdev = 0.001; + intr_->wb_rate_stdev = 0.001; + + Vector7d extr; extr << 0,0,0, 0,0,0,1; + sensor_ = std::static_pointer_cast<SensorImu>(problem_->installSensor("SensorImu", "sensor imu", extr, intr_)); + + // params and processor + params_ = std::make_shared<ParamsProcessorImu>(); + params_->voting_active = true; + params_->max_time_span = 0.9999; // create one KF every second + params_->max_buff_length = 1000000000; + params_->dist_traveled = 100000000000; + params_->angle_turned = 10000000000; + + params_->unmeasured_perturbation_std = 1e-4; + params_->time_tolerance = 0.0025; + processor_ = std::static_pointer_cast<ProcessorImu>(problem_->installProcessor("ProcessorImu", "processor imu", sensor_, params_)); + + KF0_ = problem_->setPriorFactor(x_origin, std_origin, 0, 0.01); + + Vector6d bias; bias << 0.42,0,0, 0,0,0; + // Vector6d bias; bias << 0.0,0,0, 0.42,0,0; + sensor_->getIntrinsic(0)->setState(bias); + + processor_->setOrigin(KF0_); + } + + void TearDown() override{} + +}; + +TEST_F(ProcessorImuTest, test1) +{ + Matrix6d data_cov; data_cov. setIdentity(); + // Advances at constant speed on both wheels + double AX = 0; + + problem_->print(4,true,true,true); + CaptureMotionPtr CM; + + CM = std::static_pointer_cast<CaptureMotion>(KF0_->getCaptureOf(sensor_)); + std::cout << "bias preint before" << CM->getTimeStamp() << ": " << CM->getCalibrationPreint().transpose() << " , biais est: " << sensor_->getIntrinsic(CM->getTimeStamp())->getState().transpose() << std::endl; + solver_->solve(); + std::cout << "bias preint after" << CM->getTimeStamp() << ": " << CM->getCalibrationPreint().transpose() << " , biais est: " << sensor_->getIntrinsic(CM->getTimeStamp())->getState().transpose() << std::endl; + + + Vector6d data; data << -wolf::gravity(), 0,0,0; data(0) = AX; + Vector10d state_pred; state_pred << 0,0,0, 0,0,0,1, 0,0,0; + auto C1 = std::make_shared<CaptureImu>(1, sensor_, data, data_cov, KF0_->getCaptureList().front()); C1->process(); + FrameBasePtr KF1 = problem_->getTrajectory()->getLastFrame(); + KF1->setState(integrateX(AX,1)); KF1->fix(); + CM = std::static_pointer_cast<CaptureMotion>(KF1->getCaptureOf(sensor_)); + std::cout << "bias preint before" << CM->getTimeStamp() << ": " << CM->getCalibrationPreint().transpose() << " , biais est: " << sensor_->getIntrinsic(CM->getTimeStamp())->getState().transpose() << std::endl; + solver_->solve(); + std::cout << "bias preint after" << CM->getTimeStamp() << ": " << CM->getCalibrationPreint().transpose() << " , biais est: " << sensor_->getIntrinsic(CM->getTimeStamp())->getState().transpose() << std::endl; + // problem_->print(4,true,true,true); + + auto C2 = std::make_shared<CaptureImu>(2, sensor_, data, data_cov, KF0_->getCaptureList().front()); C2->process(); + FrameBasePtr KF2 = problem_->getTrajectory()->getLastFrame(); + KF2->setState(integrateX(AX,2)); KF2->fix(); + CM = std::static_pointer_cast<CaptureMotion>(KF2->getCaptureOf(sensor_)); + std::cout << "bias preint before" << CM->getTimeStamp() << ": " << CM->getCalibrationPreint().transpose() << " , biais est: " << sensor_->getIntrinsic(CM->getTimeStamp())->getState().transpose() << std::endl; + solver_->solve(); + std::cout << "bias preint after" << CM->getTimeStamp() << ": " << CM->getCalibrationPreint().transpose() << " , biais est: " << sensor_->getIntrinsic(CM->getTimeStamp())->getState().transpose() << std::endl; + // problem_->print(4,true,true,true); + + auto C3 = std::make_shared<CaptureImu>(3, sensor_, data, data_cov, KF0_->getCaptureList().front()); C3->process(); + FrameBasePtr KF3 = problem_->getTrajectory()->getLastFrame(); + KF3->setState(integrateX(AX,3)); KF3->fix(); + CM = std::static_pointer_cast<CaptureMotion>(KF3->getCaptureOf(sensor_)); + std::cout << "bias preint before" << CM->getTimeStamp() << ": " << CM->getCalibrationPreint().transpose() << " , biais est: " << sensor_->getIntrinsic(CM->getTimeStamp())->getState().transpose() << std::endl; + solver_->solve(); + std::cout << "bias preint after" << CM->getTimeStamp() << ": " << CM->getCalibrationPreint().transpose() << " , biais est: " << sensor_->getIntrinsic(CM->getTimeStamp())->getState().transpose() << std::endl; + // problem_->print(4,true,true,true); + + auto C4 = std::make_shared<CaptureImu>(4, sensor_, data, data_cov, KF0_->getCaptureList().front()); C4->process(); + FrameBasePtr KF4 = problem_->getTrajectory()->getLastFrame(); + KF4->setState(integrateX(AX,4)); KF4->fix(); + CM = std::static_pointer_cast<CaptureMotion>(KF4->getCaptureOf(sensor_)); + std::cout << "bias preint before" << CM->getTimeStamp() << ": " << CM->getCalibrationPreint().transpose() << " , biais est: " << sensor_->getIntrinsic(CM->getTimeStamp())->getState().transpose() << std::endl; + solver_->solve(); + std::cout << "bias preint after" << CM->getTimeStamp() << ": " << CM->getCalibrationPreint().transpose() << " , biais est: " << sensor_->getIntrinsic(CM->getTimeStamp())->getState().transpose() << std::endl; + // problem_->print(4,true,true,true); + + for(auto kf: problem_->getTrajectory()->getFrameMap()){ + CaptureMotionPtr cap = std::static_pointer_cast<CaptureMotion>(kf.second->getCaptureOf(sensor_)); + } + + +} + + +/** + * SET TO TRUE TO PRODUCE CSV FILE + * SET TO FALSE TO STOP PRODUCING CSV FILE + */ +#define WRITE_CSV_FILE false + +TEST_F(ProcessorImuTest, getState) +{ + Matrix6d data_cov; data_cov. setIdentity(); + // Advances at constant acceleration + double AX = 0; + + problem_->print(4,true,true,true); + Vector6d data; data << -wolf::gravity(), 0,0,0; data(0) = AX; + CaptureImuPtr C; + + TimeStamp t(0); + double dt(0.1); + int nb_kf = 1; + +#if WRITE_CSV_FILE + std::fstream file_est; + file_est.open("./est.csv", std::fstream::out); +// std::string header_est = "t,px,py,pz,qx,qy,qz,qw,vx,vy,vz,bax_est,bax_preint\n"; + std::string header_est = "t;px;vx;bax_est;bax_preint\n"; + file_est << header_est; +#endif + + while (t < 4){ + auto C = std::make_shared<CaptureImu>(t, sensor_, data, data_cov, KF0_->getCaptureList().front()); + C->process(); + + + std::cout << "t " << t << "; cap id " << sensor_->findLastCaptureBefore(t) << "; cap ts " << sensor_->findLastCaptureBefore(t)->getTimeStamp() << std::endl; + + +#if WRITE_CSV_FILE + // pre-solve print to CSV + VectorComposite state = problem_->getState(t); + VectorXd calib_estim = sensor_->getIntrinsic(t)->getState(); + VectorXd calib_preint = processor_->getLast()->getCalibrationPreint(); + file_est << std::fixed << t << ";" + << state['P'](0) << ";" + << state['V'](0) << ";" + << calib_estim(0) << ";" + << calib_preint(0) << "\n"; +#endif + + + if (problem_->getTrajectory()->getFrameMap().size() > nb_kf){ + FrameBasePtr KF = problem_->getTrajectory()->getLastFrame(); + KF->setState(integrateX(AX, KF->getTimeStamp().get())); + KF->fix(); + + solver_->solve(); + problem_->print(4, true, true, true); + + nb_kf = problem_->getTrajectory()->getFrameMap().size(); + +#if WRITE_CSV_FILE + // post-solve print to CSV with time-stamp shifted by dt/2 to separate from pre-solve result + state = problem_->getState(t); + calib_estim = sensor_->getIntrinsic(t)->getState(); + calib_preint = processor_->getLast()->getCalibrationPreint(); + file_est << std::fixed << t+dt/2 << ";" + << state['P'](0) << ";" + << state['V'](0) << ";" + << calib_estim(0) << ";" + << calib_preint(0) << "\n"; +#endif + } + + t += dt; + } + +#if WRITE_CSV_FILE + file_est.close(); +#endif + + /** assert final results + * + * t 0 .9 1 1.9 2 3 + * BIAS .4 .4 0 0 0 0 + * BIAS PREINT .4 .4 .4 .4 0 0 + * X 0 !0 0 0 0 0 + * V 0 !0 0 0 0 0 + * + * though we only test at KFs so t = { 0, 1, 2, 3 } + */ + + for (auto F : *problem_->getTrajectory() ) + { + auto ts = F->getTimeStamp(); + + double bias = (t == 0 ? 0.42 : 0.0); + ASSERT_NEAR(F->getCaptureOf(sensor_)->getSensorIntrinsic()->getState()(0), bias, 1e-6); + ASSERT_NEAR(F->getP()->getState()(0),0.0,1e-6); + ASSERT_NEAR(F->getV()->getState()(0),0.0,1e-6); + } + +} + + + + + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}