diff --git a/.gitignore b/.gitignore index fae25dce1facaccabf8aa15085cf2491d5959212..7ecae7d373f3c31b6d5e51edd4c90749667984b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,13 @@ -.cproject +\.cproject .project .settings/ README.txt bin/ build/ +build_debug/ build_release/ +build-debug/ +build-release/ lib/ .idea/ ./Wolf.user @@ -30,6 +33,5 @@ src/CMakeFiles/cmake.check_cache src/examples/map_apriltag_save.yaml \.vscode/ -build_release/ wolf.found diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 355377d34fc5eace45662a92970c30c837fe3ad7..ff1e2eb36d460125006290be0be82e37296c54e9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,6 +3,13 @@ stages: - build_and_test ############ YAML ANCHORS ############ +.print_variables_template: &print_variables_definition + # Print variables + - echo $WOLF_CORE_BRANCH + - echo $CI_COMMIT_BRANCH + - echo $WOLF_BODYDYNAMICS_BRANCH + - echo $WOLF_IMU_BRANCH + .preliminaries_template: &preliminaries_definition ## Install ssh-agent if not already installed, it is required by Docker. ## (change apt-get to yum if you use an RPM-based image) @@ -117,6 +124,7 @@ license_headers: paths: - ci_deps/wolf/ before_script: + - *print_variables_definition - *preliminaries_definition - *install_wolf_definition script: @@ -134,6 +142,7 @@ build_and_test:bionic: paths: - ci_deps/imu/ before_script: + - *print_variables_definition - *preliminaries_definition - *install_wolf_definition - *install_wolfimu_definition @@ -153,6 +162,7 @@ build_and_test:focal: paths: - ci_deps/imu/ before_script: + - *print_variables_definition - *preliminaries_definition - *install_wolf_definition - *install_wolfimu_definition diff --git a/CMakeLists.txt b/CMakeLists.txt index b2d37d37685bef61e1d3478e941593df4a675be8..9ca4dd5c2fccc846c026b27a12f511560f160c58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,6 @@ # Pre-requisites about cmake itself -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +CMAKE_MINIMUM_REQUIRED(VERSION 3.10) -if(COMMAND cmake_policy) - cmake_policy(SET CMP0005 NEW) - cmake_policy(SET CMP0003 NEW) -endif(COMMAND cmake_policy) # MAC OSX RPATH SET(CMAKE_MACOSX_RPATH 1) @@ -16,7 +12,8 @@ MESSAGE("Starting ${PROJECT_NAME} CMakeLists ...") SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin) SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib) -SET(CMAKE_INSTALL_PREFIX /usr/local) +set(INCLUDE_INSTALL_DIR include/iri-algorithms/wolf) +set(LIB_INSTALL_DIR lib/) IF (NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE "DEBUG") @@ -67,10 +64,6 @@ if(BUILD_TESTS) enable_testing() endif() -#CMAKE modules -SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules") -MESSAGE(STATUS ${CMAKE_MODULE_PATH}) - # Some wolf compilation options IF((CMAKE_BUILD_TYPE MATCHES DEBUG) OR (CMAKE_BUILD_TYPE MATCHES debug) OR (CMAKE_BUILD_TYPE MATCHES Debug)) set(_WOLF_DEBUG true) @@ -79,12 +72,14 @@ ENDIF() option(_WOLF_TRACE "Enable wolf tracing macro" ON) # ============ DEPENDENCIES ============ -FIND_PACKAGE(wolfcore REQUIRED) +FIND_PACKAGE(wolfcore REQUIRED CONFIG) FIND_PACKAGE(wolfimu REQUIRED) +FIND_PACKAGE(Eigen3 3.3 REQUIRED CONFIG) # ============ CONFIG.H ============ -string(TOUPPER ${PROJECT_NAME} UPPER_NAME) set(_WOLF_ROOT_DIR ${CMAKE_SOURCE_DIR}) +# variable used to compile the config.h.in file +string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER) # Define the directory where will be the configured config.h SET(WOLF_CONFIG_DIR ${PROJECT_BINARY_DIR}/conf/${PROJECT_NAME}/internal) @@ -103,7 +98,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/internal/config.h.in "${WOLF_CONFIG_D include_directories("${PROJECT_BINARY_DIR}/conf") # ============ INCLUDES ============ -INCLUDE_DIRECTORIES(${wolfimu_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(BEFORE "include") # ============ HEADERS ============ @@ -121,6 +115,7 @@ include/bodydynamics/factor/factor_force_torque.h include/bodydynamics/factor/factor_force_torque_preint.h include/bodydynamics/factor/factor_inertial_kinematics.h include/bodydynamics/factor/factor_point_feet_nomove.h +include/bodydynamics/factor/factor_point_feet_altitude.h ) SET(HDRS_FEATURE include/bodydynamics/feature/feature_force_torque.h @@ -184,11 +179,12 @@ endif() #Link the created libraries #===============EXAMPLE========================= -TARGET_LINK_LIBRARIES(${PLUGIN_NAME} ${wolfimu_LIBRARIES}) +TARGET_LINK_LIBRARIES(${PLUGIN_NAME} PUBLIC wolfcore) +TARGET_LINK_LIBRARIES(${PLUGIN_NAME} PUBLIC wolfimu) +TARGET_LINK_LIBRARIES(${PLUGIN_NAME} PUBLIC Eigen3::Eigen) # Build demos IF(BUILD_DEMOS) - #Build examples MESSAGE("Building demos.") ADD_SUBDIRECTORY(demos) ENDIF(BUILD_DEMOS) @@ -199,14 +195,38 @@ IF(BUILD_TESTS) add_subdirectory(test) ENDIF(BUILD_TESTS) + #install library #============================================================= INSTALL(TARGETS ${PLUGIN_NAME} EXPORT ${PLUGIN_NAME}Targets RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} +) +install(EXPORT ${PLUGIN_NAME}Targets DESTINATION lib/${PLUGIN_NAME}/cmake) + +# Configure the package installation +include(CMakePackageConfigHelpers) +configure_package_config_file( + ${CMAKE_SOURCE_DIR}/cmake_modules/${PLUGIN_NAME}Config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_NAME}Config.cmake + INSTALL_DESTINATION ${LIB_INSTALL_DIR}/${PLUGIN_NAME}/cmake + PATH_VARS INCLUDE_INSTALL_DIR LIB_INSTALL_DIR +) + +install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_NAME}Config.cmake + DESTINATION + ${LIB_INSTALL_DIR}/${PLUGIN_NAME}/cmake +) + +# Specifies include directories to use when compiling the plugin target +# This way, include_directories does not need to be called in plugins depending on this one +target_include_directories(${PLUGIN_NAME} INTERFACE + $<INSTALL_INTERFACE:${INCLUDE_INSTALL_DIR}> +) -install(EXPORT ${PLUGIN_NAME}Targets DESTINATION lib/cmake/${PLUGIN_NAME}) #install headers INSTALL(FILES ${HDRS_CAPTURE} DESTINATION include/iri-algorithms/wolf/plugin_${PROJECT_NAME}/${PROJECT_NAME}/capture) @@ -221,17 +241,12 @@ INSTALL(FILES ${HDRS_PROCESSOR} INSTALL(FILES ${HDRS_SENSOR} DESTINATION include/iri-algorithms/wolf/plugin_${PROJECT_NAME}/${PROJECT_NAME}/sensor) -FILE(WRITE ${PROJECT_NAME}.found "") -INSTALL(FILES ${PROJECT_NAME}.found - DESTINATION include/iri-algorithms/wolf/plugin_${PROJECT_NAME}) INSTALL(FILES "${WOLF_CONFIG_DIR}/config.h" DESTINATION include/iri-algorithms/wolf/plugin_${PROJECT_NAME}/${PROJECT_NAME}/internal) -INSTALL(FILES "${CMAKE_SOURCE_DIR}/cmake_modules/${PLUGIN_NAME}Config.cmake" DESTINATION "lib/cmake/${PLUGIN_NAME}") - export(PACKAGE ${PLUGIN_NAME}) -FIND_PACKAGE(Doxygen) +FIND_PACKAGE(Doxygen MODULE) FIND_PATH(IRI_DOC_DIR doxygen.conf ${CMAKE_SOURCE_DIR}/doc/iri_doc/) IF (IRI_DOC_DIR) diff --git a/bodydynamics.found b/bodydynamics.found deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/cmake_modules/wolfbodydynamicsConfig.cmake b/cmake_modules/wolfbodydynamicsConfig.cmake deleted file mode 100644 index cfb538c1d7d49ef39ea0f6994488f9bc59d27724..0000000000000000000000000000000000000000 --- a/cmake_modules/wolfbodydynamicsConfig.cmake +++ /dev/null @@ -1,91 +0,0 @@ -#edit the following line to add the librarie's header files -FIND_PATH( - wolfbodydynamics_INCLUDE_DIRS - NAMES bodydynamics.found - PATHS /usr/local/include/iri-algorithms/wolf/plugin_bodydynamics) -IF(wolfbodydynamics_INCLUDE_DIRS) - MESSAGE("Found wolf bodydynamics include dirs: ${wolfbodydynamics_INCLUDE_DIRS}") -ELSE(wolfbodydynamics_INCLUDE_DIRS) - MESSAGE("Couldn't find wolf bodydynamics include dirs") -ENDIF(wolfbodydynamics_INCLUDE_DIRS) - -FIND_LIBRARY( - wolfbodydynamics_LIBRARIES - NAMES libwolfbodydynamics.so - PATHS /usr/local/lib) -IF(wolfbodydynamics_LIBRARIES) - MESSAGE("Found wolf bodydynamics lib: ${wolfbodydynamics_LIBRARIES}") -ELSE(wolfbodydynamics_LIBRARIES) - MESSAGE("Couldn't find wolf bodydynamics lib") -ENDIF(wolfbodydynamics_LIBRARIES) - -IF (wolfbodydynamics_INCLUDE_DIRS AND wolfbodydynamics_LIBRARIES) - SET(wolfbodydynamics_FOUND TRUE) - ELSE(wolfbodydynamics_INCLUDE_DIRS AND wolfbodydynamics_LIBRARIES) - set(wolfbodydynamics_FOUND FALSE) -ENDIF (wolfbodydynamics_INCLUDE_DIRS AND wolfbodydynamics_LIBRARIES) - -IF (wolfbodydynamics_FOUND) - IF (NOT wolfbodydynamics_FIND_QUIETLY) - MESSAGE(STATUS "Found wolf bodydynamics: ${wolfbodydynamics_LIBRARIES}") - ENDIF (NOT wolfbodydynamics_FIND_QUIETLY) -ELSE (wolfbodydynamics_FOUND) - IF (wolfbodydynamics_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find wolf bodydynamics") - ENDIF (wolfbodydynamics_FIND_REQUIRED) -ENDIF (wolfbodydynamics_FOUND) - - -macro(wolf_report_not_found REASON_MSG) - set(wolfbodydynamics_FOUND FALSE) - unset(wolfbodydynamics_INCLUDE_DIRS) - unset(wolfbodydynamics_LIBRARIES) - - # Reset the CMake module path to its state when this script was called. - set(CMAKE_MODULE_PATH ${CALLERS_CMAKE_MODULE_PATH}) - - # Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by - # FindPackage() use the camelcase library name, not uppercase. - if (wolfbodydynamics_FIND_QUIETLY) - message(STATUS "Failed to find wolf bodydynamics- " ${REASON_MSG} ${ARGN}) - elseif(wolfbodydynamics_FIND_REQUIRED) - message(FATAL_ERROR "Failed to find wolf bodydynamics - " ${REASON_MSG} ${ARGN}) - else() - # Neither QUIETLY nor REQUIRED, use SEND_ERROR which emits an error - # that prevents generation, but continues configuration. - message(SEND_ERROR "Failed to find wolf bodydynamics - " ${REASON_MSG} ${ARGN}) - endif () - return() -endmacro(wolf_report_not_found) - -if(NOT wolfbodydynamics_FOUND) - wolf_report_not_found("Something went wrong while setting up wolf bodydynamics.") -endif(NOT wolfbodydynamics_FOUND) -# Set the include directories for wolf (itself). -set(wolfbodydynamics_FOUND TRUE) - -# Now we gather all the required dependencies for Wolf Template - -#EXAMPLE Suppose that Wolf Template depends on laser_scan_utils -# FIND_PACKAGE(laser_scan_utils REQUIRED) -# list(APPEND wolflaser_INCLUDE_DIRS ${laser_scan_utils_INCLUDE_DIRS}) -# list(APPEND wolflaser_LIBRARIES ${laser_scan_utils_LIBRARY}) - -# Making sure that wolf is always looked for -if(NOT wolf_FOUND) - FIND_PACKAGE(wolfcore REQUIRED) - - #We reverse in order to insert at the start - list(REVERSE wolfbodydynamics_INCLUDE_DIRS) - list(APPEND wolfbodydynamics_INCLUDE_DIRS ${wolfcore_INCLUDE_DIRS}) - list(REVERSE wolfbodydynamics_INCLUDE_DIRS) - - list(REVERSE wolfbodydynamics_LIBRARIES) - list(APPEND wolfbodydynamics_LIBRARIES ${wolfcore_LIBRARIES}) - list(REVERSE wolfbodydynamics_LIBRARIES) -endif() - -# provide both INCLUDE_DIR and INCLUDE_DIRS -SET(wolfbodydynamics_INCLUDE_DIR ${wolfbodydynamics_INCLUDE_DIRS}) -# provide both LIBRARY and LIBRARIES -SET(wolfbodydynamics_LIBRARY ${wolfbodydynamics_LIBRARIES}) \ No newline at end of file diff --git a/cmake_modules/wolfbodydynamicsConfig.cmake.in b/cmake_modules/wolfbodydynamicsConfig.cmake.in new file mode 100644 index 0000000000000000000000000000000000000000..0722eb6dafef443a92638b2e888219c9fe0bd017 --- /dev/null +++ b/cmake_modules/wolfbodydynamicsConfig.cmake.in @@ -0,0 +1,13 @@ +set(@PLUGIN_NAME@_VERSION 0.0.1) + + +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +FIND_DEPENDENCY(wolfcore REQUIRED) +FIND_DEPENDENCY(wolfimu REQUIRED) +FIND_DEPENDENCY(Eigen3 3.3 REQUIRED) + +include("${CMAKE_CURRENT_LIST_DIR}/@PLUGIN_NAME@Targets.cmake") + +check_required_components(@PLUGIN_NAME@) \ No newline at end of file diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 4c57e21c724478a56852c13e498ee655ac4a84f8..78d2b265912a542724c6ccaa3609638dc49259e2 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -2,74 +2,63 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals") # necessary for files using boost FIND_PACKAGE(pinocchio QUIET) -FIND_PACKAGE(multicontact-api QUIET) if (pinocchio_FOUND) # SYSTEM disables warnings from library headers include_directories( SYSTEM ${PINOCCHIO_INCLUDE_DIRS} ) - + 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_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}) - + target_link_libraries(mcapi_utils Eigen3::Eigen) + add_executable(solo_real_povcdl_estimation solo_real_povcdl_estimation.cpp) target_link_libraries(solo_real_povcdl_estimation - mcapi_utils - ${wolfcore_LIBRARIES} - ${wolfimu_LIBRARIES} + wolfcore + wolfimu ${PLUGIN_NAME} ${pinocchio_LIBRARIES} /usr/local/lib/libcnpy.so z + mcapi_utils ) - - add_executable(solo_real_pov_estimation solo_real_pov_estimation.cpp) - target_link_libraries(solo_real_pov_estimation - mcapi_utils - ${wolfcore_LIBRARIES} - ${wolfimu_LIBRARIES} + + add_executable(solo_imu_mocap solo_imu_mocap.cpp) + target_link_libraries(solo_imu_mocap + wolfcore + wolfimu ${PLUGIN_NAME} ${pinocchio_LIBRARIES} /usr/local/lib/libcnpy.so 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(solo_imu_kine_mocap solo_imu_kine_mocap.cpp) + target_link_libraries(solo_imu_kine_mocap + wolfcore + wolfimu + ${PLUGIN_NAME} + ${pinocchio_LIBRARIES} + /usr/local/lib/libcnpy.so + z ) + endif() -# add_executable(test_cnpy test_cnpy.cpp) -# target_link_libraries(test_cnpy + + + +# add_library(demo_logger demo_logger.cpp) +# target_include_directories (demo_logger PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + + +# add_executable(solo_imu_mocap_refactored solo_imu_mocap_refactored.cpp) +# target_link_libraries(solo_imu_mocap_refactored +# demo_logger +# ${wolfcore_LIBRARIES} +# ${wolfimu_LIBRARIES} +# ${PLUGIN_NAME} +# ${pinocchio_LIBRARIES} # /usr/local/lib/libcnpy.so +# z # ) - diff --git a/demos/mcapi_pov_estimation.cpp b/demos/mcapi_pov_estimation.cpp deleted file mode 100644 index 9fdc2feebbea2a407bd5268d0be86388804e5de3..0000000000000000000000000000000000000000 --- a/demos/mcapi_pov_estimation.cpp +++ /dev/null @@ -1,751 +0,0 @@ -//--------LICENSE_START-------- -// -// Copyright (C) 2020,2021,2022 Institut de Robòtica i Informà tica Industrial, CSIC-UPC. -// Authors: Joan Solà Ortega (jsola@iri.upc.edu) -// All rights reserved. -// -// This file is part of WOLF -// WOLF is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// -//--------LICENSE_END-------- -#include <iostream> -// #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" - -// MCAPI -#include <curves/fwd.h> -#include <curves/so3_linear.h> -#include <curves/se3_curve.h> -#include <curves/polynomial.h> -#include <curves/bezier_curve.h> -#include <curves/piecewise_curve.h> -#include <curves/exact_cubic.h> -#include <curves/cubic_hermite_spline.h> -#include "multicontact-api/scenario/contact-sequence.hpp" - -// 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_block_absolute.h> -#include <core/processor/processor_odom_3d.h> -#include <core/sensor/sensor_odom_3d.h> - -// IMU -#include "imu/sensor/sensor_imu.h" -#include "imu/capture/capture_imu.h" -#include "imu/processor/processor_imu.h" - -// BODYDYNAMICS -#include "bodydynamics/internal/config.h" -#include "bodydynamics/sensor/sensor_inertial_kinematics.h" -#include "bodydynamics/sensor/sensor_force_torque.h" -#include "bodydynamics/capture/capture_inertial_kinematics.h" -#include "bodydynamics/capture/capture_force_torque_preint.h" -#include "bodydynamics/capture/capture_leg_odom.h" -#include "bodydynamics/processor/processor_inertial_kinematics.h" -#include "bodydynamics/processor/processor_force_torque_preint.h" -#include "bodydynamics/factor/factor_inertial_kinematics.h" -#include "bodydynamics/factor/factor_force_torque_preint.h" - - -// UTILS -#include "mcapi_utils.h" - - -using namespace Eigen; -using namespace wolf; -using namespace pinocchio; -using namespace multicontact_api::scenario; - -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/mcapi_povcdl_estimation.yaml"); - std::string robot_urdf = config["robot_urdf"].as<std::string>(); - int dimc = config["dimc"].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>(); - bool noisy_measurements = config["noisy_measurements"].as<bool>(); - - // 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>(); - - // simulated sensor noises - double std_acc_sim = config["std_acc_sim"].as<double>(); - double std_gyr_sim = config["std_gyr_sim"].as<double>(); - double std_pbc_sim = config["std_pbc_sim"].as<double>(); - double std_vbc_sim = config["std_vbc_sim"].as<double>(); - double std_f_sim = config["std_f_sim"].as<double>(); - double std_tau_sim = config["std_tau_sim"].as<double>(); - // double std_odom3d_sim = config["std_odom3d_sim"].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_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()); - - double fz_thresh = config["fz_thresh"].as<double>(); - double scale_dist = config["scale_dist"].as<double>(); - bool base_dist_only = config["base_dist_only"].as<bool>(); - bool mass_dist = config["mass_dist"].as<bool>(); - bool vbc_is_dist = config["vbc_is_dist"].as<bool>(); - bool Iw_is_dist = config["Iw_is_dist"].as<bool>(); - bool Lgest_is_dist = config["Lgest_is_dist"].as<bool>(); - - std::string contact_sequence_file = config["contact_sequence_file"].as<std::string>(); - - ContactSequence cs; - std::cout << "Loading file " << contact_sequence_file << std::endl; - cs.loadFromBinary(contact_sequence_file); - - auto q_traj = cs.concatenateQtrajectories(); - auto dq_traj = cs.concatenateDQtrajectories(); - auto ddq_traj = cs.concatenateDDQtrajectories(); - auto c_traj = cs.concatenateCtrajectories(); - auto dc_traj = cs.concatenateDCtrajectories(); - auto L_traj = cs.concatenateLtrajectories(); - auto tau_traj = cs.concatenateTauTrajectories(); - std::vector<std::string> ee_names = cs.getAllEffectorsInContact(); - unsigned int nbc = ee_names.size(); - std::vector<curves::piecewise_t> cforce_traj_lst; - for (auto ee_name: ee_names){ - std::cout << ee_name << std::endl; - auto cforce_traj = cs.concatenateContactForceTrajectories(ee_name); - cforce_traj_lst.push_back(cforce_traj); - } - - if (min_t < 0){ - min_t = q_traj.min(); - } - if (max_t < 0){ - max_t = q_traj.max(); - } - - // initialize some vectors and fill them with dicretized data - std::vector<double> t_arr; // timestamps - std::vector<VectorXd> q_traj_arr; // [p_ob, q_ob, qA] - std::vector<VectorXd> dq_traj_arr; // [spvel_b, qA_dot] - std::vector<VectorXd> ddq_traj_arr; // [spacc_b, qA_ddot] - std::vector<VectorXd> c_traj_arr; // w_p_wc - std::vector<VectorXd> dc_traj_arr; // w_v_wc - std::vector<VectorXd> L_traj_arr; // w_Lc: angular momentum at the CoM expressed in CoM (=World) frame - std::vector<VectorXd> tau_traj_arr; // w_Lc: angular momentum at the CoM expressed in CoM (=World) frame - std::vector<VectorXd> bp_traj_arr; // bias on b_p_bc: bias on the CoM position expressed in base frame - std::vector<std::vector<VectorXd>> cforce_traj_arr_lst(nbc); - int N = (max_t - min_t)/dt; - int i_t = 0; - for (double t=min_t; t <= max_t; t += dt){ - t_arr.push_back(t); - q_traj_arr.push_back(q_traj(t)); - dq_traj_arr.push_back(dq_traj(t)); - ddq_traj_arr.push_back(ddq_traj(t)); - c_traj_arr.push_back(c_traj(t)); - dc_traj_arr.push_back(dc_traj(t)); - L_traj_arr.push_back(L_traj(t)); - tau_traj_arr.push_back(tau_traj(t)); - for (unsigned int i_ee=0; i_ee < nbc; i_ee++){ - cforce_traj_arr_lst[i_ee].push_back(cforce_traj_lst[i_ee](t)); - } - i_t++; - } - std::cout << "Trajectory extracted, proceed to create sensor data" << std::endl; - - // Creating measurements from simulated trajectory - // Load the urdf model - Model model; - pinocchio::urdf::buildModel(robot_urdf, JointModelFreeFlyer(), model); - std::cout << "model name: " << model.name << std::endl; - Data data(model); - - // distorted model (modified inertias) - Model model_dist; - pinocchio::urdf::buildModel(robot_urdf, JointModelFreeFlyer(), model_dist); - - Eigen::EigenMultivariateNormal<double> noise_mass = Eigen::EigenMultivariateNormal<double>(Vector1d::Zero(), Matrix1d::Identity(), false); - Eigen::EigenMultivariateNormal<double> noise_lever = Eigen::EigenMultivariateNormal<double>(Vector3d::Zero(), Matrix3d::Identity(), false); - - // distortion - if (base_dist_only){ - if (!mass_dist){ - int root_joint_id = model.getJointId("root_joint"); - Vector3d lever_dist = model.inertias[root_joint_id].lever() + scale_dist * noise_lever.samples(1); - model_dist.inertias[root_joint_id] = pinocchio::Inertia(model.inertias[root_joint_id].mass(), lever_dist, model.inertias[root_joint_id].inertia()); - } - } - else{ - for (int i=0; i < model_dist.inertias.size(); i++){ - if (mass_dist){ - double mass_dist = model.inertias[i].mass() + scale_dist * model.inertias[i].mass() * noise_mass.samples(1)(0,0); - model_dist.inertias[i] = pinocchio::Inertia(mass_dist, model.inertias[i].lever(), model.inertias[i].inertia()); - std::cout << "mass model " << model.inertias[i].mass() << std::endl; - std::cout << "mass model_dist " << model_dist.inertias[i].mass() << std::endl; - } - else { - Vector3d lever_dist = model.inertias[i].lever() + scale_dist * noise_lever.samples(1); - model_dist.inertias[i] = pinocchio::Inertia(model.inertias[i].mass(), lever_dist, model.inertias[i].inertia()); - } - } - } - Data data_dist(model_dist); - - std::vector<int> ee_ids; - std::cout << "Frame ids" << std::endl; - for (auto ee_name: ee_names){ - ee_ids.push_back(model.getFrameId(ee_name)); - std::cout << ee_name << std::endl; - } - std::vector<Vector3d> contacts = contacts_from_footrect_center(); - - /////////////////////////////////////////////// - // Create some vectors to aggregate the groundtruth and measurements - // Groundtruth - std::vector<Vector3d> p_ob_gtr_v; - std::vector<Vector4d> q_ob_gtr_v; - std::vector<Vector3d> v_ob_gtr_v; - // std::vector<VectorXd>& c_gtr_v = c_traj_arr; // already have it directly - // std::vector<VectorXd>& cd_gtr_v = dc_traj_arr; // already have it directly - // std::vector<Vector3d> L_traj_arr; // already have it directly - - - // Measurements - std::vector<Vector3d> acc_b_meas_v; - std::vector<Vector3d> w_b_meas_v; - std::vector<std::vector<Vector3d>> p_bl_meas_v(nbc); - std::vector<std::vector<Vector4d>> q_bl_meas_v(nbc); - std::vector<std::vector<VectorXd>> wrench_meas_v(nbc); - std::vector<Vector3d> p_bc_meas_v; - std::vector<Vector3d> v_bc_meas_v; - std::vector<Vector3d> Lq_meas_v; - std::vector<Matrix3d> Iq_meas_v; - // define vectors to aggregate ground truth and simulated data - for (unsigned int i = 0; i < q_traj_arr.size(); i++) - { - /** - * Groundtruth to recover (in world frame, vels/inertial frame): - * b position --> OK - * b orientation (quat) --> OK - * b velocity: linear classical one --> OK - * CoM posi --> OK - * CoM vel --> OK - * Angular momentum --> OK - * - * Measures to recover (in local frames): - * IMU readings --> OK - * Kinematics readings --> OK - * Wrench readings --> OK - * CoM relative position/vel --> OK - * Iq, Lq --> OK - * - **/ - - // retrieve traj data - VectorXd q = q_traj_arr[i]; - VectorXd dq = dq_traj_arr[i]; - VectorXd ddq = ddq_traj_arr[i]; - // Vector3d c = c_traj_arr[i]; // gtr - // VectorXd dc = dc_traj_arr[i]; // gtr - // VectorXd L = L_traj_arr[i]; // gtr - VectorXd tau = tau_traj_arr[i]; - - // std::cout << "q " << q.transpose() << std::endl; - // std::cout << "dq " << dq.transpose() << std::endl; - // std::cout << "ddq " << ddq.transpose() << std::endl; - - ////////////////////////////////// - ////////////////////////////////// - // Set ground truth variables - Vector3d p_wb = q.head<3>(); // gtr - Vector4d quat_wb = q.segment<4>(3); // gtr - SE3 oTb(Quaterniond(quat_wb).toRotationMatrix(), p_wb); // global frame pose - // body vel is expressed in body frame - Vector3d b_v_b = dq.head<3>(); // vsp: spatial linear velocity - Vector3d b_w_b = dq.segment<3>(3); // meas - Vector3d b_asp_b = ddq.head<3>(); // body spatial acceleration in body plucker frame - - Vector3d w_v_wb = oTb.rotation() * b_v_b; // gtr - - //////////////////////////////////// - //////////////////////////////////// - // Get measurements - - // IMU readings - // We use every quantity (spatial acc, body angvel, dr=lin spatial linvel) in the same body frame -> we get acc in body frame - Vector3d b_acc = b_asp_b + b_w_b.cross(b_v_b); - // universe o frame in mcapi/pinocchio is supposed to have same reference point and orientation as WOLF world frame - Vector3d b_proper_acc = b_acc - oTb.rotation().transpose() * gravity(); // meas - - // update and retrieve kinematics - forwardKinematics(model, data, q); - updateFramePlacements(model, data); - - // compute all linear jacobians (only for quadruped) - MatrixXd Jlinvel_all(12, model.nv); Jlinvel_all.setZero(); - for (int i_ee=0; i_ee < nbc; i_ee++){ - MatrixXd Jee(6, model.nv); Jee.setZero(); - computeFrameJacobian(model, data, q, ee_ids[i_ee], Jee); - Jlinvel_all.block(3*i_ee, 0, 3, model.nv) = Jee.topRows<3>(); - } - // remove free flyer (not needed for force reconstruction) - MatrixXd Jlinvel_noff = Jlinvel_all.rightCols(model.nv-6); - - // estimate forces from torques - VectorXd tau_cf = rnea(model, data, q, dq, ddq); // compute total torques applied on the joints (and free flyer) - VectorXd tau_joints = tau_cf.tail(model.nv-6) - tau; // remove measured joint torque (not on the free flyer) - VectorXd forces = Jlinvel_noff.transpose().lu().solve(tau_joints); - - for (unsigned int i_ee=0; i_ee < nbc; i_ee++){ - auto oTl = data.oMf[ee_ids[i_ee]]; - auto bTl = oTb.inverse() * oTl; - Vector3d b_p_l = bTl.translation(); // meas - Vector4d b_qvec_l = Quaterniond(bTl.rotation()).coeffs(); // meas - p_bl_meas_v[i_ee].push_back(b_p_l); - q_bl_meas_v[i_ee].push_back(b_qvec_l); - // TODO: Only for 6D wrench or 3D force - - // Compute either from torques or from given force and compare - // std::cout << forces.segment(3*i_ee, 3).transpose() - cforce_traj_arr_lst[i_ee][i].transpose() << std::endl; - // wrench_meas_v[i_ee].push_back(cforce_traj_arr_lst[i_ee][i]); - wrench_meas_v[i_ee].push_back(forces.segment(3*i_ee, 3)); - } - - - ////////////////////////////////////////////// - // COM relative position and velocity measures - VectorXd q_static = q; - VectorXd dq_static = dq; - q_static.head<7>() << 0,0,0, 0,0,0,1; - dq_static.head<6>() << 0,0,0, 0,0,0; - // compute for both perfect and distorted models to get the bias - centerOfMass(model, data, q_static, dq_static); - centerOfMass(model_dist, data_dist, q_static, dq_static); - - // c =def w_p_wc - // Vector3d b_p_bc = oTb.inverse().act(c); // meas - Vector3d b_p_bc = data.com[0]; // meas - Vector3d b_p_bc_dist = data_dist.com[0]; // meas - Vector3d bias_pbc = b_p_bc_dist - b_p_bc; - - // velocity due to to gesticulation only in base frame - // -> set world frame = base frame and set body frame spatial vel to zero - Vector3d b_v_bc = data.vcom[0]; // meas - Vector3d b_v_bc_dist = data_dist.vcom[0]; // meas - Vector3d bias_vbc = b_v_bc_dist - b_v_bc; - - ///////////////////////// - // Centroidal inertia and gesticulation kinetic momentum - Matrix3d b_Iw = compute_Iw(model, data, q_static, b_p_bc); - Matrix3d b_Iw_dist = compute_Iw(model_dist, data_dist, q_static, b_p_bc_dist); - Matrix3d bias_Iw = b_Iw_dist - b_Iw; - - // gesticulation in base frame: just compute centroidal momentum with static q and vq - Vector3d b_Lc_gesti = computeCentroidalMomentum(model, data, q_static, dq_static).angular(); - Vector3d b_Lc_gesti_dist = computeCentroidalMomentum(model_dist, data_dist, q_static, dq_static).angular(); - Vector3d bias_Lc = b_Lc_gesti_dist - b_Lc_gesti; - - - // std::cout << "bias_pbc: " << bias_pbc.transpose() << std::endl; - // std::cout << "bias_vbc: " << bias_vbc.transpose() << std::endl; - // std::cout << "bias_Iw: \n" << bias_Iw << std::endl; - // std::cout << "bias_Lc: " << bias_Lc.transpose() << std::endl; - - ///////////////////////// - // Agreggate everything in vectors for easier WOLF consumption - p_ob_gtr_v.push_back(p_wb); - q_ob_gtr_v.push_back(quat_wb); - v_ob_gtr_v.push_back(w_v_wb); - bp_traj_arr.push_back(bias_pbc); - // Lc_gtr_v; - - // Measurements - acc_b_meas_v.push_back(b_proper_acc); - w_b_meas_v.push_back(b_w_b); - p_bc_meas_v.push_back(b_p_bc_dist); - if (vbc_is_dist){ - v_bc_meas_v.push_back(b_v_bc_dist); - } - else { - v_bc_meas_v.push_back(b_v_bc); - } - if (Lgest_is_dist){ - Lq_meas_v.push_back(b_Lc_gesti_dist); - } - else{ - Lq_meas_v.push_back(b_Lc_gesti); - } - if (Iw_is_dist){ - Iq_meas_v.push_back(b_Iw_dist); - } - else { - Iq_meas_v.push_back(b_Iw); - } - } - - ///////////////////////// - // WOLF enters the scene - // SETUP PROBLEM/SENSORS/PROCESSORS - std::string bodydynamics_root_dir = _WOLF_BODYDYNAMICS_ROOT_DIR; - - ProblemPtr problem = Problem::create("POV", 3); - - // CERES WRAPPER - SolverCeresPtr solver = std::make_shared<SolverCeres>(problem); - - // 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.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_mcapi_demo.yaml"); - ProcessorImuPtr proc_imu = std::static_pointer_cast<ProcessorImu>(proc_ftp_base); - - // SENSOR + PROCESSOR ODOM3D FOR LEG ODOMETRY - Vector7d extr_senlegodom; extr_senlegodom << 0,0,0, 0,0,0,1; // not used in practice - SensorBasePtr sen_odom3d_base = problem->installSensor("SensorOdom3d", "SenLegOdom", extr_senlegodom, bodydynamics_root_dir + "/demos/sensor_odom_3d.yaml"); - SensorOdom3dPtr sen_odom3d = std::static_pointer_cast<SensorOdom3d>(sen_odom3d_base); - ParamsProcessorOdom3dPtr params_sen_odom3d = std::make_shared<ParamsProcessorOdom3d>(); - // ProcessorBasePtr proc_legodom_base = problem->installProcessor("ProcessorOdom3d", "ProcLegOdom", sen_odom3d, params_sen_odom3d); - ProcessorBasePtr proc_legodom_base = problem->installProcessor("ProcessorOdom3d", "ProcLegOdom", "SenLegOdom", bodydynamics_root_dir + "/demos/processor_odom_3d.yaml"); - ProcessorOdom3dPtr proc_legodom = std::static_pointer_cast<ProcessorOdom3d>(proc_legodom_base); - ////////////////////////////// - - TimeStamp t0(t_arr[0]); - VectorComposite x_origin("POV", {p_ob_gtr_v[0], q_ob_gtr_v[0], v_ob_gtr_v[0]}); - 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); - - proc_imu->setOrigin(KF1); - proc_legodom->setOrigin(KF1); - - - /////////////////////////////////////////// - // process measurements in sequential order - double ts_since_last_kf = 0; - - // Add gaussian noises - std::time_t epoch = std::time(nullptr); - int64_t seed = (int64_t)epoch; - Eigen::EigenMultivariateNormal<double> noise_acc(Vector3d::Zero(), pow(std_acc_sim, 2)*Matrix3d::Identity(), false, seed); - Eigen::EigenMultivariateNormal<double> noise_gyr(Vector3d::Zero(), pow(std_gyr_sim, 2)*Matrix3d::Identity(), false, seed); - - ////////////////////////////////////////// - // 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; - ////////////////////////////////////////// - - unsigned int nb_kf = problem->getTrajectory()->getFrameMap().size(); - for (unsigned int i=0; i < t_arr.size(); i++){ - // TimeStamp ts(t_arr[i]+dt); // works best with tsid trajectories - TimeStamp ts(t_arr[i]); // works best with pyb trajectories - - // IMU - Vector6d acc_gyr_meas; acc_gyr_meas << acc_b_meas_v[i], w_b_meas_v[i]; - - if (noisy_measurements){ - acc_gyr_meas.head<3>() += noise_acc.samples(1); - acc_gyr_meas.tail<3>() += noise_gyr.samples(1); - } - - Matrix6d acc_gyr_cov = sen_imu->getNoiseCov(); - - //////////////////// - ///////////////// - - CaptureImuPtr CImu = std::make_shared<CaptureImu>(ts, sen_imu, acc_gyr_meas, acc_gyr_cov); - CImu->process(); - - - if (i > 0){ - // Leg odometry - // 1) detect feet in contact - std::vector<int> feet_int_contact; - for (unsigned int i_ee=0; i_ee<nbc; i_ee++){ - // basic contact detection based on normal foot vel, things break if no foot is in contact - // std::cout << "F" << ee_names[i_ee] << " norm: " << wrench_meas_v[i_ee][i].norm() << std::endl; - if (wrench_meas_v[i_ee][i].norm() > fz_thresh){ - feet_int_contact.push_back(i_ee); - } - } - // 2) fill the leg odometry data matrix, depending on the contact dimension - Eigen::MatrixXd data_legodom; - if (dimc == 6){ - // cols organized as: - // [pbl1_km; qbl1_k], [pbl2_km; qbl2_k], ... - data_legodom.resize(7,feet_int_contact.size()*2); - data_legodom.setZero(); - int j = 0; - for (int i_ee_c: feet_int_contact){ - data_legodom.col(2*j ) << p_bl_meas_v[i_ee_c][i-1], q_bl_meas_v[i_ee_c][i-1]; - data_legodom.col(2*j+1) << p_bl_meas_v[i_ee_c][i ], q_bl_meas_v[i_ee_c][i]; - j++; - } - } - else if (dimc == 3){ - // cols organized as: - // pbl1_km, pbl1_k, pbl2_km, pbl2_k, ..., w_b - data_legodom.resize(3,feet_int_contact.size()*2 + 1); - data_legodom.setZero(); - int j = 0; - for (int i_ee_c: feet_int_contact){ - data_legodom.col(2*j ) << p_bl_meas_v[i_ee_c][i-1]; - data_legodom.col(2*j+1) << p_bl_meas_v[i_ee_c][i ]; - j++; - } - data_legodom.rightCols<1>() = acc_gyr_meas.tail<3>(); - } - // std::cout << "data_legodom\n" << data_legodom << std::endl; - // 3) process the data and its cov - Eigen::Matrix6d data_legodom3D_cov = pow(std_odom3d_est, 2) * Eigen::Matrix6d::Identity(); - CaptureLegOdomPtr CLO = std::make_shared<CaptureLegOdom>(ts, sen_odom3d, data_legodom, data_legodom3D_cov, dt, CaptureLegOdomType::POINT_FEET_RELATIVE_KIN); - CLO->process(); - } - - // if new KF add - // unsigned int new_kf_nb = problem->getTrajectory()->getFrameMap().size(); - // if (new_kf_nb > nb_kf){ - // auto last_kf = problem->getTrajectory()->getFrameMap().rbegin()->second; - // nb_kf = new_kf_nb; - // // ADD ABSOLUTE FACTOR (GPS LIKE) - // } - - - ts_since_last_kf += dt; - if ((solve_every_sec > 0) && (ts_since_last_kf >= solve_every_sec)){ - // problem->print(4,true,true,true); - std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); - std::cout << report << std::endl; - ts_since_last_kf = 0; - } - - // Store current state estimation - VectorComposite curr_state = problem->getState(ts); - p_ob_fbk_v.push_back(curr_state['P']); - q_ob_fbk_v.push_back(curr_state['O']); - v_ob_fbk_v.push_back(curr_state['V']); - - } - - //////////////////////////////////////////// - // 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); - - - /////////////////////////////////////////// - //////////////// SOLVING ////////////////// - /////////////////////////////////////////// - problem->print(4,true,true,true); - if (solve_end){ - std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); - problem->print(4,true,true,true); - std::cout << report << std::endl; - } - - ////////////////////////////////////// - ////////////////////////////////////// - // STORE DATA // - ////////////////////////////////////// - ////////////////////////////////////// - std::fstream file_gtr; - std::fstream file_est; - std::fstream file_fbk; - std::fstream file_kfs; - std::fstream file_cov; - file_gtr.open("/home/mfourmy/Documents/Phd_LAAS/phd_misc/centroidalkin/gtr.csv", std::fstream::out); - file_est.open("/home/mfourmy/Documents/Phd_LAAS/phd_misc/centroidalkin/est.csv", std::fstream::out); - file_fbk.open("/home/mfourmy/Documents/Phd_LAAS/phd_misc/centroidalkin/fbk.csv", std::fstream::out); - file_kfs.open("/home/mfourmy/Documents/Phd_LAAS/phd_misc/centroidalkin/kfs.csv", std::fstream::out); - file_cov.open("/home/mfourmy/Documents/Phd_LAAS/phd_misc/centroidalkin/cov.csv", std::fstream::out); - std::string header_est = "t,px,py,pz,qx,qy,qz,qw,vx,vy,vz\n"; - file_est << header_est; - file_fbk << header_est; - std::string header_kfs = "t,px,py,pz,qx,qy,qz,qw,vx,vy,vz,bax,bay,baz,bwx,bwy,bwz\n"; - file_kfs << header_kfs; - file_gtr << header_kfs; - std::string header_cov = "t,Qpx,Qpy,Qpz,Qqx,Qqy,Qqz,Qvx,Qvy,Qvz,Qbax,Qbay,Qbaz,Qbwx,Qbwy,Qbwz\n"; - file_cov << header_cov; - - VectorComposite state_est; - for (unsigned int i=0; i < t_arr.size(); i++) { - file_gtr << std::setprecision(std::numeric_limits<long double>::digits10 + 1) - << t_arr[i] << "," - << p_ob_gtr_v[i](0) << "," - << p_ob_gtr_v[i](1) << "," - << p_ob_gtr_v[i](2) << "," - << q_ob_gtr_v[i](0) << "," - << q_ob_gtr_v[i](1) << "," - << q_ob_gtr_v[i](2) << "," - << q_ob_gtr_v[i](3) << "," - << v_ob_gtr_v[i](0) << "," - << v_ob_gtr_v[i](1) << "," - << v_ob_gtr_v[i](2) - << "\n"; - } - - for (unsigned int i=0; i < t_arr.size(); i++) { - state_est = problem->getState(t_arr[i]); - file_est << std::setprecision(std::numeric_limits<long double>::digits10 + 1) - << t_arr[i] << "," - << state_est['P'](0) << "," - << state_est['P'](1) << "," - << state_est['P'](2) << "," - << state_est['O'](0) << "," - << state_est['O'](1) << "," - << state_est['O'](2) << "," - << state_est['O'](3) << "," - << state_est['V'](0) << "," - << state_est['V'](1) << "," - << state_est['V'](2) - << "\n"; - } - - for (unsigned int i=0; i < t_arr.size(); i++) { - file_fbk << std::setprecision(std::numeric_limits<long double>::digits10 + 1) - << t_arr[i] << "," - << p_ob_fbk_v[i](0) << "," - << p_ob_fbk_v[i](1) << "," - << p_ob_fbk_v[i](2) << "," - << q_ob_fbk_v[i](0) << "," - << q_ob_fbk_v[i](1) << "," - << q_ob_fbk_v[i](2) << "," - << q_ob_fbk_v[i](3) << "," - << v_ob_fbk_v[i](0) << "," - << v_ob_fbk_v[i](1) << "," - << v_ob_fbk_v[i](2) - << "\n"; - } - - VectorComposite kf_state; - CaptureBasePtr cap_imu; - VectorComposite bi_bias_est; - for (auto& elt: problem->getTrajectory()->getFrameMap()){ - auto kf = elt.second; - kf_state = kf->getState(); - cap_imu = kf->getCaptureOf(sen_imu); - bi_bias_est = cap_imu->getState(); - - file_kfs << std::setprecision(std::numeric_limits<long double>::digits10 + 1) - << kf->getTimeStamp().get() << "," - << kf_state['P'](0) << "," - << kf_state['P'](1) << "," - << kf_state['P'](2) << "," - << kf_state['O'](0) << "," - << kf_state['O'](1) << "," - << kf_state['O'](2) << "," - << kf_state['O'](3) << "," - << kf_state['V'](0) << "," - << kf_state['V'](1) << "," - << kf_state['V'](2) << "," - << bi_bias_est['I'](0) << "," - << bi_bias_est['I'](1) << "," - << bi_bias_est['I'](2) << "," - << bi_bias_est['I'](3) << "," - << bi_bias_est['I'](4) << "," - << bi_bias_est['I'](5) - << "\n"; - - // 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(); - - 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); - - solver->computeCovariances(cap_imu->getStateBlockVec()); // not computed by ALL and destroys other computed covs -> issue to raise - problem->getCovarianceBlock(cap_imu->getSensorIntrinsic(), Qbi); - - file_cov << std::setprecision(std::numeric_limits<long double>::digits10 + 1) - << kf->getTimeStamp().get() << "," - << Qp(0,0) << "," - << Qp(1,1) << "," - << Qp(2,2) << "," - << Qo(0,0) << "," - << Qo(1,1) << "," - << Qo(2,2) << "," - << Qv(0,0) << "," - << Qv(1,1) << "," - << Qv(2,2) << "," - << Qbi(0,0) << "," - << Qbi(1,1) << "," - << Qbi(2,2) << "," - << Qbi(3,3) << "," - << Qbi(4,4) << "," - << Qbi(5,5) - << "\n"; - } - - file_gtr.close(); - file_est.close(); - file_fbk.close(); - file_kfs.close(); - file_cov.close(); - - - // // Print factor energy - // for (auto kf: problem->getTrajectory()->getFrameMap()){ - // for (auto cap: kf->getCaptureList()){ - // for (auto feat: cap->getFeatureList()){ - // for (auto fac: feat->getFactorList()){ - // if (fac->getType() == "FactorForceTorquePreint"){ - // std::cout << "Type: FactorForceTorquePreint" << std::endl; - // auto fac_ftp = std::static_pointer_cast<FactorForceTorquePreint>(fac); - // std::cout << "try the cost" << std::endl; - // std::cout << fac_ftp->cost() << std::endl; - // } - // } - // } - // } - // } - - -} diff --git a/demos/mcapi_povcdl_estimation.cpp b/demos/mcapi_povcdl_estimation.cpp deleted file mode 100644 index 82bf7d64e2c9779a17a590fc7b9a6cf2b58cded1..0000000000000000000000000000000000000000 --- a/demos/mcapi_povcdl_estimation.cpp +++ /dev/null @@ -1,969 +0,0 @@ -//--------LICENSE_START-------- -// -// Copyright (C) 2020,2021,2022 Institut de Robòtica i Informà tica Industrial, CSIC-UPC. -// Authors: Joan Solà Ortega (jsola@iri.upc.edu) -// All rights reserved. -// -// This file is part of WOLF -// WOLF is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// -//--------LICENSE_END-------- -#include <iostream> -// #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" - -// MCAPI -#include <curves/fwd.h> -#include <curves/so3_linear.h> -#include <curves/se3_curve.h> -#include <curves/polynomial.h> -#include <curves/bezier_curve.h> -#include <curves/piecewise_curve.h> -#include <curves/exact_cubic.h> -#include <curves/cubic_hermite_spline.h> -#include "multicontact-api/scenario/contact-sequence.hpp" - -// 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_block_absolute.h> -#include <core/processor/processor_odom_3d.h> -#include <core/sensor/sensor_odom_3d.h> - -// IMU -#include "imu/sensor/sensor_imu.h" -#include "imu/capture/capture_imu.h" -#include "imu/processor/processor_imu.h" - -// BODYDYNAMICS -#include "bodydynamics/internal/config.h" -#include "bodydynamics/sensor/sensor_inertial_kinematics.h" -#include "bodydynamics/sensor/sensor_force_torque.h" -#include "bodydynamics/capture/capture_inertial_kinematics.h" -#include "bodydynamics/capture/capture_force_torque_preint.h" -#include "bodydynamics/capture/capture_leg_odom.h" -#include "bodydynamics/processor/processor_inertial_kinematics.h" -#include "bodydynamics/processor/processor_force_torque_preint.h" -#include "bodydynamics/factor/factor_inertial_kinematics.h" -#include "bodydynamics/factor/factor_force_torque_preint.h" - - -// UTILS -#include "mcapi_utils.h" - - -using namespace Eigen; -using namespace wolf; -using namespace pinocchio; -using namespace multicontact_api::scenario; - -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/mcapi_povcdl_estimation.yaml"); - std::string robot_urdf = config["robot_urdf"].as<std::string>(); - int dimc = config["dimc"].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>(); - bool noisy_measurements = config["noisy_measurements"].as<bool>(); - - // 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>(); - - // simulated sensor noises - double std_acc_sim = config["std_acc_sim"].as<double>(); - double std_gyr_sim = config["std_gyr_sim"].as<double>(); - double std_pbc_sim = config["std_pbc_sim"].as<double>(); - double std_vbc_sim = config["std_vbc_sim"].as<double>(); - double std_f_sim = config["std_f_sim"].as<double>(); - double std_tau_sim = config["std_tau_sim"].as<double>(); - // double std_odom3d_sim = config["std_odom3d_sim"].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_pbc_prior_vec = config["bias_pbc_prior"].as<std::vector<double>>(); - Eigen::Map<Vector3d> bias_pbc_prior(bias_pbc_prior_vec.data()); - 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()); - - double fz_thresh = config["fz_thresh"].as<double>(); - double scale_dist = config["scale_dist"].as<double>(); - bool base_dist_only = config["base_dist_only"].as<bool>(); - bool mass_dist = config["mass_dist"].as<bool>(); - bool vbc_is_dist = config["vbc_is_dist"].as<bool>(); - bool Iw_is_dist = config["Iw_is_dist"].as<bool>(); - bool Lgest_is_dist = config["Lgest_is_dist"].as<bool>(); - - std::string contact_sequence_file = config["contact_sequence_file"].as<std::string>(); - - ContactSequence cs; - std::cout << "Loading file " << contact_sequence_file << std::endl; - cs.loadFromBinary(contact_sequence_file); - - auto q_traj = cs.concatenateQtrajectories(); - auto dq_traj = cs.concatenateDQtrajectories(); - auto ddq_traj = cs.concatenateDDQtrajectories(); - auto c_traj = cs.concatenateCtrajectories(); - auto dc_traj = cs.concatenateDCtrajectories(); - auto L_traj = cs.concatenateLtrajectories(); - auto tau_traj = cs.concatenateTauTrajectories(); - std::vector<std::string> ee_names = cs.getAllEffectorsInContact(); - unsigned int nbc = ee_names.size(); - std::vector<curves::piecewise_t> cforce_traj_lst; - for (auto ee_name: ee_names){ - std::cout << ee_name << std::endl; - auto cforce_traj = cs.concatenateContactForceTrajectories(ee_name); - cforce_traj_lst.push_back(cforce_traj); - } - - if (min_t < 0){ - min_t = q_traj.min(); - } - if (max_t < 0){ - max_t = q_traj.max(); - } - - // initialize some vectors and fill them with dicretized data - std::vector<double> t_arr; // timestamps - std::vector<VectorXd> q_traj_arr; // [p_ob, q_ob, qA] - std::vector<VectorXd> dq_traj_arr; // [spvel_b, qA_dot] - std::vector<VectorXd> ddq_traj_arr; // [spacc_b, qA_ddot] - std::vector<VectorXd> c_traj_arr; // w_p_wc - std::vector<VectorXd> dc_traj_arr; // w_v_wc - std::vector<VectorXd> L_traj_arr; // w_Lc: angular momentum at the CoM expressed in CoM (=World) frame - std::vector<VectorXd> tau_traj_arr; // w_Lc: angular momentum at the CoM expressed in CoM (=World) frame - std::vector<VectorXd> bp_traj_arr; // bias on b_p_bc: bias on the CoM position expressed in base frame - std::vector<std::vector<VectorXd>> cforce_traj_arr_lst(nbc); - int N = (max_t - min_t)/dt; - int i_t = 0; - for (double t=min_t; t <= max_t; t += dt){ - t_arr.push_back(t); - q_traj_arr.push_back(q_traj(t)); - dq_traj_arr.push_back(dq_traj(t)); - ddq_traj_arr.push_back(ddq_traj(t)); - c_traj_arr.push_back(c_traj(t)); - dc_traj_arr.push_back(dc_traj(t)); - L_traj_arr.push_back(L_traj(t)); - tau_traj_arr.push_back(tau_traj(t)); - for (unsigned int i_ee=0; i_ee < nbc; i_ee++){ - cforce_traj_arr_lst[i_ee].push_back(cforce_traj_lst[i_ee](t)); - } - i_t++; - } - std::cout << "Trajectory extracted, proceed to create sensor data" << std::endl; - - // Creating measurements from simulated trajectory - // Load the urdf model - Model model; - pinocchio::urdf::buildModel(robot_urdf, JointModelFreeFlyer(), model); - std::cout << "model name: " << model.name << std::endl; - Data data(model); - - // distorted model (modified inertias) - Model model_dist; - pinocchio::urdf::buildModel(robot_urdf, JointModelFreeFlyer(), model_dist); - Eigen::EigenMultivariateNormal<double> noise_mass = Eigen::EigenMultivariateNormal<double>(Vector1d::Zero(), Matrix1d::Identity(), false); - Eigen::EigenMultivariateNormal<double> noise_lever = Eigen::EigenMultivariateNormal<double>(Vector3d::Zero(), Matrix3d::Identity(), false); - if (base_dist_only){ - if (!mass_dist){ - int root_joint_id = model.getJointId("root_joint"); - Vector3d lever_dist = model.inertias[root_joint_id].lever() + scale_dist * noise_lever.samples(1); - model_dist.inertias[root_joint_id] = pinocchio::Inertia(model.inertias[root_joint_id].mass(), lever_dist, model.inertias[root_joint_id].inertia()); - } - } - else{ - for (int i=0; i < model_dist.inertias.size(); i++){ - if (mass_dist){ - double mass_dist = model.inertias[i].mass() + scale_dist * model.inertias[i].mass() * noise_mass.samples(1)(0,0); - model_dist.inertias[i] = pinocchio::Inertia(mass_dist, model.inertias[i].lever(), model.inertias[i].inertia()); - std::cout << "mass model " << model.inertias[i].mass() << std::endl; - std::cout << "mass model_dist " << model_dist.inertias[i].mass() << std::endl; - } - else { - Vector3d lever_dist = model.inertias[i].lever() + scale_dist * noise_lever.samples(1); - model_dist.inertias[i] = pinocchio::Inertia(model.inertias[i].mass(), lever_dist, model.inertias[i].inertia()); - } - } - } - Data data_dist(model_dist); - - // Recover end effector frame ids - std::vector<int> ee_ids; - std::cout << "Frame ids" << std::endl; - for (auto ee_name: ee_names){ - ee_ids.push_back(model.getFrameId(ee_name)); - std::cout << ee_name << std::endl; - } - // std::vector<Vector3d> contacts = contacts_from_footrect_center(); // for Humanoid only TODO - - - /////////////////////////////////////////////// - // Create some vectors to aggregate the groundtruth and measurements - // Groundtruth - std::vector<Vector3d> p_ob_gtr_v; - std::vector<Vector4d> q_ob_gtr_v; - std::vector<Vector3d> v_ob_gtr_v; - // std::vector<VectorXd>& c_gtr_v = c_traj_arr; // already have it directly - // std::vector<VectorXd>& cd_gtr_v = dc_traj_arr; // already have it directly - // std::vector<Vector3d> L_traj_arr; // already have it directly - - // Measurements - std::vector<Vector3d> acc_b_meas_v; - std::vector<Vector3d> w_b_meas_v; - std::vector<std::vector<Vector3d>> p_bl_meas_v(nbc); - std::vector<std::vector<Vector4d>> q_bl_meas_v(nbc); - std::vector<std::vector<VectorXd>> wrench_meas_v(nbc); - std::vector<Vector3d> p_bc_meas_v; - std::vector<Vector3d> v_bc_meas_v; - std::vector<Vector3d> Lq_meas_v; - std::vector<Matrix3d> Iq_meas_v; - // define vectors to aggregate ground truth and simulated data - for (unsigned int i = 0; i < q_traj_arr.size(); i++) - { - /** - * Groundtruth to recover (in world frame, vels/inertial frame): - * b position --> OK - * b orientation (quat) --> OK - * b velocity: linear classical one --> OK - * CoM posi --> OK - * CoM vel --> OK - * Angular momentum --> OK - * - * Measures to recover (in local frames): - * IMU readings --> OK - * Kinematics readings --> OK - * Wrench readings --> OK - * CoM relative position/vel --> OK - * Iq, Lq --> OK - * - **/ - - // retrieve traj data - VectorXd q = q_traj_arr[i]; - VectorXd dq = dq_traj_arr[i]; - VectorXd ddq = ddq_traj_arr[i]; - // Vector3d c = c_traj_arr[i]; // gtr - // VectorXd dc = dc_traj_arr[i]; // gtr - // VectorXd L = L_traj_arr[i]; // gtr - VectorXd tau = tau_traj_arr[i]; - - // std::cout << "q " << q.transpose() << std::endl; - // std::cout << "dq " << dq.transpose() << std::endl; - // std::cout << "ddq " << ddq.transpose() << std::endl; - - ////////////////////////////////// - ////////////////////////////////// - // Set ground truth variables - Vector3d p_wb = q.head<3>(); // gtr - Vector4d quat_wb = q.segment<4>(3); // gtr - SE3 oTb(Quaterniond(quat_wb).toRotationMatrix(), p_wb); // global frame pose - // body vel is expressed in body frame - Vector3d b_v_b = dq.head<3>(); // vsp: spatial linear velocity - Vector3d b_w_b = dq.segment<3>(3); // meas - Vector3d b_asp_b = ddq.head<3>(); // body spatial acceleration in body plucker frame - - Vector3d w_v_wb = oTb.rotation() * b_v_b; // gtr - - //////////////////////////////////// - //////////////////////////////////// - // Get measurements - - // IMU readings - // We use every quantity (spatial acc, body angvel, dr=lin spatial linvel) in the same body frame -> we get acc in body frame - Vector3d b_acc = b_asp_b + b_w_b.cross(b_v_b); - // universe o frame in mcapi/pinocchio is supposed to have same reference point and orientation as WOLF world frame - Vector3d b_proper_acc = b_acc - oTb.rotation().transpose() * gravity(); // meas - - // update and retrieve kinematics - forwardKinematics(model, data, q); - updateFramePlacements(model, data); - - // compute all linear jacobians (only for quadruped) - MatrixXd Jlinvel(12, model.nv); Jlinvel.setZero(); - for (int i_ee=0; i_ee < nbc; i_ee++){ - MatrixXd Jee(6, model.nv); Jee.setZero(); - computeFrameJacobian(model, data, q, ee_ids[i_ee], Jee); - Jlinvel.block(3*i_ee, 0, 3, model.nv) = Jee.topRows<3>(); - } - - // estimate forces from torques - VectorXd tau_cf = rnea(model, data, q, dq, ddq); // compute total torques applied on the joints (and free flyer) - tau_cf.tail(model.nv-6) -= tau; // remove measured joint torque (not on the free flyer) - - // VectorXd forces = Jlinvel_reduced.transpose().lu().solve(tau_joints); // works only for exactly determined system, removing free flyer from the system -> 12x12 J mat - // Solve in Least square sense (3 ways): - // VectorXd forces = Jlinvel.transpose().bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(tau_cf); // SVD - VectorXd forces = Jlinvel.transpose().colPivHouseholderQr().solve(tau_cf); // QR - // (A.transpose() * A).ldlt().solve(A.transpose() * b) // solve the normal equation (twice less accurate than other 2) - - Vector3d o_f_tot = Vector3d::Zero(); - std::cout << "" << std::endl; - std::cout << "t: " << t_arr[i] << std::endl; - // std::cout << "ddq: " << ddq.transpose() << std::endl; - for (unsigned int i_ee=0; i_ee < nbc; i_ee++){ - auto oTl = data.oMf[ee_ids[i_ee]]; - auto bTl = oTb.inverse() * oTl; - Vector3d b_p_l = bTl.translation(); // meas - Vector4d b_qvec_l = Quaterniond(bTl.rotation()).coeffs(); // meas - p_bl_meas_v[i_ee].push_back(b_p_l); - q_bl_meas_v[i_ee].push_back(b_qvec_l); - // TODO: Only for 6D wrench or 3D force - - // Compute either from torques or from given force and compare - std::cout << "f_force_from_tau - f_force_from_cs_file: " << forces.segment(3*i_ee, 3).transpose() - cforce_traj_arr_lst[i_ee][i].transpose() << std::endl; - - Vector3d l_f_l = forces.segment(3*i_ee, 3); - // wrench_meas_v[i_ee].push_back(cforce_traj_arr_lst[i_ee][i]); // EITHER - wrench_meas_v[i_ee].push_back(l_f_l); - - Vector3d o_f_l = oTl.rotation() * l_f_l; - // std::cout << "o_p_" << ee_names[i_ee] << " " << oTl.translation().transpose() << std::endl; - // std::cout << "o_f_" << ee_names[i_ee] << " " << o_f_l.transpose() << std::endl; - o_f_tot += o_f_l; - } - // std::cout << "o_f_tot: " << o_f_tot.transpose() << std::endl; - std::cout << "o_f_tot + m*g: " << (o_f_tot + data.mass[0]*model.gravity.linear()).transpose() << std::endl; - std::cout << "pin.gravity - wolf gravity: " << model.gravity.linear() - wolf::gravity() << std::endl; - - - ////////////////////////////////////////////// - // COM relative position and velocity measures - VectorXd q_static = q; - VectorXd dq_static = dq; - q_static.head<7>() << 0,0,0, 0,0,0,1; - dq_static.head<6>() << 0,0,0, 0,0,0; - // compute for both perfect and distorted models to get the bias - centerOfMass(model, data, q_static, dq_static); - centerOfMass(model_dist, data_dist, q_static, dq_static); - - // c =def w_p_wc - // Vector3d b_p_bc = oTb.inverse().act(c); // meas - Vector3d b_p_bc = data.com[0]; // meas - Vector3d b_p_bc_dist = data_dist.com[0]; // meas - Vector3d bias_pbc = b_p_bc_dist - b_p_bc; - - // velocity due to to gesticulation only in base frame - // -> set world frame = base frame and set body frame spatial vel to zero - Vector3d b_v_bc = data.vcom[0]; // meas - Vector3d b_v_bc_dist = data_dist.vcom[0]; // meas - Vector3d bias_vbc = b_v_bc_dist - b_v_bc; - - ///////////////////////// - // Centroidal inertia and gesticulation kinetic momentum - Matrix3d b_Iw = compute_Iw(model, data, q_static, b_p_bc); - Matrix3d b_Iw_dist = compute_Iw(model_dist, data_dist, q_static, b_p_bc_dist); - Matrix3d bias_Iw = b_Iw_dist - b_Iw; - - // gesticulation in base frame: just compute centroidal momentum with static q and vq - Vector3d b_Lc_gesti = computeCentroidalMomentum(model, data, q_static, dq_static).angular(); - Vector3d b_Lc_gesti_dist = computeCentroidalMomentum(model_dist, data_dist, q_static, dq_static).angular(); - Vector3d bias_Lc = b_Lc_gesti_dist - b_Lc_gesti; - - - // std::cout << "bias_pbc: " << bias_pbc.transpose() << std::endl; - // std::cout << "bias_vbc: " << bias_vbc.transpose() << std::endl; - // std::cout << "bias_Iw: \n" << bias_Iw << std::endl; - // std::cout << "bias_Lc: " << bias_Lc.transpose() << std::endl; - - ///////////////////////// - // Agreggate everything in vectors for easier WOLF consumption - p_ob_gtr_v.push_back(p_wb); - q_ob_gtr_v.push_back(quat_wb); - v_ob_gtr_v.push_back(w_v_wb); - bp_traj_arr.push_back(bias_pbc); - // Lc_gtr_v; - - // Measurements - acc_b_meas_v.push_back(b_proper_acc); - w_b_meas_v.push_back(b_w_b); - p_bc_meas_v.push_back(b_p_bc_dist); - if (vbc_is_dist){ - v_bc_meas_v.push_back(b_v_bc_dist); - } - else { - v_bc_meas_v.push_back(b_v_bc); - } - if (Lgest_is_dist){ - Lq_meas_v.push_back(b_Lc_gesti_dist); - } - else{ - Lq_meas_v.push_back(b_Lc_gesti); - } - if (Iw_is_dist){ - Iq_meas_v.push_back(b_Iw_dist); - } - else { - Iq_meas_v.push_back(b_Iw); - } - } - - ///////////////////////// - // WOLF enters the scene - // SETUP PROBLEM/SENSORS/PROCESSORS - std::string bodydynamics_root_dir = _WOLF_BODYDYNAMICS_ROOT_DIR; - - ProblemPtr problem = Problem::create("POVCDL", 3); - - // CERES WRAPPER - SolverCeresPtr solver = std::make_shared<SolverCeres>(problem); - - //===================================================== INITIALIZATION - // SENSOR + PROCESSOR INERTIAL KINEMATICS - ParamsSensorInertialKinematicsPtr intr_ik = std::make_shared<ParamsSensorInertialKinematics>(); - intr_ik->std_pbc = std_pbc_est; - intr_ik->std_vbc = std_vbc_est; - VectorXd extr; // default size for dynamic vector is 0-0 -> what we need - SensorBasePtr sen_ikin_base = problem->installSensor("SensorInertialKinematics", "SenIK", extr, intr_ik); - // SensorBasePtr sen_ikin_base = problem->installSensor("SensorInertialKinematics", "SenIK", extr, bodydynamics_root_dir + "/demos/sensor_inertial_kinematics.yaml"); // TODO: does not work! - SensorInertialKinematicsPtr sen_ikin = std::static_pointer_cast<SensorInertialKinematics>(sen_ikin_base); - - ParamsProcessorInertialKinematicsPtr params_ik = std::make_shared<ParamsProcessorInertialKinematics>(); - params_ik->sensor_angvel_name = "SenImu"; - params_ik->std_bp_drift = std_bp_drift; - ProcessorBasePtr proc_ikin_base = problem->installProcessor("ProcessorInertialKinematics", "PInertialKinematics", sen_ikin, params_ik); - // ProcessorBasePtr proc_ikin_base = problem->installProcessor("ProcessorInertialKinematics", "PInertialKinematics", "SenIK", bodydynamics_root_dir + "/demos/processor_inertial_kinematics.yaml"); - ProcessorInertialKinematicsPtr proc_inkin = std::static_pointer_cast<ProcessorInertialKinematics>(proc_ikin_base); - - // 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.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_mcapi_demo.yaml"); - ProcessorImuPtr proc_imu = std::static_pointer_cast<ProcessorImu>(proc_ftp_base); - - // SENSOR + PROCESSOR FT PREINT - ParamsSensorForceTorquePtr intr_ft = std::make_shared<ParamsSensorForceTorque>(); - intr_ft->std_f = std_f_est; - intr_ft->std_tau = std_tau_est; - intr_ft->mass = data.mass[0]; - std::cout << std::setprecision(std::numeric_limits<long double>::digits10 + 1) << "\n\nROBOT MASS: " << intr_ft->mass << std::endl; - SensorBasePtr sen_ft_base = problem->installSensor("SensorForceTorque", "SenFT", VectorXd(0), intr_ft); - // SensorBasePtr sen_ft_base = problem->installSensor("SensorForceTorque", "SenFT", VectorXd(0), bodydynamics_root_dir + "/demos/sensor_ft.yaml"); - SensorForceTorquePtr sen_ft = std::static_pointer_cast<SensorForceTorque>(sen_ft_base); - ParamsProcessorForceTorquePreintPtr params_sen_ft = std::make_shared<ParamsProcessorForceTorquePreint>(); - params_sen_ft->sensor_ikin_name = "SenIK"; - params_sen_ft->sensor_angvel_name = "SenImu"; - params_sen_ft->nbc = nbc; - params_sen_ft->dimc = dimc; - params_sen_ft->time_tolerance = 0.0005; - params_sen_ft->unmeasured_perturbation_std = 0.000001; - params_sen_ft->max_time_span = 1000; - params_sen_ft->max_buff_length = 500; - params_sen_ft->dist_traveled = 20000.0; - params_sen_ft->angle_turned = 1000; - params_sen_ft->voting_active = false; - ProcessorBasePtr proc_ft_base = problem->installProcessor("ProcessorForceTorquePreint", "PFTPreint", sen_ft, params_sen_ft); - // ProcessorBasePtr proc_ft_base = problem->installProcessor("ProcessorForceTorquePreint", "PFTPreint", "SenFT", bodydynamics_root_dir + "/demos/processor_ft_preint"); - ProcessorForceTorquePreintPtr proc_ftpreint = std::static_pointer_cast<ProcessorForceTorquePreint>(proc_ft_base); - - // SENSOR + PROCESSOR ODOM3D FOR LEG ODOMETRY - Vector7d extr_senlegodom; extr_senlegodom << 0,0,0, 0,0,0,1; // not used in practice - SensorBasePtr sen_odom3d_base = problem->installSensor("SensorOdom3d", "SenLegOdom", extr_senlegodom, bodydynamics_root_dir + "/demos/sensor_odom_3d.yaml"); - SensorOdom3dPtr sen_odom3d = std::static_pointer_cast<SensorOdom3d>(sen_odom3d_base); - ParamsProcessorOdom3dPtr params_sen_odom3d = std::make_shared<ParamsProcessorOdom3d>(); - // ProcessorBasePtr proc_legodom_base = problem->installProcessor("ProcessorOdom3d", "ProcLegOdom", sen_odom3d, params_sen_odom3d); - ProcessorBasePtr proc_legodom_base = problem->installProcessor("ProcessorOdom3d", "ProcLegOdom", "SenLegOdom", bodydynamics_root_dir + "/demos/processor_odom_3d.yaml"); - ProcessorOdom3dPtr proc_legodom = std::static_pointer_cast<ProcessorOdom3d>(proc_legodom_base); - ////////////////////////////// - - - // SETPRIOR RETRO-ENGINEERING - // We are not using setPrior because of processors initial captures problems so we have to - // - Manually create the first KF and its pose and velocity priors - // - call setOrigin on processors MotionProvider since the flag prior_is_set is not true when doing installProcessor (later) - TimeStamp t0(t_arr[0]); - VectorXd x_origin; x_origin.resize(19); - x_origin << p_ob_gtr_v[0], q_ob_gtr_v[0], v_ob_gtr_v[0], c_traj_arr[0], dc_traj_arr[0], L_traj_arr[0]; - MatrixXd P_origin(9,9); P_origin.setIdentity(); - P_origin.block<3,3>(0,0) = pow(std_prior_p, 2) * Matrix3d::Identity(); - P_origin.block<3,3>(3,3) = pow(std_prior_o, 2) * Matrix3d::Identity(); - P_origin.block<3,3>(6,6) = pow(std_prior_v, 2) * Matrix3d::Identity(); - FrameBasePtr KF1 = problem->emplaceFrame(t0, x_origin); - // Prior pose factor - CapturePosePtr pose_prior_capture = CaptureBase::emplace<CapturePose>(KF1, t0, nullptr, x_origin.head(7), P_origin.topLeftCorner(6, 6)); - pose_prior_capture->emplaceFeatureAndFactor(); - // Prior velocity factor - CaptureBasePtr capV0 = CaptureBase::emplace<CaptureBase>(KF1, "Vel0", t0); - FeatureBasePtr featV0 = FeatureBase::emplace<FeatureBase>(capV0, "Vel0", x_origin.segment<3>(7), P_origin.block<3, 3>(6, 6)); - FactorBasePtr facV0 = FactorBase::emplace<FactorBlockAbsolute>(featV0, featV0, KF1->getV(), nullptr, false); - - // Special trick to make things work in the IMU + IKin + FTPreint case - // 0. Call keyFrameCallback of processorIKin so that its kf_buffer contains the first KF0 - // 1. Call setOrigin processorIMU to generate a fake captureIMU -> generates b_imu - // 2. process one IKin capture corresponding to the same KF, the factor needing b_imu -> generates a b_pbc - // 3. set processorForceTorquePreint origin which requires both b_imu and b_pbc - proc_inkin->keyFrameCallback(KF1, 0.0005); - proc_imu->setOrigin(KF1); - proc_legodom->setOrigin(KF1); - - // INERTIAL KINEMATICS CAPTURE DATA ZERO MOTION - // momentum parameters - Matrix<double, 9, 1> meas_ikin; meas_ikin << p_bc_meas_v[0], v_bc_meas_v[0], w_b_meas_v[0]; - auto CIKin0 = std::make_shared<CaptureInertialKinematics>(t0, sen_ikin, meas_ikin, Iq_meas_v[0], Lq_meas_v[0]); - CIKin0->process(); - proc_ftpreint->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); - - // Add loose absolute factor on initial bp bias since dynamical trajectories - Matrix3d Q_bp = pow(std_abs_bias_pbc, 2)* Matrix3d::Identity(); - CaptureBasePtr cap_bp0 = CaptureBase::emplace<CaptureBase>(KF1, "bp0", t0); - FeatureBasePtr feat_bp0 = FeatureBase::emplace<FeatureBase>(cap_bp0, "bp0", bias_pbc_prior, Q_bp); - FactorBasePtr fac_bp0 = FactorBase::emplace<FactorBlockAbsolute>(feat_bp0, feat_bp0, KF1->getCaptureOf(sen_ikin)->getSensorIntrinsic(), nullptr, false); - - - /////////////////////////////////////////// - // process measurements in sequential order - // SE3 oTb_prev(Quaterniond(q_ob_gtr_v[0]).toRotationMatrix(), p_ob_gtr_v[0]); - // FrameBasePtr KF_prev = KF1; - double ts_since_last_kf = 0; - - // Add gaussian noises - std::time_t epoch = std::time(nullptr); - int64_t seed = (int64_t)epoch; - Eigen::EigenMultivariateNormal<double> noise_acc(Vector3d::Zero(), pow(std_acc_sim, 2)*Matrix3d::Identity(), false, seed); - Eigen::EigenMultivariateNormal<double> noise_gyr(Vector3d::Zero(), pow(std_gyr_sim, 2)*Matrix3d::Identity(), false, seed); - Eigen::EigenMultivariateNormal<double> noise_pbc(Vector3d::Zero(), pow(std_pbc_sim, 2)*Matrix3d::Identity(), false, seed); - Eigen::EigenMultivariateNormal<double> noise_vbc(Vector3d::Zero(), pow(std_vbc_sim, 2)*Matrix3d::Identity(), false, seed); - Eigen::EigenMultivariateNormal<double> noise_f (Vector3d::Zero(), pow(std_f_sim, 2)*Matrix3d::Identity(), false, seed); - Eigen::EigenMultivariateNormal<double> noise_tau(Vector3d::Zero(), pow(std_tau_sim, 2)*Matrix3d::Identity(), false, seed); - - ////////////////////////////////////////// - // 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; - std::vector<Vector3d> c_ob_fbk_v; - std::vector<Vector3d> cd_ob_fbk_v; - std::vector<Vector3d> Lc_ob_fbk_v; - ////////////////////////////////////////// - - for (unsigned int i=0; i < t_arr.size(); i++){ - // TimeStamp ts(t_arr[i]+dt); // works best with tsid trajectories - TimeStamp ts(t_arr[i]); // works best with pyb trajectories - - // IMU - Vector6d acc_gyr_meas; acc_gyr_meas << acc_b_meas_v[i], w_b_meas_v[i]; - - if (noisy_measurements){ - acc_gyr_meas.head<3>() += noise_acc.samples(1); - acc_gyr_meas.tail<3>() += noise_gyr.samples(1); - } - - Matrix6d acc_gyr_cov = sen_imu->getNoiseCov(); - - // Inertial kinematics - meas_ikin << p_bc_meas_v[i], v_bc_meas_v[i], w_b_meas_v[i]; - // meas_ikin << p_bc_meas_v[ii], v_bc_meas_v[ii], w_b_meas_v[ii]; - // meas_ikin << p_bc_meas_v[ii+1], v_bc_meas_v[ii+1], w_b_meas_v[ii+1]; - - if (noisy_measurements){ - meas_ikin.segment<3>(0) += noise_pbc.samples(1); - meas_ikin.segment<3>(3) += noise_vbc.samples(1); - } - - //////////////////// - // Force Torque - //////////////////// - - - VectorXd f_meas(nbc*3); - VectorXd tau_meas(nbc*3); - VectorXd kin_meas(nbc*7); - for (unsigned int i_ee=0; i_ee < nbc; i_ee++){ - if (dimc == 3){ - f_meas.segment<3>(3*i_ee) = wrench_meas_v[i_ee][i]; - } - else if (dimc == 6){ - f_meas.segment<3>(3*i_ee) = wrench_meas_v[i_ee][i].head<3>(); - tau_meas.segment<3>(3*i_ee) = wrench_meas_v[i_ee][i].tail<3>(); - } - kin_meas.segment<3>(i_ee*3) = p_bl_meas_v[i_ee][i]; - kin_meas.segment<4>(nbc*3 + i_ee*4) = q_bl_meas_v[i_ee][i]; - } - - if (noisy_measurements){ - f_meas.segment<3>(0) += noise_f.samples(1); - f_meas.segment<3>(3) += noise_f.samples(1); - tau_meas.segment<3>(0) += noise_tau.samples(1); - tau_meas.segment<3>(3) += noise_tau.samples(1); - } - - VectorXd cap_ftp_data(dimc*nbc+3+3+nbc*7); - MatrixXd Qftp(dimc*nbc+3+3,dimc*nbc+3+3); // kin not in covariance mat - if (dimc == 3){ - cap_ftp_data << f_meas, p_bc_meas_v[i], w_b_meas_v[i], kin_meas; - Qftp.setIdentity(); - Qftp.block(0,0, nbc*3,nbc*3) *= pow(std_f_est, 2); - Qftp.block<3, 3>(nbc*dimc, nbc*dimc, 3,3) *= pow(std_pbc_est, 2); - Qftp.block<3, 3>(nbc*dimc+3,nbc*dimc+3, 3,3) = acc_gyr_cov.bottomRightCorner<3,3>(); - } - if (dimc == 6){ - cap_ftp_data << f_meas, tau_meas, p_bc_meas_v[i], w_b_meas_v[i], kin_meas; - Qftp.setIdentity(); - Qftp.block(0,0, nbc*3,nbc*3) *= pow(std_f_est, 2); - Qftp.block(nbc*3,nbc*3, nbc*3,nbc*3) *= pow(std_tau_est, 2); - Qftp.block<3, 3>(nbc*dimc, nbc*dimc, 3,3) *= pow(std_pbc_est, 2); - Qftp.block<3, 3>(nbc*dimc+3,nbc*dimc+3, 3,3) = acc_gyr_cov.bottomRightCorner<3,3>(); - } - //////////////////// - ///////////////// - - CaptureImuPtr CImu = std::make_shared<CaptureImu>(ts, sen_imu, acc_gyr_meas, acc_gyr_cov); - CImu->process(); - auto CIKin = std::make_shared<CaptureInertialKinematics>(ts, sen_ikin, meas_ikin, Iq_meas_v[i], Lq_meas_v[i]); - CIKin->process(); - auto CFTpreint = std::make_shared<CaptureForceTorquePreint>(ts, sen_ft, CIKin, CImu, cap_ftp_data, Qftp); - CFTpreint->process(); - - - - if (i > 0){ - // Leg odometry - // 1) detect feet in contact - std::vector<int> feet_in_contact; - for (unsigned int i_ee=0; i_ee<nbc; i_ee++){ - // basic contact detection based on normal foot vel, things break if no foot is in contact - if (wrench_meas_v[i_ee][i].norm() > fz_thresh){ - feet_in_contact.push_back(i_ee); - } - } - // 2) fill the leg odometry data matrix, depending on the contact dimension - Eigen::MatrixXd data_legodom; - if (dimc == 6){ - // cols organized as: - // [pbl1_km; qbl1_k], [pbl2_km; qbl2_k], ... - data_legodom.resize(7,feet_in_contact.size()*2); - data_legodom.setZero(); - int j = 0; - for (int i_ee_c: feet_in_contact){ - data_legodom.col(2*j ) << p_bl_meas_v[i_ee_c][i-1], q_bl_meas_v[i_ee_c][i-1]; - data_legodom.col(2*j+1) << p_bl_meas_v[i_ee_c][i ], q_bl_meas_v[i_ee_c][i]; - j++; - } - } - else if (dimc == 3){ - // cols organized as: - // pbl1_km, pbl1_k, pbl2_km, pbl2_k, ..., w_b - data_legodom.resize(3,feet_in_contact.size()*2 + 1); - data_legodom.setZero(); - int j = 0; - for (int i_ee_c: feet_in_contact){ - data_legodom.col(2*j ) << p_bl_meas_v[i_ee_c][i-1]; - data_legodom.col(2*j+1) << p_bl_meas_v[i_ee_c][i ]; - j++; - } - data_legodom.rightCols<1>() = acc_gyr_meas.tail<3>(); - } - // std::cout << "data_legodom\n" << data_legodom << std::endl; - // 3) process the data and its cov - Eigen::Matrix6d data_legodom3D_cov = pow(std_odom3d_est, 2) * Eigen::Matrix6d::Identity(); - CaptureLegOdomPtr CLO = std::make_shared<CaptureLegOdom>(ts, sen_odom3d, data_legodom, data_legodom3D_cov, dt, CaptureLegOdomType::POINT_FEET_RELATIVE_KIN); - CLO->process(); - } - - ts_since_last_kf += dt; - if ((solve_every_sec > 0) && (ts_since_last_kf >= solve_every_sec)){ - // problem->print(4,true,true,true); - std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); - std::cout << report << std::endl; - ts_since_last_kf = 0; - } - - - // Store current state estimation - VectorComposite curr_state = problem->getState(ts); - p_ob_fbk_v.push_back(curr_state['P']); - q_ob_fbk_v.push_back(curr_state['O']); - v_ob_fbk_v.push_back(curr_state['V']); - c_ob_fbk_v.push_back(curr_state['C']); - cd_ob_fbk_v.push_back(curr_state['D']); - Lc_ob_fbk_v.push_back(curr_state['L']); - } - - - - /////////////////////////////////////////// - //////////////// SOLVING ////////////////// - /////////////////////////////////////////// - problem->print(4,true,true,true); - if (solve_end){ - std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); - problem->print(4,true,true,true); - std::cout << report << std::endl; - } - - ////////////////////////////////////// - ////////////////////////////////////// - // STORE DATA // - ////////////////////////////////////// - ////////////////////////////////////// - std::fstream file_gtr; - std::fstream file_est; - std::fstream file_fbk; - std::fstream file_kfs; - std::fstream file_cov; - std::fstream file_wre; - file_gtr.open("/home/mfourmy/Documents/Phd_LAAS/phd_misc/centroidalkin/gtr.csv", std::fstream::out); - file_est.open("/home/mfourmy/Documents/Phd_LAAS/phd_misc/centroidalkin/est.csv", std::fstream::out); - file_fbk.open("/home/mfourmy/Documents/Phd_LAAS/phd_misc/centroidalkin/fbk.csv", std::fstream::out); - file_kfs.open("/home/mfourmy/Documents/Phd_LAAS/phd_misc/centroidalkin/kfs.csv", std::fstream::out); - file_cov.open("/home/mfourmy/Documents/Phd_LAAS/phd_misc/centroidalkin/cov.csv", std::fstream::out); - file_wre.open("/home/mfourmy/Documents/Phd_LAAS/phd_misc/centroidalkin/wre.csv", std::fstream::out); - std::string header_est = "t,px,py,pz,qx,qy,qz,qw,vx,vy,vz,cx,cy,cz,cdx,cdy,cdz,Lcx,Lcy,Lcz\n"; - file_est << header_est; - file_fbk << header_est; - std::string header_kfs = "t,px,py,pz,qx,qy,qz,qw,vx,vy,vz,bax,bay,baz,bwx,bwy,bwz,cx,cy,cz,cdx,cdy,cdz,Lcx,Lcy,Lcz,bpx,bpy,bpz\n"; - file_kfs << header_kfs; - file_gtr << header_kfs; // at the same frequency as "est" but ground truth biases added for comparison with kfs - std::string header_cov = "t,Qpx,Qpy,Qpz,Qqx,Qqy,Qqz,Qvx,Qvy,Qvz,Qbax,Qbay,Qbaz,Qbwx,Qbwy,Qbwz,Qcx,Qcy,Qcz,Qcdx,Qcdy,Qcdz,QLcx,QLcy,QLcz,Qbpx,Qbpy,Qbpz\n"; - file_cov << header_cov; - - for (unsigned int i=0; i < t_arr.size(); i++) { - // TODO: change if simulate a non zero imu bias - file_gtr << std::setprecision(std::numeric_limits<long double>::digits10 + 1) - << t_arr[i] << "," - << p_ob_gtr_v[i](0) << "," - << p_ob_gtr_v[i](1) << "," - << p_ob_gtr_v[i](2) << "," - << q_ob_gtr_v[i](0) << "," - << q_ob_gtr_v[i](1) << "," - << q_ob_gtr_v[i](2) << "," - << q_ob_gtr_v[i](3) << "," - << v_ob_gtr_v[i](0) << "," - << v_ob_gtr_v[i](1) << "," - << v_ob_gtr_v[i](2) << "," - << 0.0 << "," - << 0.0 << "," - << 0.0 << "," - << 0.0 << "," - << 0.0 << "," - << 0.0 << "," - << c_traj_arr[i](0) << "," - << c_traj_arr[i](1) << "," - << c_traj_arr[i](2) << "," - << dc_traj_arr[i](0) << "," - << dc_traj_arr[i](1) << "," - << dc_traj_arr[i](2) << "," - << L_traj_arr[i](0) << "," - << L_traj_arr[i](1) << "," - << L_traj_arr[i](2) << "," - << bp_traj_arr[i](0) << "," - << bp_traj_arr[i](1) << "," - << bp_traj_arr[i](2) - << std::endl; - } - - VectorComposite state_est; - for (unsigned int i=0; i < t_arr.size(); i++) { - state_est = problem->getState(t_arr[i]); - file_est << std::setprecision(std::numeric_limits<long double>::digits10 + 1) - << t_arr[i] << "," - << state_est['P'](0) << "," - << state_est['P'](1) << "," - << state_est['P'](2) << "," - << state_est['O'](0) << "," - << state_est['O'](1) << "," - << state_est['O'](2) << "," - << state_est['O'](3) << "," - << state_est['V'](0) << "," - << state_est['V'](1) << "," - << state_est['V'](2) << "," - << state_est['C'](0) << "," - << state_est['C'](1) << "," - << state_est['C'](2) << "," - << state_est['D'](0) << "," - << state_est['D'](1) << "," - << state_est['D'](2) << "," - << state_est['L'](0) << "," - << state_est['L'](1) << "," - << state_est['L'](2) - << "\n"; - } - - for (unsigned int i=0; i < t_arr.size(); i++) { - file_fbk << std::setprecision(std::numeric_limits<long double>::digits10 + 1) - << t_arr[i] << "," - << p_ob_fbk_v[i](0) << "," - << p_ob_fbk_v[i](1) << "," - << p_ob_fbk_v[i](2) << "," - << q_ob_fbk_v[i](0) << "," - << q_ob_fbk_v[i](1) << "," - << q_ob_fbk_v[i](2) << "," - << q_ob_fbk_v[i](3) << "," - << v_ob_fbk_v[i](0) << "," - << v_ob_fbk_v[i](1) << "," - << v_ob_fbk_v[i](2) << "," - << c_ob_fbk_v[i](0) << "," - << c_ob_fbk_v[i](1) << "," - << c_ob_fbk_v[i](2) << "," - << cd_ob_fbk_v[i](0) << "," - << cd_ob_fbk_v[i](1) << "," - << cd_ob_fbk_v[i](2) << "," - << Lc_ob_fbk_v[i](0) << "," - << Lc_ob_fbk_v[i](1) << "," - << Lc_ob_fbk_v[i](2) - << "\n"; - } - - VectorComposite kf_state; - CaptureBasePtr cap_ikin; - VectorComposite bp_bias_est; - CaptureBasePtr cap_imu; - VectorComposite bi_bias_est; - for (auto& elt: problem->getTrajectory()->getFrameMap()){ - auto kf = elt.second; - kf_state = kf->getState(); - cap_ikin = kf->getCaptureOf(sen_ikin); - bp_bias_est = cap_ikin->getState(); - cap_imu = kf->getCaptureOf(sen_imu); - bi_bias_est = cap_imu->getState(); - - file_kfs << std::setprecision(std::numeric_limits<long double>::digits10 + 1) - << kf->getTimeStamp().get() << "," - << kf_state['P'](0) << "," - << kf_state['P'](1) << "," - << kf_state['P'](2) << "," - << kf_state['O'](0) << "," - << kf_state['O'](1) << "," - << kf_state['O'](2) << "," - << kf_state['O'](3) << "," - << kf_state['V'](0) << "," - << kf_state['V'](1) << "," - << kf_state['V'](2) << "," - << bi_bias_est['I'](0) << "," - << bi_bias_est['I'](1) << "," - << bi_bias_est['I'](2) << "," - << bi_bias_est['I'](3) << "," - << bi_bias_est['I'](4) << "," - << bi_bias_est['I'](5) << "," - << kf_state['C'](0) << "," - << kf_state['C'](1) << "," - << kf_state['C'](2) << "," - << kf_state['D'](0) << "," - << kf_state['D'](1) << "," - << kf_state['D'](2) << "," - << kf_state['L'](0) << "," - << kf_state['L'](1) << "," - << kf_state['L'](2) << "," - << bp_bias_est['I'](0) << "," - << bp_bias_est['I'](1) << "," - << bp_bias_est['I'](2) - << "\n"; - - // 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 Qc = Eigen::Matrix3d::Identity(); - Eigen::MatrixXd Qd = Eigen::Matrix3d::Identity(); - Eigen::MatrixXd QL = Eigen::Matrix3d::Identity(); - Eigen::MatrixXd Qbp = Eigen::Matrix3d::Identity(); - // solver->computeCovariances(kf->getStateBlockVec()); // !! does not work as intended... - - 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); - problem->getCovarianceBlock(kf->getStateBlock('C'), Qc); - problem->getCovarianceBlock(kf->getStateBlock('D'), Qd); - problem->getCovarianceBlock(kf->getStateBlock('L'), QL); - - solver->computeCovariances(cap_ikin->getStateBlockVec()); // not computed by ALL and destroys other computed covs -> issue to raise - problem->getCovarianceBlock(cap_ikin->getSensorIntrinsic(), Qbp); - // 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); - - file_cov << std::setprecision(std::numeric_limits<long double>::digits10 + 1) - << kf->getTimeStamp().get() << "," - << Qp(0,0) << "," - << Qp(1,1) << "," - << Qp(2,2) << "," - << Qo(0,0) << "," - << Qo(1,1) << "," - << Qo(2,2) << "," - << Qv(0,0) << "," - << Qv(1,1) << "," - << Qv(2,2) << "," - << Qbi(0,0) << "," - << Qbi(1,1) << "," - << Qbi(2,2) << "," - << Qbi(3,3) << "," - << Qbi(4,4) << "," - << Qbi(5,5) << "," - << Qc(0,0) << "," - << Qc(1,1) << "," - << Qc(2,2) << "," - << Qd(0,0) << "," - << Qd(1,1) << "," - << Qd(2,2) << "," - << QL(0,0) << "," - << QL(1,1) << "," - << QL(2,2) << "," - << Qbp(0,0) << "," - << Qbp(1,1) << "," - << Qbp(2,2) - << "\n"; - } - - file_gtr.close(); - file_est.close(); - file_kfs.close(); - file_cov.close(); - file_wre.close(); - - -} diff --git a/demos/mcapi_povcdl_estimation.yaml b/demos/mcapi_povcdl_estimation.yaml deleted file mode 100644 index 28b57f008d929631d65099e27a746a82c049c3da..0000000000000000000000000000000000000000 --- a/demos/mcapi_povcdl_estimation.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# trajectory handling -dt: 0.001 -min_t: -1.0 # -1 means from the beginning of the trajectory -max_t: -1 # -1 means until the end of the trajectory -solve_every_sec: -1 # < 0 strict --> no solve -solve_end: False -# solve_every_sec: 0.3 # < 0 strict --> no solve -# solve_end: True - -# estimator sensor noises -std_acc_est: 0.001 -std_gyr_est: 0.001 -std_pbc_est: 0.001 -std_vbc_est: 0.001 # higher than simulated -> has to take care of the non-modeled bias as well... Good value for solo sin traj -std_f_est: 0.001 -std_tau_est: 0.001 -# std_odom3d_est: 0.000001 -std_odom3d_est: 100000 - -# simulated sensor noises -std_acc_sim: 0.0001 -std_gyr_sim: 0.0001 -std_pbc_sim: 0.0001 -std_vbc_sim: 0.0001 -std_f_sim: 0.0001 -std_tau_sim: 0.0001 -std_odom3d_sim: 100000000 - -# some controls -fz_thresh: 1 -noisy_measurements: False - -# priors -std_prior_p: 0.01 -std_prior_o: 0.1 -std_prior_v: 0.1 - -# std_abs_biasimu: 100000 -std_abs_biasimu: 0.0000001 # almost fixed -std_abs_bias_pbc: 10000 # noprior -# std_abs_bias_pbc: 0.00001 # almost fixed -std_bp_drift: 10000 # All the drift you want -# std_bp_drift: 0.1 # no drift - -bias_pbc_prior: [0,0,0] - - -# model disturbance -scale_dist: 0.00 # disturbance of link inertia -mass_dist: False -base_dist_only: False - -# which measurement/parameter is disturbed? -vbc_is_dist: False -Iw_is_dist: False -Lgest_is_dist: False - - -# Robot model -# robot_urdf: "/opt/openrobots/share/example-robot-data/robots/talos_data/robots/talos_reduced.urdf" -# dimc: 6 -robot_urdf: "/opt/openrobots/share/example-robot-data/robots/solo_description/robots/solo12.urdf" -dimc: 3 - - -# Trajectory files -# contact_sequence_file: "/home/mfourmy/Documents/Phd_LAAS/data/trajs/talos_sin_traj.cs" -# contact_sequence_file: "/home/mfourmy/Documents/Phd_LAAS/data/trajs/talos_contact_switch.cs" -# contact_sequence_file: "/home/mfourmy/Documents/Phd_LAAS/data/trajs/solo_sin_traj.cs" -contact_sequence_file: "/home/mfourmy/Documents/Phd_LAAS/data/trajs/solo_sin_traj_pyb.cs" - -# contact_sequence_file: "/home/mfourmy/Documents/Phd_LAAS/data/trajs/solo_sin_y_notrunk.cs" -# contact_sequence_file: "/home/mfourmy/Documents/Phd_LAAS/data/trajs/solo_sin_r+y.cs" - -# contact_sequence_file: "/home/mfourmy/Documents/Phd_LAAS/data/trajs/solo_sin_r+z.cs" -# contact_sequence_file: "/home/mfourmy/Documents/Phd_LAAS/data/trajs/solo_stamping.cs" diff --git a/demos/processor_imu_solo12.yaml b/demos/processor_imu_solo12.yaml index f92b74c06167c96ef4294e00600c7270bd0d20e2..14964b20685f70720ed8d21c19ba8cdf66406aac 100644 --- a/demos/processor_imu_solo12.yaml +++ b/demos/processor_imu_solo12.yaml @@ -2,7 +2,7 @@ keyframe_vote: angle_turned: 1000 dist_traveled: 20000.0 max_buff_length: 100000000000 - max_time_span: 0.19999 + max_time_span: 0.05 voting_active: true name: Main imu time_tolerance: 0.0005 diff --git a/demos/sensor_imu_solo12.yaml b/demos/sensor_imu_solo12.yaml index 68ad34e3b0d14ec0711760551d8875ab005622cc..baf999bfa6179df1967dceb5f95a17da8134d3f3 100644 --- a/demos/sensor_imu_solo12.yaml +++ b/demos/sensor_imu_solo12.yaml @@ -1,9 +1,9 @@ -type: "SensorImu" # This must match the KEY used in the SensorFactory. Otherwise it is an error. -name: "Main Imu Sensor" # This is ignored. The name provided to the SensorFactory prevails -motion_variances: - a_noise: 0.05 # standard deviation of Acceleration noise (same for all the axis) in m/s2 - w_noise: 0.005 # standard deviation of Gyroscope noise (same for all the axis) in rad/sec - ab_initial_stdev: 0.00 # m/s2 - initial bias - wb_initial_stdev: 0.0 # rad/sec - initial bias - ab_rate_stdev: 0.0001 # m/s2/sqrt(s) - wb_rate_stdev: 0.0001 # rad/s/sqrt(s) \ No newline at end of file +motion_variances: + a_noise: 0.02 + ab_initial_stdev: 0.0 + ab_rate_stdev: 1.0e-06 + w_noise: 0.03 + wb_initial_stdev: 0.0 + wb_rate_stdev: 1.0e-06 +name: Main Imu Sensor +type: SensorImu diff --git a/demos/solo_imu_kine.cpp b/demos/solo_imu_kine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9f52035066348852f9a296504e414520669656e --- /dev/null +++ b/demos/solo_imu_kine.cpp @@ -0,0 +1,742 @@ +//--------LICENSE_START-------- +// +// Copyright (C) 2020,2021,2022 Institut de Robòtica i Informà tica Industrial, CSIC-UPC. +// Authors: Joan Solà Ortega (jsola@iri.upc.edu) +// All rights reserved. +// +// This file is part of WOLF +// WOLF is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +//--------LICENSE_END-------- +#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" +#include "bodydynamics/sensor/sensor_inertial_kinematics.h" +#include "bodydynamics/sensor/sensor_force_torque.h" +#include "bodydynamics/capture/capture_inertial_kinematics.h" +#include "bodydynamics/capture/capture_force_torque_preint.h" +#include "bodydynamics/capture/capture_leg_odom.h" +#include "bodydynamics/processor/processor_inertial_kinematics.h" +#include "bodydynamics/processor/processor_force_torque_preint.h" +#include "bodydynamics/factor/factor_inertial_kinematics.h" +#include "bodydynamics/factor/factor_force_torque_preint.h" + +#include "bodydynamics/sensor/sensor_point_feet_nomove.h" +#include "bodydynamics/processor/processor_point_feet_nomove.h" +#include "bodydynamics/capture/capture_point_feet_nomove.h" +#include "bodydynamics/factor/factor_point_feet_nomove.h" + + + + +using namespace Eigen; +using namespace wolf; +using namespace pinocchio; + +typedef pinocchio::SE3Tpl<double> SE3; +typedef pinocchio::ForceTpl<double> Force; + +void printFactorCosts(FrameBasePtr kf_last){ + int nb_max_fact_ptf = 4; + int nb = 0; + for (auto f: kf_last->getFactorList()){ + auto fimu = std::dynamic_pointer_cast<FactorImu>(f); + if (fimu){ + std::cout << std::setprecision(12) << " C_IMU " << sqrt(fimu->cost()) << std::endl; + } + else{ + auto fptn = std::dynamic_pointer_cast<FactorPointFeetNomove>(f); + if (fptn and (nb < nb_max_fact_ptf)){ + Vector3d error = fptn->error(); + double cost = fptn->cost(); + std::cout << std::setprecision(12) << " E_PF" << nb << " " << error.transpose() << std::endl; + std::cout << std::setprecision(12) << " C_PF" << nb << " " << sqrt(cost) << std::endl; + nb++; + } + } + } +} + + +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"); + 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>(); + double func_tol = config["func_tol"].as<double>(); + bool compute_cov = config["compute_cov"].as<bool>(); + + // robot + std::string robot_urdf = config["robot_urdf"].as<std::string>(); + int dimc = config["dimc"].as<int>(); + int nb_feet = config["nb_feet"].as<int>(); + + + // 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> i_p_im_vec = config["i_p_im"].as<std::vector<double>>(); + Eigen::Map<Vector3d> i_p_im(i_p_im_vec.data()); + std::vector<double> i_q_m_vec = config["i_q_m"].as<std::vector<double>>(); + Eigen::Map<Vector4d> i_qvec_m(i_q_m_vec.data()); + std::vector<double> m_p_mb_vec = config["m_p_mb"].as<std::vector<double>>(); + Eigen::Map<Vector3d> m_p_mb(m_p_mb_vec.data()); + std::vector<double> m_q_b_vec = config["m_q_b"].as<std::vector<double>>(); + Eigen::Map<Vector4d> m_qvec_b(m_q_b_vec.data()); + + + // kinematics + double std_foot_nomove = config["std_foot_nomove"].as<double>(); + double std_altitude = config["std_altitude"].as<double>(); + double foot_radius = config["foot_radius"].as<double>(); + std::vector<double> delta_qa_vec = config["delta_qa"].as<std::vector<double>>(); + Eigen::Map<Eigen::Matrix<double,12,1>> delta_qa(delta_qa_vec.data()); + std::vector<double> alpha_qa_vec = config["alpha_qa"].as<std::vector<double>>(); + Eigen::Map<Eigen::Matrix<double,12,1>> alpha_qa(alpha_qa_vec.data()); + std::vector<double> l_p_lg_vec = config["l_p_lg"].as<std::vector<double>>(); + 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>(); + + // MOCAP to IMU transform + Quaterniond i_q_m(i_qvec_m); + i_q_m.normalize(); + assert(i_q_m.normalized().isApprox(i_q_m)); + SE3 i_T_m(i_q_m, i_p_im); + Matrix3d i_R_m = i_T_m.rotation(); + + // IMU to MOCAP transform + SE3 m_T_i = i_T_m.inverse(); + Vector3d m_p_mi = m_T_i.translation(); + Quaterniond m_q_i = Quaterniond(m_T_i.rotation()); + + // MOCAP to BASE transform + Quaterniond m_q_b(m_qvec_b); + m_q_b.normalize(); + assert(m_q_b.normalized().isApprox(m_q_b)); + SE3 m_T_b(m_q_b, m_p_mb); + Matrix3d m_R_b = m_T_b.rotation(); + + // IMU to BASE transform (composition) + SE3 i_T_b = i_T_m*m_T_b; + 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["contacts"]; + // 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); + } + + // Load the urdf model + Model model; + pinocchio::urdf::buildModel(robot_urdf, JointModelFreeFlyer(), model); + std::cout << "model name: " << model.name << std::endl; + Data data(model); + std::vector<std::string> ee_names = {"FL_ANKLE", "FR_ANKLE", "HL_ANKLE", "HR_ANKLE"}; + unsigned int nbc = ee_names.size(); + + // Recover end effector frame ids + std::vector<int> ee_ids; + std::cout << "Frame ids" << std::endl; + for (auto ee_name: ee_names){ + ee_ids.push_back(model.getFrameId(ee_name)); + std::cout << ee_name << std::endl; + } + + ///////////////////////// + // 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); + + ////////////////////// + // CERES WRAPPER + SolverCeresPtr solver = std::make_shared<SolverCeres>(problem); + solver->getSolverOptions().max_num_iterations = max_num_iterations; + solver->getSolverOptions().function_tolerance = func_tol; // 1e-6 + solver->getSolverOptions().gradient_tolerance = 1e-4*solver->getSolverOptions().function_tolerance; + + // solver->getSolverOptions().minimizer_type = ceres::TRUST_REGION; + // solver->getSolverOptions().trust_region_strategy_type = ceres::DOGLEG; + // solver->getSolverOptions().trust_region_strategy_type = ceres::LEVENBERG_MARQUARDT; + + // solver->getSolverOptions().minimizer_type = ceres::LINE_SEARCH; + // solver->getSolverOptions().line_search_direction_type = ceres::LBFGS; + + + //===================================================== 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 POINT FEET NOMOVE + ParamsSensorPointFeetNomovePtr intr_pfn = std::make_shared<ParamsSensorPointFeetNomove>(); + intr_pfn->std_foot_nomove_ = std_foot_nomove; + intr_pfn->std_altitude_ = std_altitude; + intr_pfn->foot_radius_ = foot_radius; + VectorXd extr; // default size for dynamic vector is 0-0 -> what we need + SensorBasePtr sen_pfnm_base = problem->installSensor("SensorPointFeetNomove", "SenPfnm", extr, intr_pfn); + SensorPointFeetNomovePtr sen_pfnm = std::static_pointer_cast<SensorPointFeetNomove>(sen_pfnm_base); + ParamsProcessorPointFeetNomovePtr params_pfnm = std::make_shared<ParamsProcessorPointFeetNomove>(); + params_pfnm->voting_active = false; + params_pfnm->time_tolerance = 0.0; + params_pfnm->max_time_vote = 0.0; + ProcessorBasePtr proc_pfnm_base = problem->installProcessor("ProcessorPointFeetNomove", "PPointFeetNomove", sen_pfnm, params_pfnm); + + + // SETPRIOR RETRO-ENGINEERING + // We are not using setPrior because of processors initial captures problems so we have to + // - Manually create the first KF and its pose and velocity priors + // - call setOrigin on processors MotionProvider since the flag prior_is_set is not true when doing installProcessor (later) + + ////////////////////// + // COMPUTE INITIAL STATE + TimeStamp t0(t_arr[0]); + Eigen::Map<Vector3d> w_p_wm(w_p_wm_arr); + Eigen::Map<Vector4d> w_qvec_m_init(w_q_m_arr); + w_qvec_m_init.normalize(); // not close enough to wolf eps sometimes + Quaterniond w_q_m_init(w_qvec_m_init); + Vector3d w_p_wi_init = w_p_wm + w_q_m_init*m_p_mi; + Quaterniond w_q_i_init = w_q_m_init*m_q_i; + VectorComposite x_origin("POV", {w_p_wi_init, w_q_i_init.coeffs(), 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); + FrameBasePtr KF1 = problem->setPriorInitialGuess(x_origin, t0); // 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); + + + // 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* o_p_oi_fbk_carr = new double[3*N]; + double* o_q_i_fbk_carr = new double[4*N]; + double* o_v_oi_fbk_carr = new double[3*N]; + double* imu_bias_fbk_carr = new double[6*N]; + double* i_pose_im_fbk_carr = new double[7*N]; + + // covariances computed on the fly + std::vector<Vector3d> Qp_fbk_v; Qp_fbk_v.push_back(Vector3d::Zero()); + std::vector<Vector3d> Qo_fbk_v; Qo_fbk_v.push_back(Vector3d::Zero()); + std::vector<Vector3d> Qv_fbk_v; Qv_fbk_v.push_back(Vector3d::Zero()); + std::vector<Vector6d> Qbi_fbk_v; Qbi_fbk_v.push_back(Vector6d::Zero()); + std::vector<Vector6d> Qm_fbk_v; Qm_fbk_v.push_back(Vector6d::Zero()); + + + 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']; + + + ////////////// + // PROCESS IMU + ////////////// + // 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); + // 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>()); + + Vector6d acc_gyr_meas; acc_gyr_meas << imu_acc, i_omg_oi; + CaptureImuPtr CImu = std::make_shared<CaptureImu>(ts, sen_imu, acc_gyr_meas, sen_imu->getNoiseCov()); + CImu->process(); + ////////////// + ////////////// + + ////////////////////////////////// + // Kinematics + forces + // retrieve traj data + 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<Matrix<double,4, 1>> contact_gtr(contact_arr+4*i); // int conversion does not work! + // std::cout << contact_gtr.transpose() << std::endl; + // Eigen::Map<Matrix<double,12, 1>> b_p_bl_mocap(b_p_bl_mocap_arr+12*i); // int conversion does not work! + + // Kinematics model + qa = qa + delta_qa + alpha_qa.cwiseProduct(tau); + + Matrix3d o_R_i = Quaterniond(o_q_i_curr).toRotationMatrix(); // IMU internal filter + + // Or else, retrieve from preprocessed dataset + Eigen::Map<Matrix<double,12, 1>> l_forces(l_forces_arr+12*i); + + Vector3d o_f_tot = Vector3d::Zero(); + std::vector<Vector3d> l_f_l_vec; + std::vector<Vector3d> o_f_l_vec; + std::vector<Vector3d> i_p_il_vec; + std::vector<Vector4d> i_qvec_l_vec; + // needing relative kinematics measurements + VectorXd q_static(19); q_static << 0,0,0, 0,0,0,1, qa; + VectorXd dq_static(18); dq_static << 0,0,0, 0,0,0, dqa; + forwardKinematics(model, data, q_static, dq_static); + updateFramePlacements(model, data); + + for (unsigned int i_ee=0; i_ee < nbc; i_ee++){ + auto b_T_l = data.oMf[ee_ids[i_ee]]; + + auto i_T_l = i_T_b * b_T_l; + Vector3d i_p_il = i_T_l.translation(); + Matrix3d i_R_l = i_T_l.rotation(); + Vector4d i_qvec_l = Quaterniond(i_R_l).coeffs(); + i_p_il = i_p_il + i_R_l*l_p_lg; + + Vector3d l_f_l = l_forces.segment(3*i_ee, 3); + Vector3d o_f_l = o_R_i*i_R_l * l_f_l; // for contact test + + l_f_l_vec.push_back(l_f_l); + o_f_l_vec.push_back(o_f_l); + i_p_il_vec.push_back(i_p_il); + i_qvec_l_vec.push_back(i_qvec_l); + } + + // Detect feet in contact + int nb_feet_in_contact = 0; + std::unordered_map<int, Vector7d> kin_incontact; + // std::cout << "" << std::endl; + for (unsigned int i_ee=0; i_ee<nbc; i_ee++){ + // basic contact detection based on normal foot vel, things break if no foot is in contact + // if ((o_f_l_vec[i_ee](2) > fz_thresh) && (nb_feet_in_contact < nb_feet)){ + // if ((contact_gtr[i_ee] > 0.5) && (nb_feet_in_contact < nb_feet)){ + if (contact_gtr[i_ee] > 0.5){ + nb_feet_in_contact++; + Vector7d i_pose_il; i_pose_il << i_p_il_vec[i_ee], i_qvec_l_vec[i_ee]; + kin_incontact.insert({i_ee, i_pose_il}); + } + } + + CapturePointFeetNomovePtr CPF = std::make_shared<CapturePointFeetNomove>(ts, sen_pfnm, kin_incontact); + CPF->process(); + + // solve every new KF + if (problem->getTrajectory()->size() > nb_kf ){ + std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); + + // //////////////////////////////// + // // FOR PLOTS + // if (solver->iterations() == 1){ + // std::cout << "ONLY ONE!" << std::endl; + // printFactorCosts(kf_last); + // for (int k=0; k < 5; k++){ + // std::cout << "P E R T U B!" << std::endl; + // // problem->perturb(0.000001); + // kf_last->perturb(); + // // std::cout << "kf_last P " << kf_last->getP()->getState().transpose() << std::endl; + // report = solver->solve(SolverManager::ReportVerbosity::BRIEF); + // printFactorCosts(kf_last); + // } + + // } + // /////////////////////// + + + //////////////////////////////// + // FOR REAL + if (solver->iterations() == 1){ + // kf_last->perturb(0.000001); + report = solver->solve(SolverManager::ReportVerbosity::BRIEF); + } + /////////////////////// + + std::cout << ts << " "; + std::cout << report << std::endl; + ////////////////////////////// + + // printFactorCosts(kf_last); + + + // compute covariances of KF and capture stateblocks + Eigen::MatrixXd Qp_fbk = Eigen::Matrix3d::Identity(); + Eigen::MatrixXd Qo_fbk = Eigen::Matrix3d::Identity(); // global or local? + Eigen::MatrixXd Qv_fbk = Eigen::Matrix3d::Identity(); + Eigen::MatrixXd Qbi_fbk = Eigen::Matrix6d::Identity(); + Eigen::MatrixXd Qmp_fbk = Eigen::Matrix3d::Identity(); // extr mocap + Eigen::MatrixXd Qmo_fbk = Eigen::Matrix3d::Identity(); // extr mocap + + if (compute_cov) + solver->computeCovariances(SolverManager::CovarianceBlocksToBeComputed::ALL); // should not be computed every time !! see below + problem->getCovarianceBlock(kf_last->getStateBlock('P'), Qp_fbk); + problem->getCovarianceBlock(kf_last->getStateBlock('O'), Qo_fbk); + problem->getCovarianceBlock(kf_last->getStateBlock('V'), Qv_fbk); + + CaptureBasePtr cap_imu = kf_last->getCaptureOf(sen_imu); + if (compute_cov) + solver->computeCovariances(cap_imu->getStateBlockVec()); // not computed by ALL and destroys other computed covs -> issue to raise + problem->getCovarianceBlock(cap_imu->getSensorIntrinsic(), Qbi_fbk); + + // Retrieve diagonals + Vector3d Qp_fbk_diag = Qp_fbk.diagonal(); + Vector3d Qo_fbk_diag = Qo_fbk.diagonal(); + Vector3d Qv_fbk_diag = Qv_fbk.diagonal(); + Vector6d Qbi_fbk_diag = Qbi_fbk.diagonal(); + Vector6d Qm_fbk_diag; Qm_fbk_diag << Qmp_fbk.diagonal(), Qmo_fbk.diagonal(); + Vector3d Qmo_fbk_diag = Qmo_fbk.diagonal(); + + Qp_fbk_v.push_back(Qp_fbk_diag); + Qo_fbk_v.push_back(Qo_fbk_diag); + Qv_fbk_v.push_back(Qv_fbk_diag); + Qbi_fbk_v.push_back(Qbi_fbk_diag); + Qm_fbk_v.push_back(Qm_fbk_diag); + + 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 + 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_p_ib); + Vector3d o_v_ob = o_v_oi + o_R_i * i_omg_oi.cross(i_p_ib); + + imu_bias = sen_imu->getIntrinsic()->getState(); + Vector7d i_pose_im_fbk; i_pose_im_fbk << i_p_im, i_qvec_m; + + 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(o_p_oi_fbk_carr+3*i, o_p_oi.data(), 3*sizeof(double)); + mempcpy(o_q_i_fbk_carr +4*i, o_qvec_i.data(), 4*sizeof(double)); + mempcpy(o_v_oi_fbk_carr+3*i, o_v_oi.data(), 3*sizeof(double)); + mempcpy(imu_bias_fbk_carr+6*i, imu_bias.data(), 6*sizeof(double)); + mempcpy(i_pose_im_fbk_carr+7*i, i_pose_im_fbk.data(), 7*sizeof(double)); + } + + + + /////////////////////////////////////////// + //////////////// SOLVING ////////////////// + /////////////////////////////////////////// + // if (solve_end){ + // std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); + // problem->print(3,true,false,false); + // std::cout << report << std::endl; + // } + + double* o_p_ob_carr = new double[3*N]; + double* o_q_b_carr = new double[4*N]; + double* o_v_ob_carr = new double[3*N]; + double* o_p_oi_carr = new double[3*N]; + double* o_q_i_carr = new double[4*N]; + double* o_v_oi_carr = new double[3*N]; + double* imu_bias_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(); + 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_p_ib); + Vector3d o_v_ob = o_v_oi + o_R_i * i_omg_oi.cross(i_p_ib); + + 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(o_p_oi_carr+3*i, o_p_oi.data(), 3*sizeof(double)); + mempcpy(o_q_i_carr +4*i, o_qvec_i.data(), 4*sizeof(double)); + mempcpy(o_v_oi_carr+3*i, o_v_oi.data(), 3*sizeof(double)); + mempcpy(imu_bias_carr+6*i, imu_bias.data(), 6*sizeof(double)); + } + + + // Compute Covariances + unsigned int Nkf = problem->getTrajectory()->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]; + // feedback covariances + double* Qp_fbk_carr = new double[3*Nkf]; + double* Qo_fbk_carr = new double[3*Nkf]; + double* Qv_fbk_carr = new double[3*Nkf]; + double* Qbi_fbk_carr = new double[6*Nkf]; + double* Qm_fbk_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()->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 + + if (compute_cov) + 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); + if (compute_cov) + 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)); + + // Recover feedback covariances + memcpy(Qp_fbk_carr + 3*i, Qp_fbk_v[i].data(), 3*sizeof(double)); + memcpy(Qo_fbk_carr + 3*i, Qo_fbk_v[i].data(), 3*sizeof(double)); + memcpy(Qv_fbk_carr + 3*i, Qv_fbk_v[i].data(), 3*sizeof(double)); + memcpy(Qbi_fbk_carr + 6*i, Qbi_fbk_v[i].data(), 6*sizeof(double)); + memcpy(Qm_fbk_carr + 6*i, Qm_fbk_v[i].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(); + + 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_imu", o_q_i_arr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "qa", qa_arr, {N,12}, "a"); + cnpy::npz_save(out_npz_file_path, "i_omg_oi", i_omg_oi_arr, {N,3}, "a"); + + // Online 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_oi_fbk", o_p_oi_fbk_carr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_i_fbk", o_q_i_fbk_carr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "o_v_oi_fbk", o_v_oi_fbk_carr, {N,3}, "a"); + + // offline states + 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"); + cnpy::npz_save(out_npz_file_path, "o_p_oi", o_p_oi_carr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_i", o_q_i_carr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "o_v_oi", o_v_oi_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, "i_pose_im_fbk", i_pose_im_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, "Qp_fbk", Qp_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qo_fbk", Qo_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qv_fbk", Qv_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qbi_fbk", Qbi_fbk_carr, {Nkf,6}, "a"); + cnpy::npz_save(out_npz_file_path, "Qm_fbk", Qm_fbk_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_pov_estimation.cpp b/demos/solo_imu_kine_mocap.cpp similarity index 61% rename from demos/solo_real_pov_estimation.cpp rename to demos/solo_imu_kine_mocap.cpp index fbae4d51a0f97f30aa05c5329ca754986ce72cb2..82d2df1c42da66a66e6894fe49e037b4a04259cd 100644 --- a/demos/solo_real_pov_estimation.cpp +++ b/demos/solo_imu_kine_mocap.cpp @@ -81,9 +81,6 @@ -// UTILS -#include "mcapi_utils.h" - using namespace Eigen; using namespace wolf; @@ -96,42 +93,53 @@ 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 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>(); + // double solve_every_sec = config["solve_every_sec"].as<double>(); bool solve_end = config["solve_end"].as<bool>(); + // robot + std::string robot_urdf = config["robot_urdf"].as<std::string>(); + // int dimc = config["dimc"].as<int>(); + // int nb_feet = config["nb_feet"].as<int>(); + // Ceres setup int max_num_iterations = config["max_num_iterations"].as<int>(); + bool compute_cov = config["compute_cov"].as<bool>(); // 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>(); + // 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_foot_nomove = config["std_foot_nomove"].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_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>(); + // 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> i_p_im_vec = config["i_p_im"].as<std::vector<double>>(); + Eigen::Map<Vector3d> i_p_im(i_p_im_vec.data()); + std::vector<double> i_q_m_vec = config["i_q_m"].as<std::vector<double>>(); + Eigen::Map<Vector4d> i_qvec_m(i_q_m_vec.data()); + std::vector<double> m_p_mb_vec = config["m_p_mb"].as<std::vector<double>>(); + Eigen::Map<Vector3d> m_p_mb(m_p_mb_vec.data()); + std::vector<double> m_q_b_vec = config["m_q_b"].as<std::vector<double>>(); + Eigen::Map<Vector4d> m_qvec_b(m_q_b_vec.data()); + + // contacts 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>(); + // double fz_thresh = config["fz_thresh"].as<double>(); + std::vector<double> delta_qa_vec = config["delta_qa"].as<std::vector<double>>(); + Eigen::Map<Eigen::Matrix<double,12,1>> delta_qa(delta_qa_vec.data()); // MOCAP double std_pose_p = config["std_pose_p"].as<double>(); @@ -146,17 +154,31 @@ int main (int argc, char **argv) { 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>(); - std::vector<std::string> ee_names = {"FL_ANKLE", "FR_ANKLE", "HL_ANKLE", "HR_ANKLE"}; - unsigned int nbc = ee_names.size(); - // 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(); + // MOCAP to IMU transform + Quaterniond i_q_m(i_qvec_m); + i_q_m.normalize(); + assert(i_q_m.normalized().isApprox(i_q_m)); + SE3 i_T_m(i_q_m, i_p_im); + // Matrix3d i_R_m = i_T_m.rotation(); + + // IMU to MOCAP transform + SE3 m_T_i = i_T_m.inverse(); + Vector3d m_p_mi = m_T_i.translation(); + Quaterniond m_q_i = Quaterniond(m_T_i.rotation()); + + // MOCAP to BASE transform + Quaterniond m_q_b(m_qvec_b); + m_q_b.normalize(); + assert(m_q_b.normalized().isApprox(m_q_b)); + SE3 m_T_b(m_q_b, m_p_mb); + // Matrix3d m_R_b = m_T_b.rotation(); + + // IMU to BASE transform (composition) + SE3 i_T_b = i_T_m*m_T_b; Vector3d i_p_ib = i_T_b.translation(); - Matrix3d i_R_b = i_T_b.rotation(); + 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); @@ -177,7 +199,7 @@ int main (int argc, char **argv) { // 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 contact_npyarr = arr_map["contacts"]; // cnpy::NpyArray b_p_bl_mocap_npyarr = arr_map["b_p_bl_mocap"]; // cnpy::NpyArray w_R_m_npyarr = arr_map["w_R_m"]; @@ -197,7 +219,7 @@ int main (int argc, char **argv) { 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* 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>(); @@ -206,12 +228,13 @@ int main (int argc, char **argv) { N = N < int(max_t/dt) ? N : int(max_t/dt); } - // Creating measurements from simulated trajectory // Load the urdf model Model model; pinocchio::urdf::buildModel(robot_urdf, JointModelFreeFlyer(), model); std::cout << "model name: " << model.name << std::endl; Data data(model); + std::vector<std::string> ee_names = {"FL_ANKLE", "FR_ANKLE", "HL_ANKLE", "HR_ANKLE"}; + unsigned int nbc = ee_names.size(); // Recover end effector frame ids std::vector<int> ee_ids; @@ -235,22 +258,6 @@ int main (int argc, char **argv) { problem->setTreeManager(tree_manager); ////////////////////// - // COMPUTE INITIAL STATE - TimeStamp t0(t_arr[0]); - Eigen::Map<Matrix<double,12, 1>> qa(qa_arr); - Eigen::Map<Matrix<double,12, 1>> dqa(dqa_arr); - 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 - - // initial state - VectorXd q(19); q << 0,0,0, o_q_i, qa; // TODO: put current base orientation estimate? YES - VectorXd dq(18); dq << 0,0,0, i_omg_oi, dqa; // TODO: put current base velocity estimate? YES - - ////////////////////// - // CERES WRAPPER SolverCeresPtr solver = std::make_shared<SolverCeres>(problem); solver->getSolverOptions().max_num_iterations = max_num_iterations; @@ -262,21 +269,25 @@ int main (int argc, char **argv) { 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 POINT FEET NOMOVE - // ParamsSensorPointFeetNomovePtr intr_pfn = std::make_shared<ParamsSensorPointFeetNomove>(); - // intr_pfn->std_foot_nomove_ = std_odom3d_est; - // VectorXd extr; // default size for dynamic vector is 0-0 -> what we need - // SensorBasePtr sen_pfnm_base = problem->installSensor("SensorPointFeetNomove", "SenPfnm", extr, intr_pfn); - // SensorPointFeetNomovePtr sen_pfnm = std::static_pointer_cast<SensorPointFeetNomove>(sen_pfnm_base); - // ParamsProcessorPointFeetNomovePtr params_pfnm = std::make_shared<ParamsProcessorPointFeetNomove>(); - // ProcessorBasePtr proc_pfnm_base = problem->installProcessor("ProcessorPointFeetNomove", "PPointFeetNomove", sen_pfnm, params_pfnm); + // SENSOR + PROCESSOR POINT FEET NOMOVE + ParamsSensorPointFeetNomovePtr intr_pfn = std::make_shared<ParamsSensorPointFeetNomove>(); + intr_pfn->std_foot_nomove_ = std_foot_nomove; + VectorXd extr; // default size for dynamic vector is 0-0 -> what we need + SensorBasePtr sen_pfnm_base = problem->installSensor("SensorPointFeetNomove", "SenPfnm", extr, intr_pfn); + SensorPointFeetNomovePtr sen_pfnm = std::static_pointer_cast<SensorPointFeetNomove>(sen_pfnm_base); + ParamsProcessorPointFeetNomovePtr params_pfnm = std::make_shared<ParamsProcessorPointFeetNomove>(); + params_pfnm->voting_active = false; + params_pfnm->time_tolerance = 0.0; + params_pfnm->max_time_vote = 0.0; + ProcessorBasePtr proc_pfnm_base = problem->installProcessor("ProcessorPointFeetNomove", "PPointFeetNomove", sen_pfnm, params_pfnm); + // 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(); + Vector7d extr_pose; extr_pose << i_p_im, i_q_m.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; @@ -293,16 +304,23 @@ int main (int argc, char **argv) { sensor_pose->fixExtrinsics(); } - - // SETPRIOR RETRO-ENGINEERING // We are not using setPrior because of processors initial captures problems so we have to // - Manually create the first KF and its pose and velocity priors - // - call setOrigin on processors MotionProvider since the flag prior_is_set is not true when doing installProcessor (later) + // - call setOrigin on processors isMotion since the flag prior_is_set is not true when doing installProcessor (later) - VectorComposite x_origin("POV", {w_p_wm, w_qvec_wm, Vector3d::Zero()}); + ////////////////////// + // COMPUTE INITIAL STATE + TimeStamp t0(t_arr[0]); + Eigen::Map<Vector3d> w_p_wm(w_p_wm_arr); + Eigen::Map<Vector4d> w_qvec_m_init(w_q_m_arr); + w_qvec_m_init.normalize(); // not close enough to wolf eps sometimes + Quaterniond w_q_m_init(w_qvec_m_init); + Vector3d w_p_wi_init = w_p_wm + w_q_m_init*m_p_mi; + Quaterniond w_q_i_init = w_q_m_init*m_q_i; + VectorComposite x_origin("POV", {w_p_wi_init, w_q_i_init.coeffs(), 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); + // FrameBasePtr KF1 = problem->setPriorFactor(x_origin, std_origin, t0); // needed to anchor the problem FrameBasePtr KF1 = problem->setPriorInitialGuess(x_origin, t0); // if mocap used proc_imu->setOrigin(KF1); @@ -317,29 +335,25 @@ int main (int argc, char **argv) { 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(); - - - /////////////////////////////////////////// - // process measurements in sequential order - double ts_since_last_kf = 0; - std::vector<Vector3d> i_p_il_vec_prev; - std::vector<Vector4d> i_qvec_l_vec_prev; - std::vector<bool> feet_in_contact_prev; - ////////////////////////////////////////// - // 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* o_p_oi_fbk_carr = new double[3*N]; + double* o_q_i_fbk_carr = new double[4*N]; + double* o_v_oi_fbk_carr = new double[3*N]; double* imu_bias_fbk_carr = new double[6*N]; - double* extr_mocap_fbk_carr = new double[7*N]; + double* i_pose_im_fbk_carr = new double[7*N]; + + // covariances computed on the fly + std::vector<Vector3d> Qp_fbk_v; Qp_fbk_v.push_back(Vector3d::Zero()); + std::vector<Vector3d> Qo_fbk_v; Qo_fbk_v.push_back(Vector3d::Zero()); + std::vector<Vector3d> Qv_fbk_v; Qv_fbk_v.push_back(Vector3d::Zero()); + std::vector<Vector6d> Qbi_fbk_v; Qbi_fbk_v.push_back(Vector6d::Zero()); + std::vector<Vector6d> Qm_fbk_v; Qm_fbk_v.push_back(Vector6d::Zero()); + std::vector<Vector3d> i_omg_oi_v; ////////////////////////////////////////// @@ -351,154 +365,154 @@ int main (int argc, char **argv) { //////////////////////////////////// // 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']; + 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']; - //////////////////////////////////// - //////////////////////////////////// + + ////////////// + // PROCESS IMU + ////////////// // 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<Matrix<double,4, 1>> contact_gtr(contact_arr+4*i); // int conversion does not work! - // Eigen::Map<Matrix<double,12, 1>> b_p_bl_mocap(b_p_bl_mocap_arr+12*i); // int conversion does not work! - 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 - + Eigen::Map<Vector3d> i_omg_oi(i_omg_oi_arr+3*i); // 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, sen_imu->getNoiseCov()); + CImu->process(); + ////////////// + ////////////// - //////////////////////////////////// - // Kinematics + forces - // SE3 o_T_i(o_q_i_curr, Vector3d::Zero()); - // Matrix3d o_R_i = o_T_i.rotation(); - // Matrix3d i_R_o = o_R_i.transpose(); - // Vector3d i_v_oi_curr = i_R_o * o_v_oi_curr; - // Vector3d i_acc = imu_acc + i_R_o * gravity(); - // Vector3d i_asp_i = i_acc - i_omg_oi_unbiased.cross(i_v_oi_curr); - - // VectorXd q(19); q << 0,0,0, o_q_i_curr.coeffs(), qa; - // VectorXd dq(18); dq << i_v_oi_curr, i_omg_oi_unbiased, dqa; - // VectorXd ddq(model.nv); ddq.setZero(); - // ddq.head<3>() = i_asp_i; - // // TODO: add other terms to compute forces (ddqa...) - - // // update and retrieve kinematics - // forwardKinematics(model, data, q); - // updateFramePlacements(model, data); - - // // compute all linear jacobians in feet frames (only for quadruped) - // MatrixXd Jlinvel(12, model.nv); Jlinvel.setZero(); - // for (unsigned int i_ee=0; i_ee < nbc; i_ee++){ - // MatrixXd Jee(6, model.nv); Jee.setZero(); - // computeFrameJacobian(model, data, q, ee_ids[i_ee], Jee); - // Jlinvel.block(3*i_ee, 0, 3, model.nv) = Jee.topRows<3>(); - // } - - // // estimate forces from torques - // VectorXd tau_cf = rnea(model, data, q, dq, ddq); // compute total torques applied on the joints (and free flyer) - // tau_cf.tail(model.nv-6) -= tau; // remove measured joint torque (not on the free flyer) - - // VectorXd forces = Jlinvel_reduced.transpose().lu().solve(tau_joints); // works only for exactly determined system, removing free flyer from the system -> 12x12 J mat - // Solve in Least square sense (3 ways): - // VectorXd forces = Jlinvel.transpose().bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(tau_cf); // SVD - // VectorXd l_forces = Jlinvel.transpose().colPivHouseholderQr().solve(tau_cf); // QR - // (A.transpose() * A).ldlt().solve(A.transpose() * b) // solve the normal equation (twice less accurate than other 2) - // Or else, retrieve from preprocessed dataset - // Eigen::Map<Matrix<double,12, 1>> l_forces(l_forces_arr+12*i); - - // Vector3d o_f_tot = Vector3d::Zero(); - // std::vector<Vector3d> l_f_l_vec; - // std::vector<Vector3d> o_f_l_vec; - // std::vector<Vector3d> i_p_il_vec; - // std::vector<Vector4d> i_qvec_l_vec; - // // needing relative kinematics measurements - // VectorXd q_static = q; q_static.head<7>() << 0,0,0, 0,0,0,1; - // VectorXd dq_static = dq; dq_static.head<6>() << 0,0,0, 0,0,0; - // forwardKinematics(model, data, q_static, dq_static); - // updateFramePlacements(model, data); - // // std::cout << "" << std::endl; - // for (unsigned int i_ee=0; i_ee < nbc; i_ee++){ - // // std::cout << i_ee << std::endl; - // auto b_T_l = data.oMf[ee_ids[i_ee]]; - - // // overides with value from mocap - // // std::cout << b_T_l.translation().transpose() << std::endl; - // b_T_l.translation(b_p_bl_mocap.segment<3>(3*i_ee)); - // // std::cout << b_T_l.translation().transpose() << std::endl; - - // auto i_T_l = i_T_b * b_T_l; - // Vector3d i_p_il = i_T_l.translation(); // meas - // Matrix3d i_R_l = i_T_l.rotation(); - // Vector4d i_qvec_l = Quaterniond(i_R_l).coeffs(); // meas - // i_p_il = i_p_il + i_R_l*l_p_lg; - - // Vector3d l_f_l = l_forces.segment(3*i_ee, 3); // meas - // // Vector3d o_f_l = o_R_i*i_R_l * l_f_l; // for contact test - - // l_f_l_vec.push_back(l_f_l); - // // o_f_l_vec.push_back(o_f_l); - // i_p_il_vec.push_back(i_p_il); - // i_qvec_l_vec.push_back(i_qvec_l); - // } - - CaptureImuPtr CImu = std::make_shared<CaptureImu>(ts, sen_imu, acc_gyr_meas, acc_gyr_cov); - CImu->process(); + //////////////// + // PROCESS MOCAP + //////////////// + // Get measurements + // retrieve traj data + 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 - // 1) detect feet in contact - // int nb_feet_in_contact = 0; - // std::unordered_map<int, Vector3d> kin_incontact; - // for (unsigned int i_ee=0; i_ee<nbc; i_ee++){ - // // basic contact detection based on normal foot vel, things break if no foot is in contact - // // std::cout << "F" << ee_names[i_ee] << " norm: " << wrench_meas_v[i_ee][i].norm() << std::endl; - // // nb_feet: just for debugging/testing kinematic factor - - // // if ((o_f_l_vec[i_ee](2) > fz_thresh) && (nb_feet_in_contact < nb_feet)){ - // if (contact_gtr(i_ee)){ - // nb_feet_in_contact++; - // kin_incontact.insert({i_ee, i_p_il_vec[i_ee]}); - // } - // } - - // CapturePointFeetNomovePtr CPF = std::make_shared<CapturePointFeetNomove>(ts, sen_pfnm, kin_incontact); - // CPF->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(); + //////////////// + //////////////// + + ////////////////////////////////// + // Kinematics + forces + // retrieve traj data + 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<Matrix<double,4, 1>> contact_gtr(contact_arr+4*i); // int conversion does not work! + // Eigen::Map<Matrix<double,12, 1>> b_p_bl_mocap(b_p_bl_mocap_arr+12*i); // int conversion does not work! + + qa = qa + delta_qa; - // ts_since_last_kf += dt; - // if ((solve_every_sec > 0) && (ts_since_last_kf >= solve_every_sec)){ - // // problem->print(4,true,true,true); - // auto kf = problem->emplaceFrame(ts); - // problem->keyFrameCallback(kf, nullptr, 0.0005); - // std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); - // std::cout << report << std::endl; - // ts_since_last_kf = 0; - // // std::cout << "Extr SPose: " << sensor_pose->getP()->getState().transpose() << " " << sensor_pose->getO()->getState().transpose() << std::endl; - // } + Matrix3d o_R_i = Quaterniond(o_q_i_curr).toRotationMatrix(); // IMU internal filter + + // Or else, retrieve from preprocessed dataset + Eigen::Map<Matrix<double,12, 1>> l_forces(l_forces_arr+12*i); + + std::vector<Vector3d> l_f_l_vec; + std::vector<Vector3d> o_f_l_vec; + std::vector<Vector3d> i_p_il_vec; + std::vector<Vector4d> i_qvec_l_vec; + // needing relative kinematics measurements + VectorXd q_static(19); q_static << 0,0,0, 0,0,0,1, qa; + VectorXd dq_static(18); dq_static << 0,0,0, 0,0,0, dqa; + forwardKinematics(model, data, q_static, dq_static); + updateFramePlacements(model, data); + + for (unsigned int i_ee=0; i_ee < nbc; i_ee++){ + auto b_T_l = data.oMf[ee_ids[i_ee]]; + + auto i_T_l = i_T_b * b_T_l; + Vector3d i_p_il = i_T_l.translation(); + Matrix3d i_R_l = i_T_l.rotation(); + Vector4d i_qvec_l = Quaterniond(i_R_l).coeffs(); + i_p_il = i_p_il + i_R_l*l_p_lg; + + Vector3d l_f_l = l_forces.segment(3*i_ee, 3); + Vector3d o_f_l = o_R_i*i_R_l * l_f_l; // for contact test + + l_f_l_vec.push_back(l_f_l); + o_f_l_vec.push_back(o_f_l); + i_p_il_vec.push_back(i_p_il); + i_qvec_l_vec.push_back(i_qvec_l); + } + + // Detect feet in contact + int nb_feet_in_contact = 0; + std::unordered_map<int, Vector7d> kin_incontact; + // std::cout << "" << std::endl; + for (unsigned int i_ee=0; i_ee<nbc; i_ee++){ + // basic contact detection based on normal foot vel, things break if no foot is in contact + // if ((o_f_l_vec[i_ee](2) > fz_thresh) && (nb_feet_in_contact < nb_feet)){ + // if ((contact_gtr[i_ee] > 0.5) && (nb_feet_in_contact < nb_feet)){ + if (contact_gtr[i_ee] > 0.5){ + nb_feet_in_contact++; + Vector7d i_pose_il; i_pose_il << i_p_il_vec[i_ee], i_qvec_l_vec[i_ee]; + kin_incontact.insert({i_ee, i_pose_il}); + } + } + + CapturePointFeetNomovePtr CPF = std::make_shared<CapturePointFeetNomove>(ts, sen_pfnm, kin_incontact); + CPF->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; + + auto kf_last = problem->getTrajectory()->getFrameMap().rbegin()->second; + + // compute covariances of KF and capture stateblocks + Eigen::MatrixXd Qp_fbk = Eigen::Matrix3d::Identity(); + Eigen::MatrixXd Qo_fbk = Eigen::Matrix3d::Identity(); // global or local? + Eigen::MatrixXd Qv_fbk = Eigen::Matrix3d::Identity(); + Eigen::MatrixXd Qbi_fbk = Eigen::Matrix6d::Identity(); + Eigen::MatrixXd Qmp_fbk = Eigen::Matrix3d::Identity(); // extr mocap + Eigen::MatrixXd Qmo_fbk = Eigen::Matrix3d::Identity(); // extr mocap + + if (compute_cov) + solver->computeCovariances(SolverManager::CovarianceBlocksToBeComputed::ALL); // should not be computed every time !! see below + problem->getCovarianceBlock(kf_last->getStateBlock('P'), Qp_fbk); + problem->getCovarianceBlock(kf_last->getStateBlock('O'), Qo_fbk); + problem->getCovarianceBlock(kf_last->getStateBlock('V'), Qv_fbk); + + CaptureBasePtr cap_imu = kf_last->getCaptureOf(sen_imu); + if (compute_cov) + solver->computeCovariances(cap_imu->getStateBlockVec()); // not computed by ALL and destroys other computed covs -> issue to raise + problem->getCovarianceBlock(cap_imu->getSensorIntrinsic(), Qbi_fbk); + + std::vector<StateBlockPtr> extr_sb_vec = {sensor_pose->getP(), sensor_pose->getO()}; + if (compute_cov) + solver->computeCovariances(extr_sb_vec); // not computed by ALL and destroys other computed covs -> issue to raise + problem->getCovarianceBlock(sensor_pose->getP(), Qmp_fbk); + problem->getCovarianceBlock(sensor_pose->getO(), Qmo_fbk); + + // Retrieve diagonals + Vector3d Qp_fbk_diag = Qp_fbk.diagonal(); + Vector3d Qo_fbk_diag = Qo_fbk.diagonal(); + Vector3d Qv_fbk_diag = Qv_fbk.diagonal(); + Vector6d Qbi_fbk_diag = Qbi_fbk.diagonal(); + Vector6d Qm_fbk_diag; Qm_fbk_diag << Qmp_fbk.diagonal(), Qmo_fbk.diagonal(); + + Qp_fbk_v.push_back(Qp_fbk_diag); + Qo_fbk_v.push_back(Qo_fbk_diag); + Qv_fbk_v.push_back(Qv_fbk_diag); + Qbi_fbk_v.push_back(Qbi_fbk_diag); + Qm_fbk_v.push_back(Qm_fbk_diag); + nb_kf = problem->getTrajectory()->getFrameMap().size(); } @@ -509,27 +523,23 @@ int main (int argc, char **argv) { 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(); + 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; + Vector3d o_v_ob = o_v_oi + o_R_i * i_omg_oi_unbiased.cross(i_p_ib); imu_bias = sen_imu->getIntrinsic()->getState(); - Vector7d extr_mocap_est; extr_mocap_est << sensor_pose->getP()->getState(), sensor_pose->getO()->getState(); + Vector7d i_pose_im_fbk; i_pose_im_fbk << 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(o_p_oi_fbk_carr+3*i, o_p_oi.data(), 3*sizeof(double)); + mempcpy(o_q_i_fbk_carr +4*i, o_qvec_i.data(), 4*sizeof(double)); + mempcpy(o_v_oi_fbk_carr+3*i, o_v_oi.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); + mempcpy(i_pose_im_fbk_carr+7*i, i_pose_im_fbk.data(), 7*sizeof(double)); } @@ -545,8 +555,12 @@ int main (int argc, char **argv) { double* o_p_ob_carr = new double[3*N]; double* o_q_b_carr = new double[4*N]; + double* o_v_ob_carr = new double[3*N]; + double* o_p_oi_carr = new double[3*N]; + double* o_q_i_carr = new double[4*N]; + double* o_v_oi_carr = new double[3*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]; @@ -556,20 +570,20 @@ int main (int argc, char **argv) { 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; + Vector3d o_v_ob = o_v_oi + o_R_i * i_omg_oi_unbiased.cross(i_p_ib); 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(o_p_oi_carr+3*i, o_p_oi.data(), 3*sizeof(double)); + mempcpy(o_q_i_carr +4*i, o_qvec_i.data(), 4*sizeof(double)); + mempcpy(o_v_oi_carr+3*i, o_v_oi.data(), 3*sizeof(double)); mempcpy(imu_bias_carr+6*i, imu_bias.data(), 6*sizeof(double)); } @@ -582,6 +596,13 @@ int main (int argc, char **argv) { double* Qv_carr = new double[3*Nkf]; double* Qbi_carr = new double[6*Nkf]; double* Qm_carr = new double[6*Nkf]; + // feedback covariances + double* Qp_fbk_carr = new double[3*Nkf]; + double* Qo_fbk_carr = new double[3*Nkf]; + double* Qv_fbk_carr = new double[3*Nkf]; + double* Qbi_fbk_carr = new double[6*Nkf]; + double* Qm_fbk_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]; @@ -600,19 +621,15 @@ int main (int argc, char **argv) { 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 + if (compute_cov) + 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 + if (compute_cov) + 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 @@ -628,43 +645,23 @@ int main (int argc, char **argv) { memcpy(Qbi_carr + 6*i, Qbi_diag.data(), 6*sizeof(double)); memcpy(Qm_carr + 6*i, Qm_diag.data(), 6*sizeof(double)); + // Recover feedback covariances + memcpy(Qp_fbk_carr + 3*i, Qp_fbk_v[i].data(), 3*sizeof(double)); + memcpy(Qo_fbk_carr + 3*i, Qo_fbk_v[i].data(), 3*sizeof(double)); + memcpy(Qv_fbk_carr + 3*i, Qv_fbk_v[i].data(), 3*sizeof(double)); + memcpy(Qbi_fbk_carr + 6*i, Qbi_fbk_v[i].data(), 6*sizeof(double)); + memcpy(Qm_fbk_carr + 6*i, Qm_fbk_v[i].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 @@ -672,22 +669,35 @@ int main (int argc, char **argv) { 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, "o_q_i_imu", o_q_i_arr, {N,3}, "a"); cnpy::npz_save(out_npz_file_path, "qa", qa_arr, {N,12}, "a"); + cnpy::npz_save(out_npz_file_path, "i_omg_oi", i_omg_oi_arr, {N,3}, "a"); - // save estimates + // Online 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_oi_fbk", o_p_oi_fbk_carr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_i_fbk", o_q_i_fbk_carr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "o_v_oi_fbk", o_v_oi_fbk_carr, {N,3}, "a"); + // offline states 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"); + cnpy::npz_save(out_npz_file_path, "o_p_oi", o_p_oi_carr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_i", o_q_i_carr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "o_v_oi", o_v_oi_carr, {N,3}, "a"); + + // imu states + cnpy::npz_save(out_npz_file_path, "o_p_oi", o_p_oi_carr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_i", o_q_i_carr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "o_v_oi", o_v_oi_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"); + cnpy::npz_save(out_npz_file_path, "i_pose_im_fbk", i_pose_im_fbk_carr, {N,7}, "a"); // covariances cnpy::npz_save(out_npz_file_path, "tkf", tkf_carr, {Nkf}, "a"); @@ -696,6 +706,11 @@ int main (int argc, char **argv) { 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, "Qp_fbk", Qp_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qo_fbk", Qo_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qv_fbk", Qv_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qbi_fbk", Qbi_fbk_carr, {Nkf,6}, "a"); + cnpy::npz_save(out_npz_file_path, "Qm_fbk", Qm_fbk_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_mocap_imu.cpp b/demos/solo_imu_mocap.cpp similarity index 69% rename from demos/solo_mocap_imu.cpp rename to demos/solo_imu_mocap.cpp index 19f8dfaa700dbcb7876dfd2f3587bb996d68ab1b..1ffabd4c847bb9f3f0954f5eb70862cc20eedf00 100644 --- a/demos/solo_mocap_imu.cpp +++ b/demos/solo_imu_mocap.cpp @@ -67,9 +67,6 @@ #include "bodydynamics/internal/config.h" -// UTILS -#include "mcapi_utils.h" - using namespace Eigen; using namespace wolf; @@ -88,6 +85,7 @@ int main (int argc, char **argv) { // Ceres setup int max_num_iterations = config["max_num_iterations"].as<int>(); + bool compute_cov = config["compute_cov"].as<bool>(); // priors double std_prior_p = config["std_prior_p"].as<double>(); @@ -97,10 +95,14 @@ int main (int argc, char **argv) { double std_abs_bias_gyro = config["std_abs_bias_gyro"].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>>(); - Eigen::Map<Vector3d> b_p_bi(b_p_bi_vec.data()); - Eigen::Map<Vector4d> b_qvec_i(b_q_i_vec.data()); + std::vector<double> i_p_im_vec = config["i_p_im"].as<std::vector<double>>(); + Eigen::Map<Vector3d> i_p_im(i_p_im_vec.data()); + std::vector<double> i_q_m_vec = config["i_q_m"].as<std::vector<double>>(); + Eigen::Map<Vector4d> i_qvec_m(i_q_m_vec.data()); + std::vector<double> m_p_mb_vec = config["m_p_mb"].as<std::vector<double>>(); + Eigen::Map<Vector3d> m_p_mb(m_p_mb_vec.data()); + std::vector<double> m_q_b_vec = config["m_q_b"].as<std::vector<double>>(); + Eigen::Map<Vector4d> m_qvec_b(m_q_b_vec.data()); // MOCAP double std_pose_p = config["std_pose_p"].as<double>(); @@ -115,21 +117,38 @@ int main (int argc, char **argv) { 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(); + // MOCAP to IMU transform + Quaterniond i_q_m(i_qvec_m); + i_q_m.normalize(); + assert(i_q_m.normalized().isApprox(i_q_m)); + SE3 i_T_m(i_q_m, i_p_im); + Matrix3d i_R_m = i_T_m.rotation(); + + // IMU to MOCAP transform + SE3 m_T_i = i_T_m.inverse(); + Vector3d m_p_mi = m_T_i.translation(); + Quaterniond m_q_i = Quaterniond(m_T_i.rotation()); + + // MOCAP to BASE transform + Quaterniond m_q_b(m_qvec_b); + m_q_b.normalize(); + assert(m_q_b.normalized().isApprox(m_q_b)); + SE3 m_T_b(m_q_b, m_p_mb); + // Matrix3d m_R_b = m_T_b.rotation(); + + // IMU to BASE transform (composition) + SE3 i_T_b = i_T_m*m_T_b; Vector3d i_p_ib = i_T_b.translation(); - Matrix3d i_R_b = i_T_b.rotation(); + 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 w_p_wm_npyarr = arr_map["w_p_wm"]; + cnpy::NpyArray w_q_m_npyarr = arr_map["w_q_m"]; 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"]; @@ -142,20 +161,39 @@ int main (int argc, char **argv) { 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 contact_npyarr = arr_map["contacts"]; // cnpy::NpyArray b_p_bl_mocap_npyarr = arr_map["b_p_bl_mocap"]; + // std::cout << "\n\n\n\n\n\n" << std::endl; + // std::cout << data_file_path << std::endl; + // std::cout << "\n\n\n\n\n\n" << std::endl; + // std::cout << w_p_wm_npyarr.shape[0] << ", " << w_p_wm_npyarr.shape[1] << std::endl; + // std::cout << w_p_wm_npyarr.word_size << std::endl; + // std::cout << w_p_wm_npyarr.fortran_order << std::endl; + // std::cout << w_p_wm_npyarr.num_vals << std::endl; + // std::cout << "\n\n\n\n\n\n" << std::endl; + // std::cout << w_q_m_npyarr.shape[0] << ", " << w_q_m_npyarr.shape[1] << std::endl; + // std::cout << w_q_m_npyarr.word_size << std::endl; + // std::cout << w_q_m_npyarr.fortran_order << std::endl; + // std::cout << w_q_m_npyarr.num_vals << std::endl; + // std::cout << "\n\n\n\n\n\n" << std::endl; + // std::cout << i_omg_oi_npyarr.shape[0] << ", " << i_omg_oi_npyarr.shape[1] << std::endl; + // std::cout << i_omg_oi_npyarr.word_size << std::endl; + // std::cout << i_omg_oi_npyarr.fortran_order << std::endl; + // std::cout << i_omg_oi_npyarr.num_vals << std::endl; + // std::cout << "\n\n\n\n\n\n" << std::endl; + // std::cout << "\n\n\n\n\n\n" << std::endl; + // 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* 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>(); @@ -170,7 +208,8 @@ int main (int argc, char **argv) { // 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); + unsigned int N_max = (max_t/dt); + N = N < N_max ? N : N_max; } ///////////////////////// @@ -189,11 +228,9 @@ int main (int argc, char **argv) { ////////////////////// // 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 + Eigen::Map<Vector4d> w_qvec_m_init(w_q_m_arr); + w_qvec_m_init.normalize(); // not close enough to wolf eps sometimes ////////////////////// @@ -213,7 +250,7 @@ int main (int argc, char **argv) { 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(); + Vector7d extr_pose; extr_pose << i_p_im, i_q_m.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; @@ -230,12 +267,13 @@ int main (int argc, char **argv) { sensor_pose->fixExtrinsics(); } - Matrix3d w_R_m_init = q2R(w_qvec_wm); - Vector3d w_p_wi_init = w_p_wm + w_R_m_init*b_p_bi; - VectorComposite x_origin("POV", {w_p_wi_init, w_qvec_wm, Vector3d::Zero()}); + Quaterniond w_q_m_init(w_qvec_m_init); + Vector3d w_p_wi_init = w_p_wm + w_q_m_init*m_p_mi; + Quaterniond w_q_i_init = w_q_m_init*m_q_i; + VectorComposite x_origin("POV", {w_p_wi_init, w_q_i_init.coeffs(), 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->setPriorFactor(x_origin, std_origin, t0); FrameBasePtr KF1 = problem->setPriorInitialGuess(x_origin, t0); // if mocap used proc_imu->setOrigin(KF1); @@ -250,24 +288,25 @@ int main (int argc, char **argv) { 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* o_p_oi_fbk_carr = new double[3*N]; + double* o_q_i_fbk_carr = new double[4*N]; + double* o_v_oi_fbk_carr = new double[3*N]; double* imu_bias_fbk_carr = new double[6*N]; - double* extr_mocap_fbk_carr = new double[7*N]; + double* i_pose_im_fbk_carr = new double[7*N]; + // covariances computed on the fly + std::vector<Vector3d> Qp_fbk_v; Qp_fbk_v.push_back(Vector3d::Zero()); + std::vector<Vector3d> Qo_fbk_v; Qo_fbk_v.push_back(Vector3d::Zero()); + std::vector<Vector3d> Qv_fbk_v; Qv_fbk_v.push_back(Vector3d::Zero()); std::vector<Vector6d> Qbi_fbk_v; Qbi_fbk_v.push_back(Vector6d::Zero()); + std::vector<Vector6d> Qm_fbk_v; Qm_fbk_v.push_back(Vector6d::Zero()); // std::vector<Vector3d> i_omg_oi_v; @@ -277,15 +316,14 @@ int main (int argc, char **argv) { for (unsigned int i=0; i < N; i++){ TimeStamp ts(t_arr[i]); - //////////////////////////////////// - //////////////////////////////////// + + ////////////// + // PROCESS IMU + ////////////// // 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<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); @@ -293,44 +331,80 @@ int main (int argc, char **argv) { 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; + ////////////// + ////////////// + + + //////////////// + // PROCESS MOCAP + //////////////// + // retrieve traj data + 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 + 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 ){ + if (problem->getTrajectory()->size() > nb_kf ) + { std::string report = solver->solve(SolverManager::ReportVerbosity::BRIEF); std::cout << ts << " "; std::cout << report << std::endl; // recover covariances at this point - auto kf_last = problem->getTrajectory()->getFrameMap().rbegin()->second; + auto kf_last = problem->getTrajectory()->getLastFrame(); - CaptureBasePtr cap_imu = kf_last->getCaptureOf(sen_imu); - + // compute covariances of KF and capture stateblocks + Eigen::MatrixXd Qp_fbk = Eigen::Matrix3d::Identity(); + Eigen::MatrixXd Qo_fbk = Eigen::Matrix3d::Identity(); // global or local? + Eigen::MatrixXd Qv_fbk = Eigen::Matrix3d::Identity(); Eigen::MatrixXd Qbi_fbk = Eigen::Matrix6d::Identity(); - solver->computeCovariances(cap_imu->getStateBlockVec()); // not computed by ALL and destroys other computed covs -> issue to raise - problem->getCovarianceBlock(cap_imu->getSensorIntrinsic(), Qbi_fbk); - Vector6d Qbi_fbk_diag = Qbi_fbk.diagonal(); + Eigen::MatrixXd Qmp_fbk = Eigen::Matrix3d::Identity(); // extr mocap + Eigen::MatrixXd Qmo_fbk = Eigen::Matrix3d::Identity(); // extr mocap + + if (compute_cov) + solver->computeCovariances(SolverManager::CovarianceBlocksToBeComputed::ALL); // should not be computed every time !! see below + problem->getCovarianceBlock(kf_last->getStateBlock('P'), Qp_fbk); + problem->getCovarianceBlock(kf_last->getStateBlock('O'), Qo_fbk); + problem->getCovarianceBlock(kf_last->getStateBlock('V'), Qv_fbk); + CaptureBasePtr cap_imu = kf_last->getCaptureOf(sen_imu); + if (compute_cov) + solver->computeCovariances(cap_imu->getStateBlockVec()); // not computed by ALL and destroys other computed covs -> issue to raise + problem->getCovarianceBlock(cap_imu->getSensorIntrinsic(), Qbi_fbk); - Qbi_fbk_v.push_back(Qbi_fbk_diag); + std::vector<StateBlockPtr> extr_sb_vec = {sensor_pose->getP(), sensor_pose->getO()}; + if (compute_cov) + solver->computeCovariances(extr_sb_vec); // not computed by ALL and destroys other computed covs -> issue to raise + problem->getCovarianceBlock(sensor_pose->getP(), Qmp_fbk); + problem->getCovarianceBlock(sensor_pose->getO(), Qmo_fbk); - // std::cout << "Qbi_fbk: \n" << Qbi_fbk.topLeftCorner<3,3>() << std::endl; - // std::cout << "Qbi_fbk: \n" << Qbi_fbk << std::endl; + // Retrieve diagonals + Vector3d Qp_fbk_diag = Qp_fbk.diagonal(); + Vector3d Qo_fbk_diag = Qo_fbk.diagonal(); + Vector3d Qv_fbk_diag = Qv_fbk.diagonal(); + Vector6d Qbi_fbk_diag = Qbi_fbk.diagonal(); + Vector6d Qm_fbk_diag; Qm_fbk_diag << Qmp_fbk.diagonal(), Qmo_fbk.diagonal(); + Qp_fbk_v.push_back(Qp_fbk_diag); + Qo_fbk_v.push_back(Qo_fbk_diag); + Qv_fbk_v.push_back(Qv_fbk_diag); + Qbi_fbk_v.push_back(Qbi_fbk_diag); + Qm_fbk_v.push_back(Qm_fbk_diag); - nb_kf++; + nb_kf = problem->getTrajectory()->getFrameMap().size(); } // Store current state estimation @@ -346,23 +420,21 @@ int main (int argc, char **argv) { 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*i_R_b*b_p_bi); + Vector3d o_v_ob = o_v_oi + o_R_i * i_omg_oi_unbiased.cross(i_p_im); // Vector3d o_p_ob = o_p_oi; // Vector3d o_v_ob = o_v_oi; imu_bias = sen_imu->getIntrinsic()->getState(); - // imu_bias = sen_imu->getIntrinsic(ts)->getState(); - Vector7d extr_mocap_est; extr_mocap_est << sensor_pose->getP()->getState(), sensor_pose->getO()->getState(); + Vector7d i_pose_im_fbk; i_pose_im_fbk << 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(o_p_oi_fbk_carr+3*i, o_p_oi.data(), 3*sizeof(double)); + mempcpy(o_q_i_fbk_carr +4*i, o_qvec_i.data(), 4*sizeof(double)); + mempcpy(o_v_oi_fbk_carr+3*i, o_v_oi.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); + mempcpy(i_pose_im_fbk_carr+7*i, i_pose_im_fbk.data(), 7*sizeof(double)); } @@ -378,8 +450,12 @@ int main (int argc, char **argv) { double* o_p_ob_carr = new double[3*N]; double* o_q_b_carr = new double[4*N]; + double* o_v_ob_carr = new double[3*N]; + double* o_p_oi_carr = new double[3*N]; + double* o_q_i_carr = new double[4*N]; + double* o_v_oi_carr = new double[3*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]; @@ -389,26 +465,26 @@ int main (int argc, char **argv) { 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; + Matrix3d o_R_b = o_R_i * i_R_m; 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; + Vector3d o_p_ob = o_p_oi + o_R_i * i_p_im; + Vector3d o_v_ob = o_v_oi + o_R_i * i_omg_oi_unbiased.cross(i_p_im); 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(o_p_oi_carr+3*i, o_p_oi.data(), 3*sizeof(double)); + mempcpy(o_q_i_carr +4*i, o_qvec_i.data(), 4*sizeof(double)); + mempcpy(o_v_oi_carr+3*i, o_v_oi.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(); + unsigned int Nkf = problem->getTrajectory()->size(); double* tkf_carr = new double[1*Nkf]; double* Qp_carr = new double[3*Nkf]; double* Qo_carr = new double[3*Nkf]; @@ -416,14 +492,19 @@ int main (int argc, char **argv) { double* Qbi_carr = new double[6*Nkf]; double* Qm_carr = new double[6*Nkf]; // feedback covariances + double* Qp_fbk_carr = new double[3*Nkf]; + double* Qo_fbk_carr = new double[3*Nkf]; + double* Qv_fbk_carr = new double[3*Nkf]; double* Qbi_fbk_carr = new double[6*Nkf]; + double* Qm_fbk_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; + for (auto elt: problem->getTrajectory()->getFrameMap()) + { + std::cout << "Traj " << i << "/" << problem->getTrajectory()->size() << std::endl; tkf_carr[i] = elt.first.get(); auto kf = elt.second; VectorComposite kf_state = kf->getState(); @@ -436,7 +517,8 @@ int main (int argc, char **argv) { 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 + if (compute_cov) + 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); @@ -444,11 +526,12 @@ int main (int argc, char **argv) { 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 + if (compute_cov) + 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 + if (compute_cov) + 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 @@ -465,7 +548,11 @@ int main (int argc, char **argv) { memcpy(Qm_carr + 6*i, Qm_diag.data(), 6*sizeof(double)); // Recover feedback covariances + memcpy(Qp_fbk_carr + 3*i, Qp_fbk_v[i].data(), 3*sizeof(double)); + memcpy(Qo_fbk_carr + 3*i, Qo_fbk_v[i].data(), 3*sizeof(double)); + memcpy(Qv_fbk_carr + 3*i, Qv_fbk_v[i].data(), 3*sizeof(double)); memcpy(Qbi_fbk_carr + 6*i, Qbi_fbk_v[i].data(), 6*sizeof(double)); + memcpy(Qm_fbk_carr + 6*i, Qm_fbk_v[i].data(), 6*sizeof(double)); // Factor errors @@ -477,16 +564,6 @@ int main (int argc, char **argv) { 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(); } @@ -514,20 +591,28 @@ int main (int argc, char **argv) { 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"); + cnpy::npz_save(out_npz_file_path, "i_omg_oi", i_omg_oi_arr, {N,3}, "a"); - // save estimates + // Online 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_oi_fbk", o_p_oi_fbk_carr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_i_fbk", o_q_i_fbk_carr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "o_v_oi_fbk", o_v_oi_fbk_carr, {N,3}, "a"); + // offline states 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"); + cnpy::npz_save(out_npz_file_path, "o_p_oi", o_p_oi_carr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_i", o_q_i_carr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "o_v_oi", o_v_oi_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"); + cnpy::npz_save(out_npz_file_path, "i_pose_im_fbk", i_pose_im_fbk_carr, {N,7}, "a"); // covariances cnpy::npz_save(out_npz_file_path, "tkf", tkf_carr, {Nkf}, "a"); @@ -535,8 +620,12 @@ int main (int argc, char **argv) { 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, "Qbi_fbk", Qbi_fbk_carr, {Nkf,6}, "a"); cnpy::npz_save(out_npz_file_path, "Qm", Qm_carr, {Nkf,6}, "a"); + cnpy::npz_save(out_npz_file_path, "Qp_fbk", Qp_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qo_fbk", Qo_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qv_fbk", Qv_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qbi_fbk", Qbi_fbk_carr, {Nkf,6}, "a"); + cnpy::npz_save(out_npz_file_path, "Qm_fbk", Qm_fbk_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_kine_mocap.cpp b/demos/solo_kine_mocap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f3927500e2298866b1b31788a1d2c6d1e1a3608 --- /dev/null +++ b/demos/solo_kine_mocap.cpp @@ -0,0 +1,640 @@ +//--------LICENSE_START-------- +// +// Copyright (C) 2020,2021,2022 Institut de Robòtica i Informà tica Industrial, CSIC-UPC. +// Authors: Joan Solà Ortega (jsola@iri.upc.edu) +// All rights reserved. +// +// This file is part of WOLF +// WOLF is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +//--------LICENSE_END-------- +#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" +#include "bodydynamics/sensor/sensor_point_feet_nomove.h" +#include "bodydynamics/processor/processor_point_feet_nomove.h" +#include "bodydynamics/capture/capture_point_feet_nomove.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"); + 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>(); + + // robot + std::string robot_urdf = config["robot_urdf"].as<std::string>(); + int dimc = config["dimc"].as<int>(); + int nb_feet = config["nb_feet"].as<int>(); + + // 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_foot_nomove = config["std_foot_nomove"].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>(); + + // IMU + double std_abs_bias_acc = config["std_abs_bias_acc"].as<double>(); + double std_abs_bias_gyro = config["std_abs_bias_gyro"].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()); + + // base extrinsics + 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>>(); + Eigen::Map<Vector3d> b_p_bi(b_p_bi_vec.data()); + Eigen::Map<Vector4d> b_qvec_i(b_q_i_vec.data()); + + // contacts + std::vector<double> l_p_lg_vec = config["l_p_lg"].as<std::vector<double>>(); + 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["contacts"]; + // 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){ + unsigned int N_max = (unsigned int)max_t/dt; + N = N < N_max ? N : N_max; + } + std::cout << "N: " << N << std::endl; + + // Load the urdf model + Model model; + pinocchio::urdf::buildModel(robot_urdf, JointModelFreeFlyer(), model); + std::cout << "model name: " << model.name << std::endl; + Data data(model); + std::vector<std::string> ee_names = {"FL_ANKLE", "FR_ANKLE", "HL_ANKLE", "HR_ANKLE"}; + unsigned int nbc = ee_names.size(); + + // Recover end effector frame ids + std::vector<int> ee_ids; + std::cout << "Frame ids" << std::endl; + for (auto ee_name: ee_names){ + ee_ids.push_back(model.getFrameId(ee_name)); + std::cout << ee_name << std::endl; + } + + ///////////////////////// + // WOLF enters the scene + // SETUP PROBLEM/SENSORS/PROCESSORS + std::string bodydynamics_root_dir = _WOLF_BODYDYNAMICS_ROOT_DIR; + + ProblemPtr problem = Problem::create("PO", 3); + // 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 + + // initial configuration + Eigen::Map<Matrix<double,12, 1>> qa(qa_arr); + Eigen::Map<Matrix<double,12, 1>> dqa(dqa_arr); + VectorXd q(19); q << 0,0,0, o_q_i, qa; // TODO: put current base orientation estimate? YES + VectorXd dq(18); dq << 0,0,0, i_omg_oi, dqa; // TODO: put current base velocity estimate? YES + + ////////////////////// + + // CERES WRAPPER + SolverCeresPtr solver = std::make_shared<SolverCeres>(problem); + solver->getSolverOptions().max_num_iterations = max_num_iterations; + + //===================================================== INITIALIZATION + // SENSOR + PROCESSOR POINT FEET NOMOVE + ParamsSensorPointFeetNomovePtr intr_pfn = std::make_shared<ParamsSensorPointFeetNomove>(); + intr_pfn->std_foot_nomove_ = std_foot_nomove; + VectorXd extr; // default size for dynamic vector is 0-0 -> what we need + SensorBasePtr sen_pfnm_base = problem->installSensor("SensorPointFeetNomove", "SenPfnm", extr, intr_pfn); + SensorPointFeetNomovePtr sen_pfnm = std::static_pointer_cast<SensorPointFeetNomove>(sen_pfnm_base); + ParamsProcessorPointFeetNomovePtr params_pfnm = std::make_shared<ParamsProcessorPointFeetNomove>(); + params_pfnm->voting_active = true; + params_pfnm->time_tolerance = 0.001; + params_pfnm->max_time_vote = 0.19999999; + ProcessorBasePtr proc_pfnm_base = problem->installProcessor("ProcessorPointFeetNomove", "PPointFeetNomove", sen_pfnm, params_pfnm); + + + // 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(); + } + + Matrix3d w_R_m_init = q2R(w_qvec_wm); + Vector3d w_p_wi_init = w_p_wm + w_R_m_init*b_p_bi; + + VectorComposite x_origin("PO", {w_p_wi_init, w_qvec_wm}); + VectorComposite std_origin("PO", {std_prior_p*Vector3d::Ones(), std_prior_o*Vector3d::Ones()}); + // FrameBasePtr KF1 = problem->setPriorFactor(x_origin, std_origin, t0, 0.0005); + FrameBasePtr KF1 = problem->setPriorInitialGuess(x_origin, t0, time_tolerance_mocap); // if mocap used + + + ////////////////////////////////////////// + // 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* i_pose_ib_fbk_carr = new double[7*N]; + + // covariances computed on the fly + std::vector<Vector3d> Qp_fbk_v; Qp_fbk_v.push_back(Vector3d::Zero()); + std::vector<Vector3d> Qo_fbk_v; Qo_fbk_v.push_back(Vector3d::Zero()); + std::vector<Vector3d> Qv_fbk_v; Qv_fbk_v.push_back(Vector3d::Zero()); + std::vector<Vector6d> Qbi_fbk_v; Qbi_fbk_v.push_back(Vector6d::Zero()); + std::vector<Vector6d> Qm_fbk_v; Qm_fbk_v.push_back(Vector6d::Zero()); + + // + 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]); + + //////////////// + // PROCESS MOCAP + //////////////// + // Get measurements + // retrieve traj data + 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 + + // 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(); + //////////////// + //////////////// + + ///////////////////// + // PROCESS KINEMATICS + ///////////////////// + 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<Matrix<double,4, 1>> contact_gtr(contact_arr+4*i); // int conversion does not work! + + + // Or else, retrieve from preprocessed dataset + Eigen::Map<Matrix<double,12, 1>> l_forces(l_forces_arr+12*i); + + Vector3d o_f_tot = Vector3d::Zero(); + std::vector<Vector3d> l_f_l_vec; + // std::vector<Vector3d> o_f_l_vec; + std::vector<Vector3d> i_p_il_vec; + std::vector<Vector4d> i_qvec_l_vec; + // needing relative kinematics measurements + VectorXd q_static(19); q_static << 0,0,0, 0,0,0,1, qa; + VectorXd dq_static(18); dq_static << 0,0,0, 0,0,0, dqa; + forwardKinematics(model, data, q_static, dq_static); + updateFramePlacements(model, data); + + for (unsigned int i_ee=0; i_ee < nbc; i_ee++){ + auto b_T_l = data.oMf[ee_ids[i_ee]]; + + auto i_T_l = i_T_b * b_T_l; + Vector3d i_p_il = i_T_l.translation(); // meas + Matrix3d i_R_l = i_T_l.rotation(); + Vector4d i_qvec_l = Quaterniond(i_R_l).coeffs(); // meas + i_p_il = i_p_il + i_R_l*l_p_lg; + + Vector3d l_f_l = l_forces.segment(3*i_ee, 3); // meas + // Vector3d o_f_l = o_R_i*i_R_l * l_f_l; // for contact test + + l_f_l_vec.push_back(l_f_l); + // o_f_l_vec.push_back(o_f_l); + i_p_il_vec.push_back(i_p_il); + i_qvec_l_vec.push_back(i_qvec_l); + } + + // Detect feet in contact + int nb_feet_in_contact = 0; + std::unordered_map<int, Vector7d> kin_incontact; + // std::cout << "" << std::endl; + for (unsigned int i_ee=0; i_ee<nbc; i_ee++){ + // basic contact detection based on normal foot vel, things break if no foot is in contact + // if ((o_f_l_vec[i_ee](2) > fz_thresh) && (nb_feet_in_contact < nb_feet)){ + // if ((contact_gtr[i_ee] > 0.5) && (nb_feet_in_contact < nb_feet)){ + if (contact_gtr[i_ee] > 0.5){ + nb_feet_in_contact++; + Vector7d i_pose_il; i_pose_il << i_p_il_vec[i_ee], i_qvec_l_vec[i_ee]; + kin_incontact.insert({i_ee, i_pose_il}); + } + } + + + CapturePointFeetNomovePtr CPF = std::make_shared<CapturePointFeetNomove>(ts, sen_pfnm, kin_incontact); + CPF->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; + + // recover covariances at this point + auto kf_last = problem->getTrajectory()->getFrameMap().rbegin()->second; + + + // compute covariances of KF and capture stateblocks + Eigen::MatrixXd Qp_fbk = Eigen::Matrix3d::Identity(); + Eigen::MatrixXd Qo_fbk = Eigen::Matrix3d::Identity(); // global or local? + Eigen::MatrixXd Qv_fbk = Eigen::Matrix3d::Identity(); + Eigen::MatrixXd Qbi_fbk = Eigen::Matrix6d::Identity(); + Eigen::MatrixXd Qmp_fbk = Eigen::Matrix3d::Identity(); // extr mocap + Eigen::MatrixXd Qmo_fbk = Eigen::Matrix3d::Identity(); // extr mocap + + solver->computeCovariances(SolverManager::CovarianceBlocksToBeComputed::ALL); // should not be computed every time !! see below + problem->getCovarianceBlock(kf_last->getStateBlock('P'), Qp_fbk); + problem->getCovarianceBlock(kf_last->getStateBlock('O'), Qo_fbk); + // problem->getCovarianceBlock(kf_last->getStateBlock('V'), Qv_fbk); + + 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_fbk); + problem->getCovarianceBlock(sensor_pose->getO(), Qmo_fbk); + + + // Retrieve diagonals + Vector3d Qp_fbk_diag = Qp_fbk.diagonal(); + Vector3d Qo_fbk_diag = Qo_fbk.diagonal(); + Vector3d Qv_fbk_diag = Qv_fbk.diagonal(); + Vector6d Qbi_fbk_diag = Qbi_fbk.diagonal(); + Vector6d Qm_fbk_diag; Qm_fbk_diag << Qmp_fbk.diagonal(), Qmo_fbk.diagonal(); + Vector3d Qmo_fbk_diag = Qmo_fbk.diagonal(); + + Qp_fbk_v.push_back(Qp_fbk_diag); + Qo_fbk_v.push_back(Qo_fbk_diag); + Qv_fbk_v.push_back(Qv_fbk_diag); + Qbi_fbk_v.push_back(Qbi_fbk_diag); + Qm_fbk_v.push_back(Qm_fbk_diag); + + + nb_kf++; + } + + // Store current state estimation + VectorComposite state_fbk = problem->getState(); + // 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']; + Vector3d o_v_oi = Vector3d::Zero(); + + // 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.cross(i_p_ib); + // Vector3d o_p_ob = o_p_oi; + Vector3d o_v_ob = o_v_oi; + + Vector3d imu_bias = Vector3d::Zero(); + // imu_bias = sen_imu->getIntrinsic()->getState(); + // imu_bias = sen_imu->getIntrinsic(ts)->getState(); + Vector7d i_pose_ib_est; i_pose_ib_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(i_pose_ib_fbk_carr+7*i, i_pose_ib_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* o_v_ob_carr = new double[6*N]; + double* imu_bias_carr = new double[6*N]; + for (unsigned int i=0; i < N; i++) { + VectorComposite state_est = problem->getState(t_arr[i]); + Vector3d o_p_oi = state_est['P']; + Vector4d o_qvec_i = state_est['O']; + Vector3d o_v_oi = Vector3d::Zero(); + + 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]; + // feedback covariances + double* Qp_fbk_carr = new double[3*Nkf]; + double* Qo_fbk_carr = new double[3*Nkf]; + double* Qv_fbk_carr = new double[3*Nkf]; + double* Qbi_fbk_carr = new double[6*Nkf]; + double* Qm_fbk_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); + + 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); + + // 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)); + + // Recover feedback covariances + memcpy(Qp_fbk_carr + 3*i, Qp_fbk_v[i].data(), 3*sizeof(double)); + memcpy(Qo_fbk_carr + 3*i, Qo_fbk_v[i].data(), 3*sizeof(double)); + memcpy(Qv_fbk_carr + 3*i, Qv_fbk_v[i].data(), 3*sizeof(double)); + memcpy(Qbi_fbk_carr + 6*i, Qbi_fbk_v[i].data(), 6*sizeof(double)); + memcpy(Qm_fbk_carr + 6*i, Qm_fbk_v[i].data(), 6*sizeof(double)); + + i++; + } + + // problem->check(1); + + // 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"); + cnpy::npz_save(out_npz_file_path, "i_omg_oi", i_omg_oi_arr, {N,3}, "a"); + + // Online 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_oi_fbk", o_p_ob_fbk_carr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_i_fbk", o_q_b_fbk_carr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "o_v_oi_fbk", o_v_ob_fbk_carr, {N,3}, "a"); + // cnpy::npz_save(out_npz_file_path, "o_p_oi_fbk", o_p_oi_fbk_carr, {N,3}, "a"); + // cnpy::npz_save(out_npz_file_path, "o_q_i_fbk", o_q_i_fbk_carr, {N,4}, "a"); + // cnpy::npz_save(out_npz_file_path, "o_v_oi_fbk", o_v_oi_fbk_carr, {N,3}, "a"); + + // offline states + 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"); + cnpy::npz_save(out_npz_file_path, "o_p_oi", o_p_ob_carr, {N,3}, "a"); + cnpy::npz_save(out_npz_file_path, "o_q_i", o_q_b_carr, {N,4}, "a"); + cnpy::npz_save(out_npz_file_path, "o_v_oi", o_v_ob_carr, {N,3}, "a"); + // cnpy::npz_save(out_npz_file_path, "o_p_oi", o_p_oi_carr, {N,3}, "a"); + // cnpy::npz_save(out_npz_file_path, "o_q_i", o_q_i_carr, {N,4}, "a"); + // cnpy::npz_save(out_npz_file_path, "o_v_oi", o_v_oi_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, "i_pose_ib_fbk", i_pose_ib_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, "Qp_fbk", Qp_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qo_fbk", Qo_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qv_fbk", Qv_fbk_carr, {Nkf,3}, "a"); + cnpy::npz_save(out_npz_file_path, "Qbi_fbk", Qbi_fbk_carr, {Nkf,6}, "a"); + cnpy::npz_save(out_npz_file_path, "Qm_fbk", Qm_fbk_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 1867ec7a227dd3a3d623fc6db430a9cbb36d823b..7106f2fce6adf0893afce1f7434b83f41e162c1f 100644 --- a/demos/solo_real_estimation.yaml +++ b/demos/solo_real_estimation.yaml @@ -10,14 +10,17 @@ solve_end: True # Ceres setup max_num_iterations: 1000 +func_tol: 1e-8 +compute_cov: false # estimator sensor noises std_pbc_est: 0.01 std_vbc_est: 0.01 std_f_est: 1 std_tau_est: 1000 -std_odom3d_est: 0.01 -# std_odom3d_est: 10000000 +std_foot_nomove: 0.01 +std_altitude: 0.01 +foot_radius: 0.0 # some controls fz_thresh: 1 # slow walk @@ -63,102 +66,25 @@ nb_feet: 4 l_p_lg: [0.0, 0, 0] # l_p_lg: [0, 0, -0.016] # l_p_lg: [0, 0, -0.031] # for sin traj, point to which position estimation on z starts to be less good +foot_radius: 0.0 -# base to IMU transformation -# 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_q_i: [0.0, 0.0, 0.0, 1.0] -# b_q_i: [0.00000592745, -0.03255761280, -0.00025745595, 0.706732091] -artificial_bias_p: [0.0, 0.0, 0.0] -# artificial_bias_p: [0.03, 0.06, 0.04] -# artificial_bias_p: [3, 6, 4] - - - - - -# Data files -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/solo12_mpi_stamping_2020-09-29.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/data_2020_10_08_09_50_Walking_Novicon.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/data_2020_10_08_10_04_StandingStill_format.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/data_2020_10_08_10_04_StandingStill_shortened_format.npz" - -# 18:58 Fixe 4 stance phase (20s) -# 19:00 Rotation 4 stance phase (30s) -# 19:02 Mouvement avant arrière, rotation, rotation, mvt bas haut, roll (30s) -# 19:03 Replay sin wave -# 19:05 Replay stamping -# 19:06 Marche 0.32 (30s) -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_09_10_20_soir/data_2020_10_09_18_58_format.npz" # OK -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_09_10_20_soir/data_2020_10_09_18_58_format_shortened.npz" # OK -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_09_10_20_soir/data_2020_10_09_19_00_format.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_09_10_20_soir/data_2020_10_09_19_02_format.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_09_10_20_soir/data_2020_10_09_19_03_format.npz" # OK -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_09_10_20_soir/data_2020_10_09_19_05_format.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_09_10_20_soir/data_2020_10_09_19_06_format.npz" - - - - -# data_2020_10_15_14_34 standing still -# data_2020_10_15_14_36 sin traj -# data_2020_10_15_14_38 solo stamping -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format_shortened.npz" - -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format_shortened_CST.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format_shortened_CST_0gyr.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format_shortened_CST_Ogyr_Gacc_0dqa.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format_shortened_CST_Ogyr_Gacc_Filtereddqa.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format_shortened_CSTmean_Filtereddqa.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format_shortened_CSTacc_0gyr_Filtereddqa.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format_shortened_CST_0gyr_Gacc.npz" +delta_qa: [0,0,0,0,0,0,0,0,0,0,0,0] +alpha_qa: [0,0,0,0,0,0,0,0,0,0,0,0] -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format_shortened_CSTqa.npz" +# IMU MOCAP extr +m_p_mb: [-0.11872364, -0.0027602, -0.01272801] +m_q_b: [0.00698701, 0.00747303, 0.00597298, 0.99992983] -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format_VERY_shortened.npz" +i_p_im: [-0.0111, -0.0073, -0.0024] +i_q_m: [ 0.0035, 0.0042, 0.0051, 0.9999] -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_36_format.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_38_format.npz" - - -# data_2020_10_15_18_21: ... -# data_2020_10_15_18_23: walk -# data_2020_10_15_18_24: walk -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Log_15_10_2020_part2/data_2020_10_15_18_21.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Log_15_10_2020_part2/data_2020_10_15_18_23.npz" -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Log_15_10_2020_part2/data_2020_10_15_18_24.npz" - - -# same but with precomputed forces -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_34_format_forces.npz" # standing still -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_36_format_forces.npz" # sinusoid -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_15_10_2020/data_2020_10_15_14_38_format_forces.npz" # stamping - -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Log_15_10_2020_part2/data_2020_10_15_18_23_format_forces.npz" # fast walk -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/data_2020_10_31_20_12_format_forces.npz" # 0.48s walk - -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_05_10_2020_18h/data_2020_11_05_18_18_format_forces.npz" # standing still+walk 0.48 FAIL -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/Logs_05_10_2020_18h/data_2020_11_05_18_20_format_forces.npz" # standing still+walk 0.48 - - -# POINT FEET -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/solo-estimation/data/Point_feet_27_11_20/data_2020_11_27_14_46_format.npz" # standing still+walk 0.48 - -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/solo-estimation/data/Experiments_Replay_30_11_2020_bis/data_2020_11_30_17_17_format.npz" # stamping -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/solo-estimation/data/Experiments_Replay_30_11_2020_bis/data_2020_11_30_17_18_format.npz" # sin -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/solo-estimation/data/Experiments_Replay_30_11_2020_bis/data_2020_11_30_17_22_format.npz" # walking - -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/solo-estimation/data/SinStamping_Corrected_09_12_2020/data_2020_12_09_17_54_format.npz" # sin -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/solo-estimation/data/SinStamping_Corrected_09_12_2020/data_2020_12_09_17_56_format.npz" # stamping - -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/solo-estimation/data/Experiments_Walk_17_12_2020/data_2020_12_17_14_25_format.npz" # point feet walk with corrected kinematics -# data_file_path: "/home/mfourmy/Documents/Phd_LAAS/solo-estimation/data/Experiments_Walk_17_12_2020/data_2020_12_17_14_29_format.npz" # point feet walk with corrected kinematics +artificial_bias_p: [0.0, 0.0, 0.0] +# artificial_bias_p: [0.03, 0.06, 0.04] +# artificial_bias_p: [3, 6, 4] -data_file_path: "/home/mfourmy/Documents/Phd_LAAS/solo-estimation/data/Mesures_Contact/data_2021_01_19_17_11_format.npz" # Contact experiment with contact status and mocap leg kin +data_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments/LAAS_21_11_09/solo_trot_round_feet_format.npz" out_npz_file_path: "/home/mfourmy/Documents/Phd_LAAS/data/quadruped_experiments_results/out.npz" \ No newline at end of file diff --git a/demos/solo_real_povcdl_estimation.cpp b/demos/solo_real_povcdl_estimation.cpp index 0e4e6a4a6ce958563c3b4e84dfe3f31feb42f464..9953db41444d0d1b1da732f5460c3bd398cd3a63 100644 --- a/demos/solo_real_povcdl_estimation.cpp +++ b/demos/solo_real_povcdl_estimation.cpp @@ -69,7 +69,6 @@ #include "bodydynamics/sensor/sensor_point_feet_nomove.h" #include "bodydynamics/processor/processor_point_feet_nomove.h" -// UTILS #include "mcapi_utils.h" @@ -88,7 +87,7 @@ int main (int argc, char **argv) { int dimc = config["dimc"].as<int>(); double mass_offset = config["mass_offset"].as<double>(); double dt = config["dt"].as<double>(); - double min_t = config["min_t"].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>(); @@ -101,7 +100,7 @@ int main (int argc, char **argv) { 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>(); + double std_foot_nomove = config["std_foot_nomove"].as<double>(); // priors double std_prior_p = config["std_prior_p"].as<double>(); @@ -303,7 +302,7 @@ int main (int argc, char **argv) { // SENSOR + PROCESSOR POINT FEET NOMOVE ParamsSensorPointFeetNomovePtr intr_pfn = std::make_shared<ParamsSensorPointFeetNomove>(); - intr_pfn->std_foot_nomove_ = std_odom3d_est; + intr_pfn->std_foot_nomove_ = std_foot_nomove; VectorXd extr; // default size for dynamic vector is 0-0 -> what we need SensorBasePtr sen_pfnm_base = problem->installSensor("SensorPointFeetNomove", "SenPfnm", extr, intr_pfn); SensorPointFeetNomovePtr sen_pfnm = std::static_pointer_cast<SensorPointFeetNomove>(sen_pfnm_base); @@ -334,7 +333,7 @@ int main (int argc, char **argv) { // 1. Call setOrigin processorIMU to generate a fake captureIMU -> generates b_imu // 2. process one IKin capture corresponding to the same KF, the factor needing b_imu -> generates a b_pbc // 3. set processorForceTorquePreint origin which requires both b_imu and b_pbc - proc_inkin->keyFrameCallback(KF1, 0.0005); + proc_inkin->keyFrameCallback(KF1); proc_imu->setOrigin(KF1); // proc_legodom->setOrigin(KF1); @@ -577,19 +576,20 @@ int main (int argc, char **argv) { } } - CapturePointFeetNomovePtr CPF = std::make_shared<CapturePointFeetNomove>(ts, sen_pfnm, kin_incontact); - CPF->process(); + // TODO: ???? kin_incontact is a map to Vector3d in this implementation, should be Vector7d [p, q] + // CapturePointFeetNomovePtr CPF = std::make_shared<CapturePointFeetNomove>(ts, sen_pfnm, kin_incontact); + // CPF->process(); // add zero vel artificial factor - if (problem->getTrajectory()->getFrameMap().size() > nb_kf){ - auto kf_pair = problem->getTrajectory()->getFrameMap().rbegin(); - std::cout << "New KF " << kf_pair->first << std::endl; - auto kf = kf_pair->second; + if (problem->getTrajectory()->size() > nb_kf) + { + auto kf = problem->getTrajectory()->getLastFrame(); + std::cout << "New KF " << kf->getTimeStamp() << std::endl; - // CaptureBasePtr capV0 = CaptureBase::emplace<CaptureBase>(kf, "Vel0", kf_pair->first); + // CaptureBasePtr capV0 = CaptureBase::emplace<CaptureBase>(kf, "Vel0", kf->getTimeStamp()); // FeatureBasePtr featV0 = FeatureBase::emplace<FeatureBase>(capV0, "Vel0", Vector3d::Zero(), 0.00001*Matrix3d::Ones()); // FactorBasePtr facV0 = FactorBase::emplace<FactorBlockAbsolute>(featV0, featV0, kf->getV(), nullptr, false); @@ -728,7 +728,8 @@ int main (int argc, char **argv) { VectorComposite bp_bias_est; CaptureBasePtr cap_imu; VectorComposite bi_bias_est; - for (auto& elt: problem->getTrajectory()->getFrameMap()){ + for (auto elt: problem->getTrajectory()->getFrameMap()) + { auto kf = elt.second; kf_state = kf->getState(); cap_ikin = kf->getCaptureOf(sen_ikin); diff --git a/demos/tree_manager.yaml b/demos/tree_manager.yaml index ceb0dd77261e7361210a690b2ba563aaa58e7779..eb2b370c5838b91cffb42dcc06fc2dde1aec49f5 100644 --- a/demos/tree_manager.yaml +++ b/demos/tree_manager.yaml @@ -2,6 +2,6 @@ config: problem: tree_manager: n_fix_first_frames: 3 - n_frames: 100000000000 + n_frames: 50000 type: TreeManagerSlidingWindow viral_remove_empty_parent: true diff --git a/include/bodydynamics/capture/capture_force_torque_preint.h b/include/bodydynamics/capture/capture_force_torque_preint.h index 12f4eb58c9e2a8b8d89e7923bea393e93bae48a5..81db7bf05f90fc9048a907253b477b73f8c748a5 100644 --- a/include/bodydynamics/capture/capture_force_torque_preint.h +++ b/include/bodydynamics/capture/capture_force_torque_preint.h @@ -62,7 +62,9 @@ class CaptureForceTorquePreint : public CaptureMotion ~CaptureForceTorquePreint() override; - CaptureBasePtr getIkinCaptureOther(){ return cap_ikin_other_; } + CaptureBaseConstPtr getIkinCaptureOther() const { return cap_ikin_other_;} + CaptureBasePtr getIkinCaptureOther(){ return cap_ikin_other_;} + CaptureBaseConstPtr getGyroCaptureOther() const { return cap_gyro_other_;} CaptureBasePtr getGyroCaptureOther(){ return cap_gyro_other_;} private: diff --git a/include/bodydynamics/capture/capture_point_feet_nomove.h b/include/bodydynamics/capture/capture_point_feet_nomove.h index 1e57c0cdd71d3cc2cd85f196a51e16df57dce844..ffad3a2d2549f2cf55b0f785c47fe5fd4561f601 100644 --- a/include/bodydynamics/capture/capture_point_feet_nomove.h +++ b/include/bodydynamics/capture/capture_point_feet_nomove.h @@ -42,13 +42,13 @@ class CapturePointFeetNomove : public CaptureBase CapturePointFeetNomove( const TimeStamp& _init_ts, SensorBasePtr _sensor_ptr, - const std::unordered_map<int, Eigen::Vector3d>& kin_incontact + const std::unordered_map<int, Eigen::Vector7d>& kin_incontact ); ~CapturePointFeetNomove() override; // <foot in contact number (0,1,2,3), b_p_bf> - std::unordered_map<int, Eigen::Vector3d> kin_incontact_; + std::unordered_map<int, Eigen::Vector7d> kin_incontact_; }; } // namespace wolf diff --git a/include/bodydynamics/factor/factor_force_torque.h b/include/bodydynamics/factor/factor_force_torque.h index 85d74de654cfd2976eae06ab640086fec74870aa..958398a325c0e6c77fd5b70a2cabb4497fec746b 100644 --- a/include/bodydynamics/factor/factor_force_torque.h +++ b/include/bodydynamics/factor/factor_force_torque.h @@ -79,7 +79,7 @@ class FactorForceTorque : public FactorAutodiff<FactorForceTorque, 9, 3,3,3, 3,3 const T* const _qkm, T* _res) const; - void computeJac(const FeatureForceTorquePtr& _feat, + void computeJac(const FeatureForceTorqueConstPtr& _feat, const double& _mass, const double& _dt, const Eigen::VectorXd& _bp, @@ -149,25 +149,24 @@ void FactorForceTorque::retrieveMeasurementCovariance(const FeatureForceTorquePt } -void FactorForceTorque::computeJac(const FeatureForceTorquePtr& _feat, +void FactorForceTorque::computeJac(const FeatureForceTorqueConstPtr& _feat, const double& _mass, const double& _dt, const Eigen::VectorXd& _bp, Eigen::Matrix<double, 9, 15>& _J_ny_nz) const { _J_ny_nz.setZero(); - FeatureForceTorquePtr feat = std::static_pointer_cast<FeatureForceTorque>(_feat); // Measurements retrieval - Eigen::Map<const Eigen::Vector3d> f1 (feat->getForcesMeas().data()); - Eigen::Map<const Eigen::Vector3d> f2 (feat->getForcesMeas().data() + 3 ); - Eigen::Map<const Eigen::Vector3d> tau1(feat->getTorquesMeas().data()); - Eigen::Map<const Eigen::Vector3d> tau2(feat->getTorquesMeas().data() + 3 ); - Eigen::Map<const Eigen::Vector3d> pbl1(feat->getKinMeas().data()); - Eigen::Map<const Eigen::Vector3d> pbl2(feat->getKinMeas().data() + 3 ); - Eigen::Map<const Eigen::Quaterniond> bql1(feat->getKinMeas().data() + 6); - Eigen::Map<const Eigen::Quaterniond> bql2(feat->getKinMeas().data() + 10); - Eigen::Map<const Eigen::Vector3d> pbc (feat->getPbcMeas().data()); + Eigen::Map<const Eigen::Vector3d> f1 (_feat->getForcesMeas().data()); + Eigen::Map<const Eigen::Vector3d> f2 (_feat->getForcesMeas().data() + 3 ); + Eigen::Map<const Eigen::Vector3d> tau1(_feat->getTorquesMeas().data()); + Eigen::Map<const Eigen::Vector3d> tau2(_feat->getTorquesMeas().data() + 3 ); + Eigen::Map<const Eigen::Vector3d> pbl1(_feat->getKinMeas().data()); + Eigen::Map<const Eigen::Vector3d> pbl2(_feat->getKinMeas().data() + 3 ); + Eigen::Map<const Eigen::Quaterniond> bql1(_feat->getKinMeas().data() + 6); + Eigen::Map<const Eigen::Quaterniond> bql2(_feat->getKinMeas().data() + 10); + Eigen::Map<const Eigen::Vector3d> pbc (_feat->getPbcMeas().data()); Eigen::Matrix3d bRl1 = q2R(bql1); Eigen::Matrix3d bRl2 = q2R(bql2); @@ -226,7 +225,7 @@ bool FactorForceTorque::operator () ( const T* const _qkm, T* _res) const { - FeatureForceTorquePtr feat = std::static_pointer_cast<FeatureForceTorque>(getFeature()); + auto feat = std::static_pointer_cast<const FeatureForceTorque>(getFeature()); // State variables instanciation Eigen::Map<const Eigen::Matrix<T,3,1> > ck(_ck); diff --git a/include/bodydynamics/factor/factor_inertial_kinematics.h b/include/bodydynamics/factor/factor_inertial_kinematics.h index c0b36d22bdd65b63b575e6d80863ea2eea978405..ff824e20b8673da4d6de79afa06e80da6cd2607e 100644 --- a/include/bodydynamics/factor/factor_inertial_kinematics.h +++ b/include/bodydynamics/factor/factor_inertial_kinematics.h @@ -158,7 +158,7 @@ bool FactorInertialKinematics::operator () ( Map<Matrix<T,9,1> > res(_res); - FeatureInertialKinematicsPtr feat = std::static_pointer_cast<FeatureInertialKinematics>(getFeature()); + auto feat = std::static_pointer_cast<const FeatureInertialKinematics>(getFeature()); // Measurements retrieval Map<const Vector3d> pBC_m(getMeasurement().data() ); // B_p_BC diff --git a/include/bodydynamics/factor/factor_point_feet_altitude.h b/include/bodydynamics/factor/factor_point_feet_altitude.h new file mode 100644 index 0000000000000000000000000000000000000000..235244a272ded4a67a5a4d8eae8c986476420140 --- /dev/null +++ b/include/bodydynamics/factor/factor_point_feet_altitude.h @@ -0,0 +1,145 @@ +//--------LICENSE_START-------- +// +// Copyright (C) 2020,2021,2022 Institut de Robòtica i Informà tica Industrial, CSIC-UPC. +// Authors: Joan Solà Ortega (jsola@iri.upc.edu) +// All rights reserved. +// +// This file is part of WOLF +// WOLF is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +//--------LICENSE_END-------- +/** + * \file factor_point_feet_altitude.h + * + * Created on: Nov 5, 2020 + * \author: mfourmy + */ + +#ifndef FACTOR_POINT_FEET_ALTITUDE_H_ +#define FACTOR_POINT_FEET_ALTITUDE_H_ + +#include "core/factor/factor_autodiff.h" + +namespace wolf +{ + +WOLF_PTR_TYPEDEFS(FactorPointFeetAltitude); + +class FactorPointFeetAltitude : public FactorAutodiff<FactorPointFeetAltitude, + 1, + 3, + 4 + > +{ + public: + FactorPointFeetAltitude(const FeatureBasePtr& _ftr_current_ptr, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status = FAC_ACTIVE); + + ~FactorPointFeetAltitude() override { /* nothing */ } + + /* + Factor state blocks: + _pb: W_p_WB -> base position in world frame + _qb: W_q_B -> base orientation in world frame + */ + template<typename T> + bool operator () ( + const T* const _pb, + const T* const _qb, + T* _res) const; + + Vector1d error() const; + Vector1d res() const; + double cost() const; + +}; + +} /* namespace wolf */ + + +namespace wolf { + +FactorPointFeetAltitude::FactorPointFeetAltitude( + const FeatureBasePtr& _ftr_current_ptr, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status) : + FactorAutodiff("FactorPointFeetAltitude", + TOP_GEOM, + _ftr_current_ptr, + nullptr, // _frame_other_ptr + nullptr, // _capture_other_ptr + nullptr, // _feature_other_ptr + nullptr, // _landmark_other_ptr + _processor_ptr, + _apply_loss_function, + _status, + _ftr_current_ptr->getFrame()->getP(), + _ftr_current_ptr->getFrame()->getO() + ) +{ +} + +Vector1d FactorPointFeetAltitude::error() const{ + + Vector3d pb = getFrame()->getP()->getState(); + Vector4d qb_vec = getFrame()->getO()->getState(); + Quaterniond qb(qb_vec); + + // Measurements retrieval + Eigen::Matrix<double,4,1> meas = getMeasurement(); + Vector3d b_p_bl = meas.topRows(3); + Vector1d z = meas.bottomRows(1); + + return (pb + qb*b_p_bl).block(2,0,1,1) - z; +} + +Vector1d FactorPointFeetAltitude::res() const{ + return getMeasurementSquareRootInformationUpper() * error(); +} + + +double FactorPointFeetAltitude::cost() const{ + return res().squaredNorm(); +} + +template<typename T> +bool FactorPointFeetAltitude::operator () ( + const T* const _pb, + const T* const _qb, + T* _res) const +{ + Map<Matrix<T,1,1> > res(_res); + + // State variables instanciation + Map<const Matrix<T,3,1> > pb(_pb); + Map<const Quaternion<T> > qb(_qb); + + // Measurements retrieval + Eigen::Matrix<T,4,1> meas = getMeasurement().cast<T>(); + Matrix<T,3,1> b_p_bl = meas.topRows(3); // Bpast_p_BpastL + Matrix<T,1,1> z = meas.bottomRows(1); // altitude + + Matrix<T,1,1> err = (pb + qb*b_p_bl).block(2,0,1,1) - z; + + res = getMeasurementSquareRootInformationUpper() * err; + + return true; +} + +} // namespace wolf + +#endif /* FACTOR__POINT_FEET_ALTITUDE_H_ */ diff --git a/include/bodydynamics/factor/factor_point_feet_nomove.h b/include/bodydynamics/factor/factor_point_feet_nomove.h index 58e7804f43b3c3e1ffe0de8e85711c3f3d595e06..9e17e16b75f6cc703ea6f5f7c58b35df27b39aad 100644 --- a/include/bodydynamics/factor/factor_point_feet_nomove.h +++ b/include/bodydynamics/factor/factor_point_feet_nomove.h @@ -29,18 +29,11 @@ #ifndef FACTOR_POINT_FEET_NOMOVE_H_ #define FACTOR_POINT_FEET_NOMOVE_H_ +#include "core/math/rotations.h" #include "core/factor/factor_autodiff.h" +#include "bodydynamics/sensor/sensor_point_feet_nomove.h" -// namespace -// { - -// constexpr std::size_t RESIDUAL_SIZE = 3; -// constexpr std::size_t POSITION_SIZE = 3; -// constexpr std::size_t ORIENTATION_SIZE = 4; - -// } - namespace wolf { @@ -67,19 +60,20 @@ class FactorPointFeetNomove : public FactorAutodiff<FactorPointFeetNomove, Factor state blocks: _pb: W_p_WB -> base position in world frame _qb: W_q_B -> base orientation in world frame - _pbm: W_p_WB -> base position in world frame, previous KF - _qbm: W_q_B -> base orientation in world frame, previous KF + _pb_past: W_p_WB -> base position in world frame, pastious KF + _qb_past: W_q_B -> base orientation in world frame, pastious KF */ template<typename T> bool operator () ( const T* const _pb, const T* const _qb, - const T* const _pbm, - const T* const _qbm, + const T* const _pb_past, + const T* const _qb_past, T* _res) const; - // Vector9d residual() const; - // double cost() const; + Vector3d error() const; + Vector3d res() const; + double cost() const; }; @@ -112,33 +106,39 @@ FactorPointFeetNomove::FactorPointFeetNomove( { } -// Vector9d FactorPointFeetNomove::residual() const{ -// Vector9d res; -// double * pb, * qb, * vb, * c, * cd, * Lc, * bp, * baw; -// pb = getFrame()->getP()->getState().data(); -// qb = getFrame()->getO()->getState().data(); -// vb = getFrame()->getV()->getState().data(); -// c = getFrame()->getStateBlock('C')->getState().data(); -// cd = getFrame()->getStateBlock('D')->getState().data(); -// Lc = getFrame()->getStateBlock('L')->getState().data(); -// bp = getCapture()->getStateBlock('I')->getState().data(); -// baw = sb_bias_imu_->getState().data(); - -// operator() (pb, qb, vb, c, cd, Lc, bp, baw, res.data()); -// // std::cout << "res: " << res.transpose() << std::endl; -// return res; -// } - -// double FactorPointFeetNomove::cost() const{ -// return residual().squaredNorm(); -// } +Vector3d FactorPointFeetNomove::error() const{ + + Vector3d pb = getFrame()->getP()->getState(); + Vector4d qb_vec = getFrame()->getO()->getState(); + Quaterniond qb(qb_vec); + Vector3d pbm = getFrameOther()->getP()->getState(); + Vector4d qb_past_vec = getFrameOther()->getO()->getState(); + Quaterniond qbm(qb_past_vec); + + // Measurements retrieval + Matrix<double,6,1> meas = getMeasurement(); + Vector3d bm_p_bml = meas.topRows(3); + Vector3d b_p_bl = meas.bottomRows(3); + + return (pbm + qbm*bm_p_bml) - (pb + qb*b_p_bl); + +} + +Vector3d FactorPointFeetNomove::res() const{ + return getMeasurementSquareRootInformationUpper() * error(); +} + + +double FactorPointFeetNomove::cost() const{ + return res().squaredNorm(); +} template<typename T> bool FactorPointFeetNomove::operator () ( const T* const _pb, const T* const _qb, - const T* const _pbm, - const T* const _qbm, + const T* const _pb_past, + const T* const _qb_past, T* _res) const { Map<Matrix<T,3,1> > res(_res); @@ -146,15 +146,48 @@ bool FactorPointFeetNomove::operator () ( // State variables instanciation Map<const Matrix<T,3,1> > pb(_pb); Map<const Quaternion<T> > qb(_qb); - Map<const Matrix<T,3,1> > pbm(_pbm); - Map<const Quaternion<T> > qbm(_qbm); + Map<const Matrix<T,3,1> > pbm(_pb_past); + Map<const Quaternion<T> > qbm(_qb_past); // Measurements retrieval - Eigen::Matrix<T,6,1> meas = getMeasurement().cast<T>(); - Matrix<T,3,1> bm_p_bml = meas.topRows(3); // Bprev_p_BprevL - Matrix<T,3,1> b_p_bl = meas.bottomRows(3); // B_p_BL + auto& meas = getMeasurement(); + Matrix<T,3,1> bm_p_bml = meas.segment(0, 3).cast<T>(); // Bminus_p_BminusL + Matrix<T,4,1> bm_qvec_l = meas.segment(3, 4).cast<T>(); // Bminus_q_BminusL + Matrix<T,3,1> b_p_bl = meas.segment(7, 3).cast<T>(); // B_p_BL + Matrix<T,4,1> b_qvec_l = meas.segment(10, 4).cast<T>(); // B_q_BL + Eigen::Quaternion<T> bm_q_l(bm_qvec_l); + Eigen::Quaternion<T> b_q_l(b_qvec_l); + + // double radius = std::dynamic_pointer_cast<SensorPointFeetNomove>(getSensor())->getFootRadius(); // DOES NOT COMPILE + double radius = 0.0; // deactivate, was not doing so great anyway + + // If the radius of the foot is not negligeable, try to account for it with a more complex model + Matrix<T,3,1> err; + if (std::fabs(radius) < wolf::Constants::EPS){ + err = (pbm + qbm*bm_p_bml) - (pb + qb*b_p_bl); + } + else{ + /* + n: frame with (xy) plane == world but orientation aligned in yaw with the robot base frame + sometimes called "Navigation frame" in some papers. + Simple roll without slipping model: we assume that most of actual movement + of the frame attached to the center of the foot is due to rolling along y axis of the foot (for solo) + */ + Quaternion<T> l_q_lm = (qbm*bm_q_l).inverse() * qb*b_q_l; + Matrix<T,3,1> l_aa_lm = log_q(l_q_lm); + Matrix<T,3,1> n_p_lml = Matrix<T,3,1>::Zero(); + n_p_lml(0) = -l_aa_lm(1)*radius; + + // Factor: w_p_wl = w_p_wlm + w_R_n * n_p_lml + // By def, w_R_n is w_R_b with roll and pitch set to zero + // Matrix<T,3,1> aa_bm = q2e(qbm); // DOES NOT WORK -> equivalent angle axis in this case + Matrix<T,3,1> aa_bm = log_q(qbm); + aa_bm.segment(0,2) = Matrix<T,2,1>::Zero(); + Quaternion<T> w_q_nm = exp_q(aa_bm); + + err = (pbm + qbm*bm_p_bml) + w_q_nm*n_p_lml - (pb + qb*b_p_bl); + } - Matrix<T,3,1> err = (pbm + qbm*bm_p_bml) - (pb + qb*b_p_bl); res = getMeasurementSquareRootInformationUpper() * err; diff --git a/include/bodydynamics/factor/factor_point_feet_zero_velocity.h b/include/bodydynamics/factor/factor_point_feet_zero_velocity.h new file mode 100644 index 0000000000000000000000000000000000000000..1907583d9d198d90c9f265a970e69dfc8dcfe507 --- /dev/null +++ b/include/bodydynamics/factor/factor_point_feet_zero_velocity.h @@ -0,0 +1,134 @@ +//--------LICENSE_START-------- +// +// Copyright (C) 2020,2021,2022 Institut de Robòtica i Informà tica Industrial, CSIC-UPC. +// Authors: Joan Solà Ortega (jsola@iri.upc.edu) +// All rights reserved. +// +// This file is part of WOLF +// WOLF is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +//--------LICENSE_END-------- +/** + * \file factor_point_feet_nomove.h + * + * Created on: Feb 22, 2020 + * \author: mfourmy + */ + +#ifndef FACTOR_POINT_FEET_ZERO_VELOCITY_H_ +#define FACTOR_POINT_FEET_ZERO_VELOCITY_H_ + +#include "core/factor/factor_autodiff.h" + + + +namespace wolf +{ + +WOLF_PTR_TYPEDEFS(FactorPointFeetNomove); + +class FactorPointFeetNomove : public FactorAutodiff<FactorPointFeetNomove, + 3, + 3, + 4, + 3 + > +{ + public: + FactorPointFeetNomove(const FeatureBasePtr& _ftr_current_ptr, + const StateBlockPtr& _bias_imu, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status = FAC_ACTIVE); + + ~FactorPointFeetNomove() override { /* nothing */ } + + /* + Factor state blocks: + _pb: W_p_WB -> base position in world frame + _qb: W_q_B -> base orientation in world frame + _pbm: W_p_WB -> base position in world frame, previous KF + _qbm: W_q_B -> base orientation in world frame, previous KF + */ + template<typename T> + bool operator () ( + const T* const _vb, + const T* const _qb, + const T* const _bi, + T* _res) const; + + // Vector9d residual() const; + // double cost() const; + +}; + +} /* namespace wolf */ + + +namespace wolf { + +FactorPointFeetNomove::FactorPointFeetNomove( + const FeatureBasePtr& _ftr_current_ptr, + const StateBlockPtr& _bias_imu, + const ProcessorBasePtr& _processor_ptr, + bool _apply_loss_function, + FactorStatus _status) : + FactorAutodiff("FactorPointFeetNomove", + TOP_GEOM, + _ftr_current_ptr, + nullptr, // _frame_other_ptr + nullptr, // _capture_other_ptr + nullptr, // _feature_other_ptr + nullptr, // _landmark_other_ptr + _processor_ptr, + _apply_loss_function, + _status, + _ftr_current_ptr->getFrame()->getV(), + _ftr_current_ptr->getFrame()->getO(), + _bias_imu + ) +{ +} + +template<typename T> +bool FactorPointFeetNomove::operator () ( + const T* const _vb, + const T* const _qb, + const T* const _bi, + T* _res) const +{ + Map<Matrix<T,3,1> > res(_res); + + // State variables instanciation + Map<const Matrix<T,3,1> > vb(_vb); + Map<const Quaternion<T> > qb(_qb); + Map<const Matrix<T,3,1> > bw(_pbm+3); // gyro bias + Map<const Quaternion<T> > qbm(_qbm); + + // Measurements retrieval + Eigen::Matrix<T,6,1> meas = getMeasurement().cast<T>(); + Eigen::Matrix<T,3,1> b_v_bl = meas.head<3>(); + Eigen::Matrix<T,3,1> i_omg_i = meas.segment<3>(3); + Eigen::Matrix<T,3,1> b_p_bl = meas.tail<3>(); + + Matrix<T,3,1> err = qb.conjugate()*vb + (i_omg_i - bw).cross(b_p_bl) + b_v_bl; + + res = getMeasurementSquareRootInformationUpper() * err; + + return true; +} + +} // namespace wolf + +#endif /* FACTOR__POINT_FEET_ZERO_VELOCITY_H_ */ diff --git a/include/bodydynamics/feature/feature_force_torque.h b/include/bodydynamics/feature/feature_force_torque.h index bbe2fda19d7fcdbde4e88aa564efc3547a6293ef..14594821f3171f7628199e4b3b5f76026f4f7f63 100644 --- a/include/bodydynamics/feature/feature_force_torque.h +++ b/include/bodydynamics/feature/feature_force_torque.h @@ -50,19 +50,19 @@ class FeatureForceTorque : public FeatureBase ~FeatureForceTorque() override; - const double & getDt(){return dt_;} - const double & getMass(){return mass_;} + const double & getDt() const {return dt_;} + const double & getMass() const {return mass_;} void setDt(const double & _dt){dt_ = _dt;} void setMass(const double & _mass){mass_ = _mass;} - const Eigen::Vector6d& getForcesMeas(){return forces_meas_;} - const Eigen::Vector6d& getTorquesMeas(){return torques_meas_;} - const Eigen::Vector3d& getPbcMeas(){return pbc_meas_;} - const Eigen::Matrix<double,14,1>& getKinMeas(){return kin_meas_;} - const Eigen::Matrix6d& getCovForcesMeas(){return cov_forces_meas_;} - const Eigen::Matrix6d& getCovTorquesMeas(){return cov_torques_meas_;} - const Eigen::Matrix3d& getCovPbcMeas(){return cov_pbc_meas_;} - const Eigen::Matrix<double,14,14>& getCovKinMeas(){return cov_kin_meas_;} + const Eigen::Vector6d& getForcesMeas() const {return forces_meas_;} + const Eigen::Vector6d& getTorquesMeas() const {return torques_meas_;} + const Eigen::Vector3d& getPbcMeas() const {return pbc_meas_;} + const Eigen::Matrix<double,14,1>& getKinMeas() const {return kin_meas_;} + const Eigen::Matrix6d& getCovForcesMeas() const {return cov_forces_meas_;} + const Eigen::Matrix6d& getCovTorquesMeas() const {return cov_torques_meas_;} + const Eigen::Matrix3d& getCovPbcMeas() const {return cov_pbc_meas_;} + const Eigen::Matrix<double,14,14>& getCovKinMeas() const {return cov_kin_meas_;} void setForcesMeas(const Eigen::Vector6d& _forces_meas){forces_meas_ = _forces_meas;} void setTorquesMeas(const Eigen::Vector6d& _torques_meas){torques_meas_ = _torques_meas;} diff --git a/include/bodydynamics/feature/feature_inertial_kinematics.h b/include/bodydynamics/feature/feature_inertial_kinematics.h index bb9588ffbc24e78162bedddc5df7a914f7d55c63..98f03fc3e948e1c5feeaf399e3bdf10297a2b1a6 100644 --- a/include/bodydynamics/feature/feature_inertial_kinematics.h +++ b/include/bodydynamics/feature/feature_inertial_kinematics.h @@ -43,8 +43,8 @@ class FeatureInertialKinematics : public FeatureBase ~FeatureInertialKinematics() override = default; - const Eigen::Matrix3d & getBIq(){return BIq_;} - const Eigen::Vector3d & getBLcm(){return BLcm_;} + const Eigen::Matrix3d & getBIq() const {return BIq_;} + const Eigen::Vector3d & getBLcm() const {return BLcm_;} void setBIq(const Eigen::Matrix3d & _BIq){BIq_ = _BIq;} void setBLcm(const Eigen::Vector3d & _BLcm){BLcm_ = _BLcm;} diff --git a/include/bodydynamics/processor/processor_force_torque_preint.h b/include/bodydynamics/processor/processor_force_torque_preint.h index c834f71b8e1fc42b2d9d8e7dfd1ee43157627d43..6cd089107cfebd55fad2a51ff1b6cf5eddb0b036 100644 --- a/include/bodydynamics/processor/processor_force_torque_preint.h +++ b/include/bodydynamics/processor/processor_force_torque_preint.h @@ -92,7 +92,7 @@ class ProcessorForceTorquePreint : public ProcessorMotion{ Eigen::VectorXd deltaZero() const override; Eigen::VectorXd correctDelta(const Eigen::VectorXd& delta_preint, const Eigen::VectorXd& delta_step) const override; - VectorXd getCalibration (const CaptureBasePtr _capture = nullptr) const override; + VectorXd getCalibration (const CaptureBaseConstPtr _capture = nullptr) const override; void setCalibration(const CaptureBasePtr _capture, const VectorXd& _calibration) override; bool voteForKeyFrame() const override; diff --git a/include/bodydynamics/processor/processor_point_feet_nomove.h b/include/bodydynamics/processor/processor_point_feet_nomove.h index 49c40be86b331397416bc8bf806aac4a4b6f9419..5c3f727fc26936f518795d146aad3ba02ae4dec6 100644 --- a/include/bodydynamics/processor/processor_point_feet_nomove.h +++ b/include/bodydynamics/processor/processor_point_feet_nomove.h @@ -29,21 +29,26 @@ #include "bodydynamics/capture/capture_point_feet_nomove.h" #include "bodydynamics/sensor/sensor_point_feet_nomove.h" #include "bodydynamics/factor/factor_point_feet_nomove.h" +#include "bodydynamics/factor/factor_point_feet_altitude.h" namespace wolf { WOLF_STRUCT_PTR_TYPEDEFS(ParamsProcessorPointFeetNomove); struct ParamsProcessorPointFeetNomove : public ParamsProcessorBase { + double max_time_vote = -1; + ParamsProcessorPointFeetNomove() = default; ParamsProcessorPointFeetNomove(std::string _unique_name, const ParamsServer& _server): ParamsProcessorBase(_unique_name, _server) { + max_time_vote = _server.getParam<double>(_unique_name + "/max_time_vote"); } ~ParamsProcessorPointFeetNomove() override = default; std::string print() const override { - return "\n" + ParamsProcessorBase::print() + "\n"; + return "\n" + ParamsProcessorBase::print() + "\n" + + "max_time_vote: " + std::to_string(max_time_vote) + "\n"; } }; @@ -68,11 +73,18 @@ class ProcessorPointFeetNomove : public ProcessorBase{ bool storeCapture(CaptureBasePtr) override; bool voteForKeyFrame() const override; - void createFactorIfNecessary(); + void createFactorConsecutive(); + + void processCaptureCreateFactorFar(CaptureBasePtr _capture); + void processKeyFrameCreateFactorFar(); + protected: ParamsProcessorPointFeetNomovePtr params_pfnomove_; + CaptureBasePtr origin_; + CaptureBasePtr incoming_; + std::map<int, CaptureBasePtr> tracks_; }; @@ -97,10 +109,6 @@ inline bool ProcessorPointFeetNomove::storeCapture(CaptureBasePtr) return true; } -inline bool ProcessorPointFeetNomove::voteForKeyFrame() const -{ - return false; -} } /* namespace wolf */ diff --git a/include/bodydynamics/sensor/sensor_point_feet_nomove.h b/include/bodydynamics/sensor/sensor_point_feet_nomove.h index 7f58ad65e96d1ca4c249cdd23a4f8e88b03f8060..077765e0ae0fc3d4df3bba4fb627a54cd507f473 100644 --- a/include/bodydynamics/sensor/sensor_point_feet_nomove.h +++ b/include/bodydynamics/sensor/sensor_point_feet_nomove.h @@ -34,20 +34,29 @@ WOLF_STRUCT_PTR_TYPEDEFS(ParamsSensorPointFeetNomove); struct ParamsSensorPointFeetNomove : public ParamsSensorBase { - //noise std dev - double std_foot_nomove_; // standard deviation on the assumption that the feet are not moving when in contact + // standard deviation on the assumption that the feet are not moving when in contact + // the noise represents a random walk on the foot position, hence the unit + double std_foot_nomove_; // m/(s^2 sqrt(dt)) + // certainty on current ground altitude + double std_altitude_ = 1000; // m, deactivated by default + double foot_radius_ = 0; // m ParamsSensorPointFeetNomove() = default; ParamsSensorPointFeetNomove(std::string _unique_name, const ParamsServer& _server): ParamsSensorBase(_unique_name, _server) { - std_foot_nomove_ = _server.getParam<double>(_unique_name + "/std_foot_nomove"); + std_foot_nomove_ = _server.getParam<double>(_unique_name + "/std_foot_nomove"); + std_altitude_ = _server.getParam<double>(_unique_name + "/std_altitude"); + foot_radius_ = _server.getParam<double>(_unique_name + "/foot_radius"); } ~ParamsSensorPointFeetNomove() override = default; std::string print() const override { - return "\n" + ParamsSensorBase::print() + "\n" - + "std_foot_nomove: " + std::to_string(std_foot_nomove_) + "\n"; + return "\n" + ParamsSensorBase::print() + "\n" + + "std_altitude: " + std::to_string(std_altitude_) + "\n" + + "std_foot_nomove: " + std::to_string(std_foot_nomove_) + "\n"; + + "foot_radius_: " + std::to_string(foot_radius_) + "\n"; + } }; @@ -57,7 +66,9 @@ class SensorPointFeetNomove : public SensorBase { protected: - Matrix3d cov_foot_nomove_; + Matrix3d cov_foot_nomove_; // random walk covariance in (m/s^2/sqrt(Hz))^2 + Matrix1d cov_altitude_; // m^2 + double foot_radius_; public: @@ -67,6 +78,8 @@ class SensorPointFeetNomove : public SensorBase WOLF_SENSOR_CREATE(SensorPointFeetNomove, ParamsSensorPointFeetNomove, 0); Matrix3d getCovFootNomove() const; + Matrix1d getCovAltitude() const; + double getFootRadius() const; }; inline Matrix3d SensorPointFeetNomove::getCovFootNomove() const @@ -74,6 +87,16 @@ inline Matrix3d SensorPointFeetNomove::getCovFootNomove() const return cov_foot_nomove_; } +inline Matrix1d SensorPointFeetNomove::getCovAltitude() const +{ + return cov_altitude_; +} + +inline double SensorPointFeetNomove::getFootRadius() const +{ + return foot_radius_; +} + } // namespace wolf diff --git a/internal/config.h.in b/internal/config.h.in index 7014ca320e5c5fea1f59a6fe5d9d1ea0987bf95e..35f3468331656ba09a63ad7f26e5c0fb78c8d5bc 100644 --- a/internal/config.h.in +++ b/internal/config.h.in @@ -24,13 +24,13 @@ // which will be added to the include path for compilation, // and installed with the public wolf headers. -#ifndef WOLF_INTERNAL_${UPPER_NAME}_CONFIG_H_ -#define WOLF_INTERNAL_${UPPER_NAME}_CONFIG_H_ +#ifndef WOLF_INTERNAL_${PROJECT_NAME_UPPER}_CONFIG_H_ +#define WOLF_INTERNAL_${PROJECT_NAME_UPPER}_CONFIG_H_ #cmakedefine _WOLF_DEBUG #cmakedefine _WOLF_TRACE -#define _WOLF_${UPPER_NAME}_ROOT_DIR "${_WOLF_ROOT_DIR}" +#define _WOLF_${PROJECT_NAME_UPPER}_ROOT_DIR "${_WOLF_ROOT_DIR}" #endif /* WOLF_INTERNAL_CONFIG_H_ */ diff --git a/src/capture/capture_point_feet_nomove.cpp b/src/capture/capture_point_feet_nomove.cpp index 3d4dca45ced860903bfdfabc3f4a86e088b63859..3851ea477acd49d8c403f5e27dd3840b49304008 100644 --- a/src/capture/capture_point_feet_nomove.cpp +++ b/src/capture/capture_point_feet_nomove.cpp @@ -38,7 +38,7 @@ namespace wolf { CapturePointFeetNomove::CapturePointFeetNomove( const TimeStamp& _init_ts, SensorBasePtr _sensor_ptr, - const std::unordered_map<int, Eigen::Vector3d>& kin_incontact + const std::unordered_map<int, Eigen::Vector7d>& kin_incontact ) : CaptureBase("CapturePointFeetNomove", _init_ts, diff --git a/src/processor/processor_force_torque_preint.cpp b/src/processor/processor_force_torque_preint.cpp index 994b91a49c911dc5835b1d642ead04d2f5ca0223..1b84f786077a0f65ee3cc944bf8ebe4f54511499 100644 --- a/src/processor/processor_force_torque_preint.cpp +++ b/src/processor/processor_force_torque_preint.cpp @@ -136,14 +136,14 @@ Eigen::VectorXd ProcessorForceTorquePreint::correctDelta (const Eigen::VectorXd& return bodydynamics::plus(delta_preint, delta_step); } -VectorXd ProcessorForceTorquePreint::getCalibration (const CaptureBasePtr _capture) const +VectorXd ProcessorForceTorquePreint::getCalibration (const CaptureBaseConstPtr _capture) const { VectorXd bias_vec(6); if (_capture) // access from capture is quicker { - CaptureForceTorquePreintPtr cap_ft(std::static_pointer_cast<CaptureForceTorquePreint>(_capture)); + auto cap_ft(std::static_pointer_cast<const CaptureForceTorquePreint>(_capture)); // get calib part from Ikin capture bias_vec.segment<3>(0) = cap_ft->getIkinCaptureOther()->getSensorIntrinsic()->getState(); @@ -211,7 +211,7 @@ void ProcessorForceTorquePreint::computeCurrentDelta( bodydynamics::debiasData(_data, _calib, nbc_, dimc_, body, jac_body_bias); MatrixXd jac_delta_body(12,data_size_-nbc_); - bodydynamics::body2delta(body, _dt, std::static_pointer_cast<SensorForceTorque>(getSensor())->getMass(), + bodydynamics::body2delta(body, _dt, std::static_pointer_cast<const SensorForceTorque>(getSensor())->getMass(), nbc_, dimc_, _delta, jac_delta_body); // Jacobians tested in bodydynamics_tools diff --git a/src/processor/processor_inertial_kinematics.cpp b/src/processor/processor_inertial_kinematics.cpp index 46eb8f944900d0eff9596ad239351d19ec74f1a3..360ef7d654952c17a18dce633f53f9177e79e61d 100644 --- a/src/processor/processor_inertial_kinematics.cpp +++ b/src/processor/processor_inertial_kinematics.cpp @@ -68,7 +68,6 @@ inline void ProcessorInertialKinematics::processCapture(CaptureBasePtr _capture) // done AFTER processCapture) // 1. get corresponding KF - FrameBasePtr kf; auto buffer_frame_it = buffer_frame_.getContainer().begin(); auto buffer_capture_it = buffer_capture_.getContainer().begin(); diff --git a/src/processor/processor_point_feet_nomove.cpp b/src/processor/processor_point_feet_nomove.cpp index 358ad06be77d987125dcd0341bbd10e62c6fdd78..161c16dd18e4bdd512868d6c9bc76ed2d4f87442 100644 --- a/src/processor/processor_point_feet_nomove.cpp +++ b/src/processor/processor_point_feet_nomove.cpp @@ -34,8 +34,14 @@ namespace wolf{ inline ProcessorPointFeetNomove::ProcessorPointFeetNomove(ParamsProcessorPointFeetNomovePtr _params_pfnomove) : ProcessorBase("ProcessorPointFeetNomove", 3, _params_pfnomove), - params_pfnomove_(std::make_shared<ParamsProcessorPointFeetNomove>(*_params_pfnomove)) + params_pfnomove_(std::make_shared<ParamsProcessorPointFeetNomove>(*_params_pfnomove)), + origin_(nullptr) { + // Init tracks to nothing + + for (int i=0; i < 4; i++){ + tracks_[0] = nullptr; + } } @@ -43,7 +49,119 @@ void ProcessorPointFeetNomove::configure(SensorBasePtr _sensor) { } -void ProcessorPointFeetNomove::createFactorIfNecessary(){ + + +inline void ProcessorPointFeetNomove::processCapture(CaptureBasePtr _capture) +{ + if (!_capture) + { + WOLF_ERROR("Received capture is nullptr."); + return; + } + incoming_ = _capture; + + // nothing to do if any of the two buffer is empty + if(buffer_frame_.empty()){ + WOLF_DEBUG("PInertialKinematic: KF pack buffer empty, time ", _capture->getTimeStamp()); + return; + } + if(buffer_frame_.empty()){ + WOLF_DEBUG("PInertialKinematics: Capture buffer empty, time ", _capture->getTimeStamp()); + return; + } + + createFactorConsecutive(); + // processCaptureCreateFactorFar(_capture); + +} + +inline void ProcessorPointFeetNomove::processKeyFrame(FrameBasePtr _keyframe_ptr) +{ + if (!_keyframe_ptr) + { + WOLF_ERROR("Received KF is nullptr."); + return; + } + // nothing to do if any of the two buffer is empty + if(buffer_frame_.empty()){ + WOLF_DEBUG("ProcessorPointFeetNomove: KF pack buffer empty, time ", _keyframe_ptr->getTimeStamp()); + return; + } + if(buffer_frame_.empty()){ + WOLF_DEBUG("ProcessorPointFeetNomove: Capture buffer empty, time ", _keyframe_ptr->getTimeStamp()); + return; + } + + createFactorConsecutive(); + // processKeyFrameCreateFactorFar(); + +} + +void ProcessorPointFeetNomove::processCaptureCreateFactorFar(CaptureBasePtr _capture){ + // Far away factors + auto cap_curr = std::static_pointer_cast<CapturePointFeetNomove>(_capture); + auto kin_incontact_current = cap_curr->kin_incontact_; + for (int i=0; i<4; i++){ + if (!kin_incontact_current.count(i)){ + tracks_[i] = nullptr; + } + } +} + +void ProcessorPointFeetNomove::processKeyFrameCreateFactorFar(){ + + auto sensor_pfnm = std::static_pointer_cast<SensorPointFeetNomove>(getSensor()); + + for (auto kf_it: buffer_frame_.getContainer()){ + TimeStamp ts = kf_it.first; + auto kf = kf_it.second; + auto cap_it = buffer_capture_.selectIterator(ts, params_->time_tolerance); + + // We have a match between the KF and a capture from the capture buffer + if (cap_it != buffer_capture_.getContainer().end()){ + auto cap_curr = std::static_pointer_cast<CapturePointFeetNomove>(cap_it->second); + + for (auto kin: cap_curr->kin_incontact_){ + // check if each leg in contact has a current active track + int leg_id = kin.first; + auto cap_origin = tracks_[leg_id]; + if (!cap_origin){ + // if not, define current KF as the leg track origin and link the capture to this KF + // Error occurs if we try to link several time the same Cap->kf due to the loop on legs -> do only once + if (!cap_curr->getFrame()){ + cap_curr->link(kf); + } + tracks_[leg_id] = cap_curr; + } + else { + if (!cap_curr->getFrame()){ + cap_curr->link(kf); + } + // if it has, create a factor + auto cap_origin = std::static_pointer_cast<CapturePointFeetNomove>(tracks_[leg_id]); + Matrix<double, 14, 1> meas; meas << cap_origin->kin_incontact_[leg_id], kin.second; + double dt_kf = cap_curr->getTimeStamp() - cap_origin->getTimeStamp(); + Matrix3d cov_int = dt_kf*sensor_pfnm->getCovFootNomove(); // integrate zero velocity cov during dt_kf + // Matrix3d cov_int = sensor_pfnm->getCovFootNomove(); // integrate zero velocity cov during dt_kf + FeatureBasePtr feat = FeatureBase::emplace<FeatureBase>(cap_curr, "PointFeet", meas, cov_int); + FactorPointFeetNomovePtr fac = FactorBase::emplace<FactorPointFeetNomove>(feat, feat, cap_origin->getFrame(), nullptr, true); + + // Zero Altitude factor + Vector4d meas_altitude; meas_altitude << kin.second.head<3>(), 0; + Matrix1d alt_cov = pow(0.01, 2)*Matrix1d::Identity(); + CaptureBasePtr cap_alt = CaptureBase::emplace<CaptureBase>(kf, "Alt0", cap_curr->getTimeStamp()); + FeatureBasePtr feat_alt = FeatureBase::emplace<FeatureBase>(cap_alt, "Alt0", meas_altitude, alt_cov); + FactorBasePtr fac_alt = FactorBase::emplace<FactorPointFeetAltitude>(feat_alt, feat_alt, nullptr, true); + } + } + buffer_frame_.removeUpTo(cap_curr->getTimeStamp()); + buffer_capture_.removeUpTo(cap_curr->getTimeStamp()); + } + } +} + +void ProcessorPointFeetNomove::createFactorConsecutive(){ + auto sensor_pfnm = std::static_pointer_cast<SensorPointFeetNomove>(getSensor()); while (buffer_frame_.size() >= 2) @@ -66,23 +184,22 @@ void ProcessorPointFeetNomove::createFactorIfNecessary(){ // store the initial contact/kinematic meas map auto cap1 = std::static_pointer_cast<CapturePointFeetNomove>(cap1_it->second); auto kin_incontact_from_t1 = cap1->kin_incontact_; - std::cout << kin_incontact_from_t1.size() << " "; - + // then loop over the captures in between cap1 and cap2 auto cap_it = std::next(cap1_it); - auto it_after_capt_t2 = std::next(cap2_it); + auto it_after_capt_t2 = std::next(cap2_it); // used to detect the end of the loop // loop throught the captures between t1 and t2 while (cap_it != it_after_capt_t2){ // for each new capture, filter the initial contact/kin meas map to track which feet stay in contact throughout - auto cap_pfeet = std::static_pointer_cast<CapturePointFeetNomove>(cap_it->second); - if (!cap_pfeet){ - + auto cap_curr = std::static_pointer_cast<CapturePointFeetNomove>(cap_it->second); + if (!cap_curr){ + WOLF_ERROR("Wrong capture type in buffer") } - auto kin_incontact_current = cap_pfeet->kin_incontact_; - // std::cout << kin_incontact_current.size() << " "; - + // check which feet are currently in contact, if one is missing wrt the previous + // timestamp, remove it from kin_incontact_from_t1 + auto kin_incontact_current = cap_curr->kin_incontact_; for (auto elt_it = kin_incontact_from_t1.cbegin(); elt_it != kin_incontact_from_t1.cend(); /* no increment */){ if (kin_incontact_current.find(elt_it->first) == kin_incontact_current.end()){ // The foot has lost contact with the ground since t1 @@ -94,7 +211,6 @@ void ProcessorPointFeetNomove::createFactorIfNecessary(){ } cap_it++; } - // std::cout << std::endl; if (!kin_incontact_from_t1.empty()) { @@ -107,9 +223,18 @@ void ProcessorPointFeetNomove::createFactorIfNecessary(){ for (auto kin_pair1: kin_incontact_from_t1){ auto kin_pair2_it = kin_incontact_t2.find(kin_pair1.first); - Vector6d meas; meas << kin_pair1.second, kin_pair2_it->second; - FeatureBasePtr feat = FeatureBase::emplace<FeatureBase>(cap2, "PointFeet", meas, sensor_pfnm->getCovFootNomove()); + Matrix<double, 14, 1> meas; meas << kin_pair1.second, kin_pair2_it->second; + double dt_kf = cap2->getTimeStamp() - cap1->getTimeStamp(); + Matrix3d cov_int = dt_kf*sensor_pfnm->getCovFootNomove(); // integrate zero velocity cov during dt_kf + FeatureBasePtr feat = FeatureBase::emplace<FeatureBase>(cap2, "PointFeet", meas, cov_int); FactorPointFeetNomovePtr fac = FactorBase::emplace<FactorPointFeetNomove>(feat, feat, kf1_it->second, nullptr, true); + + // Zero Altitude factor + Vector4d meas_altitude; meas_altitude << kin_pair2_it->second.head<3>(), 0; + Matrix1d alt_cov = pow(0.01, 2)*Matrix1d::Identity(); + CaptureBasePtr cap_alt = CaptureBase::emplace<CaptureBase>(kf2_it->second, "Alt0", cap2->getTimeStamp()); + FeatureBasePtr feat_alt = FeatureBase::emplace<FeatureBase>(cap_alt, "Alt0", meas_altitude, alt_cov); + FactorBasePtr fac_alt = FactorBase::emplace<FactorPointFeetAltitude>(feat_alt, feat_alt, nullptr, true); } } @@ -122,51 +247,15 @@ void ProcessorPointFeetNomove::createFactorIfNecessary(){ } -inline void ProcessorPointFeetNomove::processCapture(CaptureBasePtr _capture) -{ - if (!_capture) - { - WOLF_ERROR("Received capture is nullptr."); - return; - } - // nothing to do if any of the two buffer is empty - if(buffer_frame_.empty()){ - WOLF_DEBUG("PInertialKinematic: KF pack buffer empty, time ", _capture->getTimeStamp()); - return; - } - if(buffer_frame_.empty()){ - WOLF_DEBUG("PInertialKinematics: Capture buffer empty, time ", _capture->getTimeStamp()); - return; - } - - createFactorIfNecessary(); -} -inline void ProcessorPointFeetNomove::processKeyFrame(FrameBasePtr _keyframe_ptr) +inline bool ProcessorPointFeetNomove::voteForKeyFrame() const { - if (!_keyframe_ptr) - { - WOLF_ERROR("Received KF is nullptr."); - return; - } - // nothing to do if any of the two buffer is empty - if(buffer_frame_.empty()){ - WOLF_DEBUG("ProcessorPointFeetNomove: KF pack buffer empty, time ", _keyframe_ptr->getTimeStamp()); - return; - } - if(buffer_frame_.empty()){ - WOLF_DEBUG("ProcessorPointFeetNomove: Capture buffer empty, time ", _keyframe_ptr->getTimeStamp()); - return; - } - - createFactorIfNecessary(); + return false; } - - } /* namespace wolf */ // Register in the FactoryProcessor diff --git a/src/sensor/sensor_point_feet_nomove.cpp b/src/sensor/sensor_point_feet_nomove.cpp index 6e5a48b7c058aa152ad4179404a061e7fe74dedd..45d1c1ade0ac9cd8fe92ce44f01033b30933602b 100644 --- a/src/sensor/sensor_point_feet_nomove.cpp +++ b/src/sensor/sensor_point_feet_nomove.cpp @@ -36,6 +36,8 @@ SensorPointFeetNomove::SensorPointFeetNomove(const Eigen::VectorXd& _extrinsics_ assert(_extrinsics_pq.size() == 0 && "Bad extrinsics vector size! Should be 0 since not used."); cov_foot_nomove_ = pow(_params->std_foot_nomove_, 2)*Matrix3d::Identity(); + cov_altitude_ = pow(_params->std_altitude_, 2)*Matrix1d::Identity(); + foot_radius_ = _params->foot_radius_; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 60f23c1fe3f823d3c1c848365735928550d24095..5850e2db6763d74e6385f16417ed48102091ba5b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,66 +1,33 @@ # Retrieve googletest from github & compile add_subdirectory(gtest) - -## Added these two include_dirs: ###################### -# -#CMAKE modules -#SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules") -#MESSAGE(STATUS ${CMAKE_MODULE_PATH}) -# -# Include Eigen -#FIND_PACKAGE(Eigen 3 REQUIRED) -#INCLUDE_DIRECTORIES(${EIGEN_INCLUDE_DIRS}) -# -# Include Ceres -#FIND_PACKAGE(Ceres QUIET) #Ceres is not required -#IF(Ceres_FOUND) -# INCLUDE_DIRECTORIES(${CERES_INCLUDE_DIRS}) -#ENDIF(Ceres_FOUND) -# -## and now gtest_motion_2d works ###################### - - -# Include gtest directory. -include_directories(${GTEST_INCLUDE_DIRS}) - -################# ADD YOUR TESTS BELOW #################### +############# USE THIS TEST AS AN EXAMPLE ################# # # -# ==== IN ALPHABETICAL ORDER! ==== # +# Create a specific test executable for gtest_example # +# wolf_add_gtest(gtest_example gtest_example.cpp) # # # +########################################################### + wolf_add_gtest(gtest_capture_inertial_kinematics gtest_capture_inertial_kinematics.cpp) -target_link_libraries(gtest_capture_inertial_kinematics ${PLUGIN_NAME}) wolf_add_gtest(gtest_capture_leg_odom gtest_capture_leg_odom.cpp) -target_link_libraries(gtest_capture_leg_odom ${PLUGIN_NAME}) wolf_add_gtest(gtest_feature_inertial_kinematics gtest_feature_inertial_kinematics.cpp) -target_link_libraries(gtest_feature_inertial_kinematics ${PLUGIN_NAME}) wolf_add_gtest(gtest_factor_inertial_kinematics gtest_factor_inertial_kinematics.cpp) -target_link_libraries(gtest_factor_inertial_kinematics ${PLUGIN_NAME}) wolf_add_gtest(gtest_factor_force_torque gtest_factor_force_torque.cpp) -target_link_libraries(gtest_factor_force_torque ${PLUGIN_NAME}) wolf_add_gtest(gtest_force_torque_delta_tools gtest_force_torque_delta_tools.cpp) -target_link_libraries(gtest_force_torque_delta_tools ${PLUGIN_NAME}) +# TODO: revive those # wolf_add_gtest(gtest_feature_force_torque_preint gtest_feature_force_torque_preint.cpp) -# target_link_libraries(gtest_feature_force_torque_preint ${PLUGIN_NAME}) - # wolf_add_gtest(gtest_processor_inertial_kinematics gtest_processor_inertial_kinematics.cpp) -# target_link_libraries(gtest_processor_inertial_kinematics ${PLUGIN_NAME}) - # wolf_add_gtest(gtest_processor_force_torque_preint gtest_processor_force_torque_preint.cpp) -# target_link_libraries(gtest_processor_force_torque_preint ${PLUGIN_NAME}) wolf_add_gtest(gtest_processor_point_feet_nomove gtest_processor_point_feet_nomove.cpp) -target_link_libraries(gtest_processor_point_feet_nomove ${PLUGIN_NAME}) wolf_add_gtest(gtest_sensor_force_torque gtest_sensor_force_torque.cpp) -target_link_libraries(gtest_sensor_force_torque ${PLUGIN_NAME}) wolf_add_gtest(gtest_sensor_inertial_kinematics gtest_sensor_inertial_kinematics.cpp) -target_link_libraries(gtest_sensor_inertial_kinematics ${PLUGIN_NAME}) diff --git a/test/gtest/CMakeLists.txt b/test/gtest/CMakeLists.txt index 559756b02472653c655c44152c452ba8767ef6f2..2294c819aec95c1f2c6bed5c0e7b1d6cc857c614 100644 --- a/test/gtest/CMakeLists.txt +++ b/test/gtest/CMakeLists.txt @@ -1,65 +1,73 @@ -cmake_minimum_required(VERSION 2.8.8) -project(gtest_builder C CXX) +if(${CMAKE_VERSION} VERSION_LESS "3.11.0") + message("CMake version less than 3.11.0") -# We need thread support -#find_package(Threads REQUIRED) + # Enable ExternalProject CMake module + include(ExternalProject) -# Enable ExternalProject CMake module -include(ExternalProject) + set(GTEST_FORCE_SHARED_CRT ON) + set(GTEST_DISABLE_PTHREADS ON) # without this in ubuntu 18.04 we get linking errors -set(GTEST_FORCE_SHARED_CRT ON) -set(GTEST_DISABLE_PTHREADS OFF) + # Download GoogleTest + ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.8.x + # TIMEOUT 1 # We'll try this + CMAKE_ARGS -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG:PATH=DebugLibs + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE:PATH=ReleaseLibs + -DCMAKE_CXX_FLAGS=${MSVC_COMPILER_DEFS} + -Dgtest_force_shared_crt=${GTEST_FORCE_SHARED_CRT} + -Dgtest_disable_pthreads=${GTEST_DISABLE_PTHREADS} + -DBUILD_GTEST=ON + PREFIX "${CMAKE_CURRENT_BINARY_DIR}" + # Disable install step + INSTALL_COMMAND "" + UPDATE_DISCONNECTED 1 # 1: do not update googletest; 0: update googletest via github + ) -# For some reason I need to disable PTHREADS -# with g++ (Ubuntu 4.9.3-8ubuntu2~14.04) 4.9.3 -# This is a known issue for MinGW : -# https://github.com/google/shaderc/pull/174 -#if(MINGW) - set(GTEST_DISABLE_PTHREADS ON) -#endif() + # Get GTest source and binary directories from CMake project -# Download GoogleTest -ExternalProject_Add(googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.8.x - # TIMEOUT 1 # We'll try this - CMAKE_ARGS -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG:PATH=DebugLibs - -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE:PATH=ReleaseLibs - -DCMAKE_CXX_FLAGS=${MSVC_COMPILER_DEFS} - -Dgtest_force_shared_crt=${GTEST_FORCE_SHARED_CRT} - -Dgtest_disable_pthreads=${GTEST_DISABLE_PTHREADS} - -DBUILD_GTEST=ON - PREFIX "${CMAKE_CURRENT_BINARY_DIR}" - # Disable install step - INSTALL_COMMAND "" - UPDATE_DISCONNECTED 1 # 1: do not update googletest; 0: update googletest via github -) + # Specify include dir + ExternalProject_Get_Property(googletest source_dir) + set(GTEST_INCLUDE_DIRS ${source_dir}/googletest/include PARENT_SCOPE) -# Get GTest source and binary directories from CMake project + # Specify MainTest's link libraries + ExternalProject_Get_Property(googletest binary_dir) + set(GTEST_LIBS_DIR ${binary_dir}/googlemock/gtest PARENT_SCOPE) -# Specify include dir -ExternalProject_Get_Property(googletest source_dir) -set(GTEST_INCLUDE_DIRS ${source_dir}/googletest/include PARENT_SCOPE) + # Create a libgtest target to be used as a dependency by test programs + add_library(libgtest IMPORTED STATIC GLOBAL) + add_dependencies(libgtest googletest) -# Specify MainTest's link libraries -ExternalProject_Get_Property(googletest binary_dir) -set(GTEST_LIBS_DIR ${binary_dir}/googlemock/gtest PARENT_SCOPE) + # Set libgtest properties + set_target_properties(libgtest PROPERTIES + "IMPORTED_LOCATION" "${binary_dir}/googlemock/gtest/libgtest.a" + "IMPORTED_LINK_INTERFACE_LIBRARIES" "${CMAKE_THREAD_LIBS_INIT}" + ) -# Create a libgtest target to be used as a dependency by test programs -add_library(libgtest IMPORTED STATIC GLOBAL) -add_dependencies(libgtest googletest) +else() -# Set libgtest properties -set_target_properties(libgtest PROPERTIES - "IMPORTED_LOCATION" "${binary_dir}/googlemock/gtest/libgtest.a" - "IMPORTED_LINK_INTERFACE_LIBRARIES" "${CMAKE_THREAD_LIBS_INIT}" -) + message("CMake version equal or greater than 3.11.0") + include(FetchContent) + + FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG main) + + SET(INSTALL_GTEST OFF) # Disable installation of googletest + FetchContent_MakeAvailable(googletest) + +endif() + function(wolf_add_gtest target) add_executable(${target} ${ARGN}) - add_dependencies(${target} libgtest) - target_link_libraries(${target} libgtest) - - #WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin + if(${CMAKE_VERSION} VERSION_LESS "3.11.0") + add_dependencies(${target} libgtest) + target_link_libraries(${target} PUBLIC libgtest ${PLUGIN_NAME}) + target_include_directories(${target} PUBLIC ${GTEST_INCLUDE_DIRS}) + else() + target_link_libraries(${target} PUBLIC gtest_main ${PLUGIN_NAME}) + endif() add_test(NAME ${target} COMMAND ${target}) endfunction() diff --git a/test/gtest_processor_point_feet_nomove.cpp b/test/gtest_processor_point_feet_nomove.cpp index 2a246f3a1292c1b96a74ffeecb7c1ec65bc66471..ac09e66fcc1747aee3e28ecec1e47867f4d3a3c4 100644 --- a/test/gtest_processor_point_feet_nomove.cpp +++ b/test/gtest_processor_point_feet_nomove.cpp @@ -111,11 +111,11 @@ class PointFeetCaptures : public testing::Test KF0_ = problem_->getTrajectory()->getLastFrame(); // Simulate captures with 4 point feet - std::unordered_map<int, Vector3d> kin_incontact_A({ - {1, Vector3d::Zero()}, - {2, Vector3d::Zero()}, - {3, Vector3d::Zero()}, - {4, Vector3d::Zero()} + std::unordered_map<int, Vector7d> kin_incontact_A({ + {1, Vector7d::Zero()}, + {2, Vector7d::Zero()}, + {3, Vector7d::Zero()}, + {4, Vector7d::Zero()} }); CPF0_ = std::make_shared<CapturePointFeetNomove>(0.0, sen_pfnm_, kin_incontact_A); @@ -124,18 +124,18 @@ class PointFeetCaptures : public testing::Test CPF2_ = std::make_shared<CapturePointFeetNomove>(2.0, sen_pfnm_, kin_incontact_A); // contact of the 2nd foot lost - std::unordered_map<int, Eigen::Vector3d> kin_incontact_B({ - {1, Vector3d::Ones()}, - {3, Vector3d::Ones()}, - {4, Vector3d::Ones()} + std::unordered_map<int, Eigen::Vector7d> kin_incontact_B({ + {1, Vector7d::Ones()}, + {3, Vector7d::Ones()}, + {4, Vector7d::Ones()} }); CPF3_ = std::make_shared<CapturePointFeetNomove>(3.0, sen_pfnm_, kin_incontact_B); CPF4_ = std::make_shared<CapturePointFeetNomove>(4.0, sen_pfnm_, kin_incontact_B); // contact of the 3rd foot lost - std::unordered_map<int, Eigen::Vector3d> kin_incontact_C({ - {1, 2*Vector3d::Ones()}, - {4, 2*Vector3d::Ones()} + std::unordered_map<int, Eigen::Vector7d> kin_incontact_C({ + {1, 2*Vector7d::Ones()}, + {4, 2*Vector7d::Ones()} }); CPF5_ = std::make_shared<CapturePointFeetNomove>(5.0, sen_pfnm_, kin_incontact_C); CPF6_ = std::make_shared<CapturePointFeetNomove>(6.0, sen_pfnm_, kin_incontact_C);