diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 25c6f4dfdb9923e6f9bcec1d0f620e4906c1ea3a..e8896eccf78f6f4aef3138b1c6914646c788617c 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -11,28 +11,28 @@ include_directories( add_library(mcapi_utils mcapi_utils.cpp) -add_executable(mcapi_povcdl_estimation mcapi_povcdl_estimation.cpp) -target_link_libraries(mcapi_povcdl_estimation - mcapi_utils - ${wolfcore_LIBRARIES} - ${wolfimu_LIBRARIES} - ${PLUGIN_NAME} - ${multicontact-api_LIBRARIES} - ${pinocchio_LIBRARIES} -) -target_compile_definitions(mcapi_povcdl_estimation PRIVATE ${PINOCCHIO_CFLAGS_OTHER}) +# add_executable(mcapi_povcdl_estimation mcapi_povcdl_estimation.cpp) +# target_link_libraries(mcapi_povcdl_estimation +# mcapi_utils +# ${wolfcore_LIBRARIES} +# ${wolfimu_LIBRARIES} +# ${PLUGIN_NAME} +# ${multicontact-api_LIBRARIES} +# ${pinocchio_LIBRARIES} +# ) +# target_compile_definitions(mcapi_povcdl_estimation PRIVATE ${PINOCCHIO_CFLAGS_OTHER}) -add_executable(mcapi_pov_estimation mcapi_pov_estimation.cpp) -target_link_libraries(mcapi_pov_estimation - mcapi_utils - ${wolfcore_LIBRARIES} - ${wolfimu_LIBRARIES} - ${PLUGIN_NAME} - ${multicontact-api_LIBRARIES} - ${pinocchio_LIBRARIES} -) -target_compile_definitions(mcapi_pov_estimation PRIVATE ${PINOCCHIO_CFLAGS_OTHER}) +# add_executable(mcapi_pov_estimation mcapi_pov_estimation.cpp) +# target_link_libraries(mcapi_pov_estimation +# mcapi_utils +# ${wolfcore_LIBRARIES} +# ${wolfimu_LIBRARIES} +# ${PLUGIN_NAME} +# ${multicontact-api_LIBRARIES} +# ${pinocchio_LIBRARIES} +# ) +# target_compile_definitions(mcapi_pov_estimation PRIVATE ${PINOCCHIO_CFLAGS_OTHER}) add_executable(solo_real_povcdl_estimation solo_real_povcdl_estimation.cpp) target_link_libraries(solo_real_povcdl_estimation @@ -56,6 +56,15 @@ target_link_libraries(solo_real_pov_estimation z ) +add_executable(solo_mocap_imu solo_mocap_imu.cpp) +target_link_libraries(solo_mocap_imu + ${wolfcore_LIBRARIES} + ${wolfimu_LIBRARIES} + ${PLUGIN_NAME} + ${pinocchio_LIBRARIES} + /usr/local/lib/libcnpy.so + z +) # add_executable(test_cnpy test_cnpy.cpp) # target_link_libraries(test_cnpy diff --git a/demos/solo_mocap_imu.cpp b/demos/solo_mocap_imu.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da0270444b930aa6dec61620599d4107bf894665 --- /dev/null +++ b/demos/solo_mocap_imu.cpp @@ -0,0 +1,514 @@ +#include <iostream> +#include <fstream> + +// #include <random> +#include <yaml-cpp/yaml.h> +#include <Eigen/Dense> +#include <ctime> +#include "eigenmvn.h" + +#include "pinocchio/parsers/urdf.hpp" +#include "pinocchio/algorithm/joint-configuration.hpp" +#include "pinocchio/algorithm/kinematics.hpp" +#include "pinocchio/algorithm/center-of-mass.hpp" +#include "pinocchio/algorithm/centroidal.hpp" +#include "pinocchio/algorithm/rnea.hpp" +#include "pinocchio/algorithm/crba.hpp" +#include "pinocchio/algorithm/frames.hpp" + +// CNPY +#include <cnpy.h> + +// WOLF +#include <core/problem/problem.h> +#include <core/ceres_wrapper/solver_ceres.h> +#include <core/math/rotations.h> +#include <core/capture/capture_base.h> +#include <core/capture/capture_pose.h> +#include <core/feature/feature_base.h> +#include <core/factor/factor_pose_3d_with_extrinsics.h> +#include <core/factor/factor_block_absolute.h> +#include <core/processor/processor_odom_3d.h> +#include <core/sensor/sensor_odom_3d.h> +#include "core/tree_manager/tree_manager_sliding_window_dual_rate.h" +#include "core/yaml/parser_yaml.h" + +#include <core/sensor/sensor_pose.h> +#include <core/processor/processor_pose.h> + +// IMU +#include "imu/sensor/sensor_imu.h" +#include "imu/capture/capture_imu.h" +#include "imu/processor/processor_imu.h" +#include "imu/factor/factor_imu.h" + +// BODYDYNAMICS +#include "bodydynamics/internal/config.h" + + +// UTILS +#include "mcapi_utils.h" + + +using namespace Eigen; +using namespace wolf; +using namespace pinocchio; + +typedef pinocchio::SE3Tpl<double> SE3; +typedef pinocchio::ForceTpl<double> Force; + + +int main (int argc, char **argv) { + // retrieve parameters from yaml file + YAML::Node config = YAML::LoadFile("/home/mfourmy/Documents/Phd_LAAS/wolf/bodydynamics/demos/solo_real_estimation.yaml"); + std::string robot_urdf = config["robot_urdf"].as<std::string>(); + int dimc = config["dimc"].as<int>(); + int nb_feet = config["nb_feet"].as<int>(); + double dt = config["dt"].as<double>(); + double min_t = config["min_t"].as<double>(); + double max_t = config["max_t"].as<double>(); + double solve_every_sec = config["solve_every_sec"].as<double>(); + bool solve_end = config["solve_end"].as<bool>(); + + // Ceres setup + int max_num_iterations = config["max_num_iterations"].as<int>(); + + // estimator sensor noises + double std_pbc_est = config["std_pbc_est"].as<double>(); + double std_vbc_est = config["std_vbc_est"].as<double>(); + double std_f_est = config["std_f_est"].as<double>(); + double std_tau_est = config["std_tau_est"].as<double>(); + double std_odom3d_est = config["std_odom3d_est"].as<double>(); + + // priors + double std_prior_p = config["std_prior_p"].as<double>(); + double std_prior_o = config["std_prior_o"].as<double>(); + double std_prior_v = config["std_prior_v"].as<double>(); + double std_abs_bias_pbc = config["std_abs_bias_pbc"].as<double>(); + double std_abs_bias_acc = config["std_abs_bias_acc"].as<double>(); + double std_abs_bias_gyro = config["std_abs_bias_gyro"].as<double>(); + double std_bp_drift = config["std_bp_drift"].as<double>(); + std::vector<double> bias_imu_prior_vec = config["bias_imu_prior"].as<std::vector<double>>(); + Eigen::Map<Vector6d> bias_imu_prior(bias_imu_prior_vec.data()); + std::vector<double> b_p_bi_vec = config["b_p_bi"].as<std::vector<double>>(); + std::vector<double> b_q_i_vec = config["b_q_i"].as<std::vector<double>>(); + std::vector<double> l_p_lg_vec = config["l_p_lg"].as<std::vector<double>>(); + Eigen::Map<Vector3d> b_p_bi(b_p_bi_vec.data()); + Eigen::Map<Vector4d> b_qvec_i(b_q_i_vec.data()); + Eigen::Map<Vector3d> l_p_lg(l_p_lg_vec.data()); + double fz_thresh = config["fz_thresh"].as<double>(); + + // MOCAP + double std_pose_p = config["std_pose_p"].as<double>(); + double std_pose_o_deg = config["std_pose_o_deg"].as<double>(); + double std_mocap_extr_p = config["std_mocap_extr_p"].as<double>(); + double std_mocap_extr_o_deg = config["std_mocap_extr_o_deg"].as<double>(); + bool unfix_extr_sensor_pose = config["unfix_extr_sensor_pose"].as<bool>(); + bool time_tolerance_mocap = config["time_tolerance_mocap"].as<double>(); + double time_shift_mocap = config["time_shift_mocap"].as<double>(); + + + std::string data_file_path = config["data_file_path"].as<std::string>(); + std::string out_npz_file_path = config["out_npz_file_path"].as<std::string>(); + + // Base to IMU transform + Quaterniond b_q_i(b_qvec_i); + assert(b_q_i.normalized().isApprox(b_q_i)); + Quaterniond i_q_b = b_q_i.conjugate(); + SE3 b_T_i(b_q_i, b_p_bi); + SE3 i_T_b = b_T_i.inverse(); + Matrix3d b_R_i = b_T_i.rotation(); + Vector3d i_p_ib = i_T_b.translation(); + Matrix3d i_R_b = i_T_b.rotation(); + + // initialize some vectors and fill them with dicretized data + cnpy::npz_t arr_map = cnpy::npz_load(data_file_path); + + //load it into a new array + cnpy::NpyArray t_npyarr = arr_map["t"]; + cnpy::NpyArray imu_acc_npyarr = arr_map["imu_acc"]; + // cnpy::NpyArray o_a_oi_npyarr = arr_map["o_a_oi"]; + cnpy::NpyArray o_q_i_npyarr = arr_map["o_q_i"]; + cnpy::NpyArray i_omg_oi_npyarr = arr_map["i_omg_oi"]; + cnpy::NpyArray qa_npyarr = arr_map["qa"]; + cnpy::NpyArray dqa_npyarr = arr_map["dqa"]; + cnpy::NpyArray tau_npyarr = arr_map["tau"]; + cnpy::NpyArray l_forces_npyarr = arr_map["l_forces"]; + // cnpy::NpyArray w_pose_wm_npyarr = arr_map["w_pose_wm"]; + cnpy::NpyArray m_v_wm_npyarr = arr_map["m_v_wm"]; + cnpy::NpyArray w_v_wm_npyarr = arr_map["w_v_wm"]; + // cnpy::NpyArray o_R_i_npyarr = arr_map["o_R_i"]; + cnpy::NpyArray w_p_wm_npyarr = arr_map["w_p_wm"]; + cnpy::NpyArray w_q_m_npyarr = arr_map["w_q_m"]; + // cnpy::NpyArray contact_npyarr = arr_map["contact"]; + // cnpy::NpyArray b_p_bl_mocap_npyarr = arr_map["b_p_bl_mocap"]; + + // cnpy::NpyArray w_R_m_npyarr = arr_map["w_R_m"]; + double* t_arr = t_npyarr.data<double>(); + double* imu_acc_arr = imu_acc_npyarr.data<double>(); + // double* o_a_oi_arr = o_a_oi_npyarr.data<double>(); + double* i_omg_oi_arr = i_omg_oi_npyarr.data<double>(); + double* qa_arr = qa_npyarr.data<double>(); + double* dqa_arr = dqa_npyarr.data<double>(); + double* tau_arr = tau_npyarr.data<double>(); + double* l_forces_arr = l_forces_npyarr.data<double>(); + // double* w_pose_wm_arr = w_pose_wm_npyarr.data<double>(); + double* m_v_wm_arr = m_v_wm_npyarr.data<double>(); + double* w_v_wm_arr = w_v_wm_npyarr.data<double>(); + double* o_q_i_arr = o_q_i_npyarr.data<double>(); + // double* o_R_i_arr = o_R_i_npyarr.data<double>(); + double* w_p_wm_arr = w_p_wm_npyarr.data<double>(); + double* w_q_m_arr = w_q_m_npyarr.data<double>(); + + // double* contact_arr = contact_npyarr.data<double>(); + // double* b_p_bl_mocap_arr = b_p_bl_mocap_npyarr.data<double>(); + + // double* w_R_m_arr = w_R_m_npyarr.data<double>(); + unsigned int N = t_npyarr.shape[0]; + if (max_t > 0){ + N = N < int(max_t/dt) ? N : int(max_t/dt); + } + + ///////////////////////// + // WOLF enters the scene + // SETUP PROBLEM/SENSORS/PROCESSORS + std::string bodydynamics_root_dir = _WOLF_BODYDYNAMICS_ROOT_DIR; + + ProblemPtr problem = Problem::create("POV", 3); + + // add a tree manager for sliding window optimization + ParserYaml parser = ParserYaml("demos/tree_manager.yaml", bodydynamics_root_dir); + ParamsServer server = ParamsServer(parser.getParams()); + auto tree_manager = TreeManagerSlidingWindow::create("tree_manager", server); + problem->setTreeManager(tree_manager); + + ////////////////////// + // COMPUTE INITIAL STATE + TimeStamp t0(t_arr[0]); + Eigen::Map<Vector4d> o_q_i(o_q_i_arr); // initialize with IMU orientation + Eigen::Map<Vector3d> i_omg_oi(i_omg_oi_arr); // Hyp: b=i (not the case) + Eigen::Map<Vector3d> w_p_wm(w_p_wm_arr); + Eigen::Map<Vector4d> w_qvec_wm(w_q_m_arr); + w_qvec_wm.normalize(); // not close enough to wolf eps sometimes + + ////////////////////// + + // CERES WRAPPER + SolverCeresPtr solver = std::make_shared<SolverCeres>(problem); + solver->getSolverOptions().max_num_iterations = max_num_iterations; + + //===================================================== INITIALIZATION + // SENSOR + PROCESSOR IMU + SensorBasePtr sen_imu_base = problem->installSensor("SensorImu", "SenImu", (Vector7d() << 0,0,0, 0,0,0,1).finished(), bodydynamics_root_dir + "/demos/sensor_imu_solo12.yaml"); + SensorImuPtr sen_imu = std::static_pointer_cast<SensorImu>(sen_imu_base); + ProcessorBasePtr proc_ftp_base = problem->installProcessor("ProcessorImu", "imu pre-integrator", "SenImu", bodydynamics_root_dir + "/demos/processor_imu_solo12.yaml"); + ProcessorImuPtr proc_imu = std::static_pointer_cast<ProcessorImu>(proc_ftp_base); + + // SENSOR + PROCESSOR POSE (for mocap) + // pose sensor and proc (to get extrinsics in the prb) + auto intr_sp = std::make_shared<ParamsSensorPose>(); + intr_sp->std_p = std_pose_p; + intr_sp->std_o = toRad(std_pose_o_deg); + Vector7d extr_pose; extr_pose << i_p_ib, i_q_b.coeffs(); + auto sensor_pose = problem->installSensor("SensorPose", "pose", extr_pose, intr_sp); + auto params_proc = std::make_shared<ParamsProcessorPose>(); + params_proc->time_tolerance = time_tolerance_mocap; + auto proc_pose = problem->installProcessor("ProcessorPose", "pose", sensor_pose, params_proc); + // somehow by default the sensor extrinsics is fixed + Matrix3d cov_sp_p = pow(std_mocap_extr_p, 2)*Matrix3d::Identity(); + Matrix3d cov_sp_o = pow(std_mocap_extr_o_deg/60, 2)*Matrix3d::Identity(); + sensor_pose->addPriorParameter('P', extr_pose.head<3>(), cov_sp_p); + sensor_pose->addPriorParameter('O', extr_pose.tail<4>(), cov_sp_o); + if (unfix_extr_sensor_pose){ + sensor_pose->unfixExtrinsics(); + } + else{ + sensor_pose->fixExtrinsics(); + } + + VectorComposite x_origin("POV", {w_p_wm, w_qvec_wm, Vector3d::Zero()}); + VectorComposite std_origin("POV", {std_prior_p*Vector3d::Ones(), std_prior_o*Vector3d::Ones(), std_prior_v*Vector3d::Ones()}); + // FrameBasePtr KF1 = problem->setPriorFactor(x_origin, std_origin, t0, 0.0005); + FrameBasePtr KF1 = problem->setPriorInitialGuess(x_origin, t0, 0.0005); // if mocap used + + proc_imu->setOrigin(KF1); + + ////////////////////////////////////////// + // INITIAL BIAS FACTORS + // Add absolute factor on Imu biases to simulate a fix() + Vector6d std_abs_imu; std_abs_imu << std_abs_bias_acc*Vector3d::Ones(), std_abs_bias_gyro*Vector3d::Ones(); + Matrix6d Q_bi = std_abs_imu.array().square().matrix().asDiagonal(); + CaptureBasePtr capbi0 = CaptureBase::emplace<CaptureBase>(KF1, "bi0", t0); + FeatureBasePtr featbi0 = FeatureBase::emplace<FeatureBase>(capbi0, "bi0", bias_imu_prior, Q_bi); + FactorBasePtr facbi0 = FactorBase::emplace<FactorBlockAbsolute>(featbi0, featbi0, KF1->getCaptureOf(sen_imu)->getSensorIntrinsic(), nullptr, false); + KF1->getCaptureOf(sen_imu)->getStateBlock('I')->setState(bias_imu_prior); + sen_imu->getStateBlock('I')->setState(bias_imu_prior); + // sen_imu->fixIntrinsics(); + + + ////////////////////////////////////////// + // Vectors to store estimates at the time of data processing + // fbk -> feedback: to check if the estimation is stable enough for feedback control + std::vector<Vector3d> p_ob_fbk_v; + std::vector<Vector4d> q_ob_fbk_v; + std::vector<Vector3d> v_ob_fbk_v; + // Allocate on the heap to prevent stack overflow for large datasets + double* o_p_ob_fbk_carr = new double[3*N]; + double* o_q_b_fbk_carr = new double[4*N]; + double* o_v_ob_fbk_carr = new double[3*N]; + double* imu_bias_fbk_carr = new double[6*N]; + double* extr_mocap_fbk_carr = new double[7*N]; + + std::vector<Vector3d> i_omg_oi_v; + ////////////////////////////////////////// + + unsigned int nb_kf = 1; + for (unsigned int i=0; i < N; i++){ + TimeStamp ts(t_arr[i]); + + //////////////////////////////////// + // Retrieve current state + VectorComposite curr_state = problem->getState(); + Vector4d o_qvec_i_curr = curr_state['O']; + Quaterniond o_q_i_curr(o_qvec_i_curr); + Vector3d o_v_oi_curr = curr_state['V']; + + //////////////////////////////////// + //////////////////////////////////// + // Get measurements + // retrieve traj data + Eigen::Map<Vector3d> imu_acc(imu_acc_arr+3*i); + Eigen::Map<Vector3d> i_omg_oi(i_omg_oi_arr+3*i); // Hyp: b=i (not the case) + Eigen::Map<Matrix<double,12, 1>> tau(tau_arr+12*i); + Eigen::Map<Matrix<double,12, 1>> qa(qa_arr+12*i); + Eigen::Map<Matrix<double,12, 1>> dqa(dqa_arr+12*i); + Eigen::Map<Vector3d> w_p_wm(w_p_wm_arr+3*i); + Eigen::Map<Vector4d> w_qvec_wm(w_q_m_arr+4*i); + w_qvec_wm.normalize(); // not close enough to wolf eps sometimes + + // store i_omg_oi for later computation of o_v_ob from o_v_oi + i_omg_oi_v.push_back(i_omg_oi); + + Vector6d imu_bias = sen_imu->getStateBlockDynamic('I', t_arr[i])->getState(); + Vector3d i_omg_oi_unbiased = (i_omg_oi - imu_bias.tail<3>()); + + + //////////////////////////////////// + // IMU + Vector6d acc_gyr_meas; acc_gyr_meas << imu_acc, i_omg_oi; + Matrix6d acc_gyr_cov = sen_imu->getNoiseCov(); + + CaptureImuPtr CImu = std::make_shared<CaptureImu>(ts, sen_imu, acc_gyr_meas, acc_gyr_cov); + CImu->process(); + + // Vector7d pose_meas; pose_meas << w_p_wm, w_qvec_wm; + Vector7d pose_meas; pose_meas << w_p_wm, w_qvec_wm; + CapturePosePtr CP = std::make_shared<CapturePose>(ts+time_shift_mocap, sensor_pose, pose_meas, sensor_pose->getNoiseCov()); + CP->process(); + + // solve every new KF + if (problem->getTrajectory()->getFrameMap().size() > nb_kf ){ + std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); + std::cout << ts << " "; + std::cout << report << std::endl; + nb_kf = problem->getTrajectory()->getFrameMap().size(); + } + + // Store current state estimation + VectorComposite state_fbk = problem->getState(ts); + Vector3d o_p_oi = state_fbk['P']; + Vector4d o_qvec_i = state_fbk['O']; + Vector3d o_v_oi = state_fbk['V']; + + // IMU to base frame + Matrix3d o_R_i = Quaterniond(o_qvec_i).toRotationMatrix(); + // o_R_i = Quaterniond(o_qvec_i).toRotationMatrix(); + Matrix3d o_R_b = o_R_i * i_R_b; + Vector4d o_qvec_b = Quaterniond(o_R_b).coeffs(); + Vector3d o_p_ob = o_p_oi + o_R_i * i_p_ib; + Vector3d o_v_ob = o_v_oi + o_R_i * i_omg_oi_unbiased.cross(o_R_i*b_p_bi); + // Vector3d o_p_ob = o_p_oi; + // Vector3d o_v_ob = o_v_oi; + + imu_bias = sen_imu->getIntrinsic()->getState(); + Vector7d extr_mocap_est; extr_mocap_est << sensor_pose->getP()->getState(), sensor_pose->getO()->getState(); + + mempcpy(o_p_ob_fbk_carr+3*i, o_p_ob.data(), 3*sizeof(double)); + mempcpy(o_q_b_fbk_carr +4*i, o_qvec_b.data(), 4*sizeof(double)); + mempcpy(o_v_ob_fbk_carr+3*i, o_v_ob.data(), 3*sizeof(double)); + mempcpy(imu_bias_fbk_carr+6*i, imu_bias.data(), 6*sizeof(double)); + mempcpy(extr_mocap_fbk_carr+7*i, extr_mocap_est.data(), 7*sizeof(double)); + + p_ob_fbk_v.push_back(o_p_ob); + q_ob_fbk_v.push_back(o_qvec_b); + v_ob_fbk_v.push_back(o_v_ob); + } + + + + /////////////////////////////////////////// + //////////////// SOLVING ////////////////// + /////////////////////////////////////////// + if (solve_end){ + std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); + problem->print(4,true,true,true); + std::cout << report << std::endl; + } + + double* o_p_ob_carr = new double[3*N]; + double* o_q_b_carr = new double[4*N]; + double* imu_bias_carr = new double[6*N]; + double* o_v_ob_carr = new double[6*N]; + for (unsigned int i=0; i < N; i++) { + VectorComposite state_est = problem->getState(t_arr[i]); + Vector3d i_omg_oi = i_omg_oi_v[i]; + Vector3d o_p_oi = state_est['P']; + Vector4d o_qvec_i = state_est['O']; + Vector3d o_v_oi = state_est['V']; + + auto sb = sen_imu->getStateBlockDynamic('I', t_arr[i]); + Vector6d imu_bias = sb->getState(); + // std::cout << t_arr[i] << ", imu_bias: " << imu_bias.transpose() << std::endl; + Vector3d i_omg_oi_unbiased = (i_omg_oi - imu_bias.tail<3>()); + + Matrix3d o_R_i = Quaterniond(o_qvec_i).toRotationMatrix(); + Matrix3d o_R_b = o_R_i * i_R_b; + Vector4d o_qvec_b = Quaterniond(o_R_b).coeffs(); + Vector3d o_p_ob = o_p_oi + o_R_i * i_p_ib; + Vector3d o_v_ob = o_v_oi + o_R_i * i_omg_oi_unbiased.cross(i_R_b*b_p_bi); + // Vector3d o_p_ob = o_p_oi; + // Vector3d o_v_ob = o_v_oi; + + mempcpy(o_p_ob_carr+3*i, o_p_ob.data(), 3*sizeof(double)); + mempcpy(o_q_b_carr +4*i, o_qvec_b.data(), 4*sizeof(double)); + mempcpy(o_v_ob_carr+3*i, o_v_ob.data(), 3*sizeof(double)); + mempcpy(imu_bias_carr+6*i, imu_bias.data(), 6*sizeof(double)); + } + + + // Compute Covariances + unsigned int Nkf = problem->getTrajectory()->getFrameMap().size(); + double* tkf_carr = new double[1*Nkf]; + double* Qp_carr = new double[3*Nkf]; + double* Qo_carr = new double[3*Nkf]; + double* Qv_carr = new double[3*Nkf]; + double* Qbi_carr = new double[6*Nkf]; + double* Qm_carr = new double[6*Nkf]; + // factor errors + double* fac_imu_err_carr = new double[9*Nkf]; + double* fac_pose_err_carr = new double[6*Nkf]; + int i = 0; + for (auto& elt: problem->getTrajectory()->getFrameMap()){ + std::cout << "Traj " << i << "/" << problem->getTrajectory()->getFrameMap().size() << std::endl; + tkf_carr[i] = elt.first.get(); + auto kf = elt.second; + VectorComposite kf_state = kf->getState(); + + // compute covariances of KF and capture stateblocks + Eigen::MatrixXd Qp = Eigen::Matrix3d::Identity(); + Eigen::MatrixXd Qo = Eigen::Matrix3d::Identity(); // global or local? + Eigen::MatrixXd Qv = Eigen::Matrix3d::Identity(); + Eigen::MatrixXd Qbi = Eigen::Matrix6d::Identity(); + Eigen::MatrixXd Qmp = Eigen::Matrix3d::Identity(); // extr mocap + Eigen::MatrixXd Qmo = Eigen::Matrix3d::Identity(); // extr mocap + + solver->computeCovariances(SolverManager::CovarianceBlocksToBeComputed::ALL); // should not be computed every time !! see below + problem->getCovarianceBlock(kf->getStateBlock('P'), Qp); + problem->getCovarianceBlock(kf->getStateBlock('O'), Qo); + problem->getCovarianceBlock(kf->getStateBlock('V'), Qv); + + CaptureBasePtr cap_imu = kf->getCaptureOf(sen_imu); + + std::vector<StateBlockPtr> extr_sb_vec = {sensor_pose->getP(), sensor_pose->getO()}; + solver->computeCovariances(extr_sb_vec); // not computed by ALL and destroys other computed covs -> issue to raise + problem->getCovarianceBlock(sensor_pose->getP(), Qmp); + problem->getCovarianceBlock(sensor_pose->getO(), Qmo); + // std::cout << "Qbp\n" << Qbp << std::endl; + solver->computeCovariances(cap_imu->getStateBlockVec()); // not computed by ALL and destroys other computed covs -> issue to raise + problem->getCovarianceBlock(cap_imu->getSensorIntrinsic(), Qbi); + + // diagonal components + Vector3d Qp_diag = Qp.diagonal(); + Vector3d Qo_diag = Qo.diagonal(); + Vector3d Qv_diag = Qv.diagonal(); + Vector6d Qbi_diag = Qbi.diagonal(); + Vector6d Qm_diag; Qm_diag << Qmp.diagonal(), Qmo.diagonal(); + + memcpy(Qp_carr + 3*i, Qp_diag.data(), 3*sizeof(double)); + memcpy(Qo_carr + 3*i, Qo_diag.data(), 3*sizeof(double)); + memcpy(Qv_carr + 3*i, Qv_diag.data(), 3*sizeof(double)); + memcpy(Qbi_carr + 6*i, Qbi_diag.data(), 6*sizeof(double)); + memcpy(Qm_carr + 6*i, Qm_diag.data(), 6*sizeof(double)); + + // Factor errors + // std::cout << "Factors " << kf->getTimeStamp().get() << std::endl; + FactorBasePtrList fac_lst; + kf->getFactorList(fac_lst); + Vector9d imu_err = Vector9d::Zero(); + Vector6d pose_err = Vector6d::Zero(); + for (auto fac: fac_lst){ + if (fac->getProcessor() == proc_imu){ + auto f = std::dynamic_pointer_cast<FactorImu>(fac); + // Matrix6d R_bias_drift = f->getMeasurementSquareRootInformationUpper().bottomRightCorner<6,6>(); + // Matrix6d R_bias_drift = f->getFeature()->getMeasurementSquareRootInformationUpper().bottomRightCorner<6,6>(); + // std::cout << R_bias_drift << std::endl; + // MatrixXd R_bias_drift = f->getFeature()->getMeasurementSquareRootInformationUpper(); + // MatrixXd Cov_bias_drift = f->getFeature()->getMeasurementCovariance(); + // std::cout << "R_bias_drift" << std::endl; + // std::cout << R_bias_drift << std::endl; + // std::cout << "Cov_bias_drift" << std::endl; + // std::cout << Cov_bias_drift << std::endl; + + if (f){ + imu_err = f->error(); + } + } + if (fac->getProcessor() == proc_pose){ + auto f = std::dynamic_pointer_cast<FactorPose3dWithExtrinsics>(fac); + if (f){ + pose_err = f->error(); + } + } + } + memcpy(fac_imu_err_carr + 9*i, imu_err.data(), 9*sizeof(double)); + memcpy(fac_pose_err_carr + 6*i, pose_err.data(), 6*sizeof(double)); + + + i++; + } + + // Save trajectories in npz file + // save ground truth + cnpy::npz_save(out_npz_file_path, "t", t_arr, {N}, "w"); // "w" overwrites any file with same name + cnpy::npz_save(out_npz_file_path, "w_p_wm", w_p_wm_arr, {N,3}, "a"); // "a" appends to the file we created above + cnpy::npz_save(out_npz_file_path, "w_q_m", w_q_m_arr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "w_v_wm", w_v_wm_arr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "m_v_wm", m_v_wm_arr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_i", o_q_i_arr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "qa", qa_arr, {N,12}, "a"); + + // save estimates + cnpy::npz_save(out_npz_file_path, "o_p_ob_fbk", o_p_ob_fbk_carr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_b_fbk", o_q_b_fbk_carr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "o_v_ob_fbk", o_v_ob_fbk_carr, {N,3}, "a"); + + cnpy::npz_save(out_npz_file_path, "o_p_ob", o_p_ob_carr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_b", o_q_b_carr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "o_v_ob", o_v_ob_carr, {N,3}, "a"); + + // and biases/extrinsics + cnpy::npz_save(out_npz_file_path, "imu_bias_fbk", imu_bias_fbk_carr, {N,6}, "a"); + cnpy::npz_save(out_npz_file_path, "imu_bias", imu_bias_carr, {N,6}, "a"); + cnpy::npz_save(out_npz_file_path, "extr_mocap_fbk", extr_mocap_fbk_carr, {N,7}, "a"); + + // covariances + cnpy::npz_save(out_npz_file_path, "tkf", tkf_carr, {Nkf}, "a"); + cnpy::npz_save(out_npz_file_path, "Qp", Qp_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qo", Qo_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qv", Qv_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qbi", Qbi_carr, {Nkf,6}, "a"); + cnpy::npz_save(out_npz_file_path, "Qm", Qm_carr, {Nkf,6}, "a"); + cnpy::npz_save(out_npz_file_path, "fac_imu_err", fac_imu_err_carr, {Nkf,9}, "a"); + cnpy::npz_save(out_npz_file_path, "fac_pose_err", fac_pose_err_carr, {Nkf,6}, "a"); + +} diff --git a/demos/solo_real_estimation.yaml b/demos/solo_real_estimation.yaml index c00ef31936d3db340ceefa227cf9d159f4c6e0d5..1867ec7a227dd3a3d623fc6db430a9cbb36d823b 100644 --- a/demos/solo_real_estimation.yaml +++ b/demos/solo_real_estimation.yaml @@ -65,9 +65,9 @@ l_p_lg: [0.0, 0, 0] # l_p_lg: [0, 0, -0.031] # for sin traj, point to which position estimation on z starts to be less good # base to IMU transformation -b_p_bi: [0.0, 0.0, 0.0] +# b_p_bi: [0.0, 0.0, 0.0] # b_p_bi: [-0.2, 0.0, 0.0] -# b_p_bi: [0.1163, 0.0, 0.02] +b_p_bi: [0.1163, 0.0, 0.02] b_q_i: [0.0, 0.0, 0.0, 1.0] # b_q_i: [0.00000592745, -0.03255761280, -0.00025745595, 0.706732091] diff --git a/demos/solo_real_pov_estimation.cpp b/demos/solo_real_pov_estimation.cpp index 83cc8497bad7a63d861d97dd5540f17bb0a073d6..efd455589bd1cbb5889630802a58b0099e8e11f0 100644 --- a/demos/solo_real_pov_estimation.cpp +++ b/demos/solo_real_pov_estimation.cpp @@ -294,7 +294,9 @@ int main (int argc, char **argv) { CaptureBasePtr capbi0 = CaptureBase::emplace<CaptureBase>(KF1, "bi0", t0); FeatureBasePtr featbi0 = FeatureBase::emplace<FeatureBase>(capbi0, "bi0", bias_imu_prior, Q_bi); FactorBasePtr facbi0 = FactorBase::emplace<FactorBlockAbsolute>(featbi0, featbi0, KF1->getCaptureOf(sen_imu)->getSensorIntrinsic(), nullptr, false); + KF1->getCaptureOf(sen_imu)->getStateBlock('I')->setState(bias_imu_prior); sen_imu->getStateBlock('I')->setState(bias_imu_prior); + // sen_imu->fixIntrinsics(); ///////////////////////////////////////////