···88 */
991010#include "xrt/xrt_config_have.h"
1111+#include "xrt/xrt_defines.h"
1112#include "xrt/xrt_tracking.h"
1213#include "xrt/xrt_frameserver.h"
1314#include "util/u_debug.h"
···1516#include "util/u_misc.h"
1617#include "util/u_var.h"
1718#include "os/os_threading.h"
1919+#include "math/m_api.h"
1820#include "math/m_filter_fifo.h"
1921#include "math/m_filter_one_euro.h"
2022#include "math/m_predict.h"
···3234#include <fstream>
3335#include <iomanip>
3436#include <map>
3737+#include <string>
35383639#define SLAM_TRACE(...) U_LOG_IFL_T(t.log_level, __VA_ARGS__)
3740#define SLAM_DEBUG(...) U_LOG_IFL_D(t.log_level, __VA_ARGS__)
···5962#endif
60636164//! @see t_slam_tracker_config
6262-DEBUG_GET_ONCE_LOG_OPTION(slam_log, "SLAM_LOG", U_LOGGING_WARN)
6565+DEBUG_GET_ONCE_LOG_OPTION(slam_log, "SLAM_LOG", U_LOGGING_INFO)
6366DEBUG_GET_ONCE_OPTION(slam_config, "SLAM_CONFIG", nullptr)
6467DEBUG_GET_ONCE_BOOL_OPTION(slam_submit_from_start, "SLAM_SUBMIT_FROM_START", false)
6568DEBUG_GET_ONCE_NUM_OPTION(slam_prediction_type, "SLAM_PREDICTION_TYPE", long(SLAM_PRED_SP_SO_IA_SL))
···7275constexpr int UI_GTDIFF_POSE_COUNT = 192;
73767477using std::ifstream;
7878+using std::make_shared;
7579using std::make_unique;
7680using std::map;
7781using std::ofstream;
7882using std::shared_ptr;
7983using std::string;
8484+using std::to_string;
8085using std::unique_ptr;
8186using std::vector;
8287using std::filesystem::create_directories;
···778783 // Later, gt_ui_setup will setup the tracking error UI if ground truth becomes available
779784}
780785786786+static void
787787+add_camera_calibration(const TrackerSlam &t,
788788+ const t_stereo_camera_calibration *stereo_calib,
789789+ const t_slam_calib_extras *extra_calib)
790790+{
791791+ for (int i = 0; i < 2; i++) {
792792+ const t_camera_calibration &view = stereo_calib->view[i];
793793+ const auto &extra = extra_calib->cams[i];
794794+ const auto params = make_shared<FPARAMS_ACC>();
795795+796796+ params->cam_index = i;
797797+ params->width = view.image_size_pixels.w;
798798+ params->height = view.image_size_pixels.h;
799799+ params->frequency = extra.frequency;
800800+801801+ params->fx = view.intrinsics[0][0];
802802+ params->fy = view.intrinsics[1][1];
803803+ params->cx = view.intrinsics[0][2];
804804+ params->cy = view.intrinsics[1][2];
805805+806806+ params->distortion_model = view.use_fisheye ? "kb4" : string{"rt"} + to_string(view.distortion_num);
807807+ if (view.use_fisheye) { // Kannala-brandt pinhole (OpenCV's "fisheye")
808808+ params->distortion.assign(view.distortion_fisheye, std::end(view.distortion_fisheye));
809809+ SLAM_ASSERT_(params->distortion.size() == 4);
810810+ } else { // Radial-tangential pinhole
811811+ params->distortion.assign(view.distortion, view.distortion + view.distortion_num);
812812+813813+ if (params->distortion_model == "rt8") { // rt8 has a ninth parameter rpmax ("metric_radius")
814814+ params->distortion.push_back(extra.rpmax);
815815+ }
816816+ }
817817+818818+ xrt_matrix_4x4 T; // Row major T_imu_cam
819819+ math_matrix_4x4_transpose(&extra.T_imu_cam, &T);
820820+ params->t_imu_cam = cv::Matx<float, 4, 4>{T.v};
821821+822822+ shared_ptr<FRESULT_ACC> result{};
823823+ t.slam->use_feature(F_ADD_CAMERA_CALIBRATION, params, result);
824824+ }
825825+}
826826+827827+static void
828828+add_imu_calibration(const TrackerSlam &t, const t_imu_calibration *imu_calib, const t_slam_calib_extras *extra_calib)
829829+{
830830+ const auto params = make_shared<FPARAMS_AIC>();
831831+ params->imu_index = 0; // Multiple IMU setups unsupported
832832+ params->frequency = extra_calib->imu_frequency;
833833+834834+ const t_inertial_calibration &accel = imu_calib->accel;
835835+ params->accel.transform = cv::Matx<double, 3, 3>{&accel.transform[0][0]};
836836+ params->accel.offset = cv::Matx<double, 3, 1>{&accel.offset[0]};
837837+ params->accel.bias_std = cv::Matx<double, 3, 1>{&accel.bias_std[0]};
838838+ params->accel.noise_std = cv::Matx<double, 3, 1>{&accel.noise_std[0]};
839839+840840+ const t_inertial_calibration &gyro = imu_calib->gyro;
841841+ params->gyro.transform = cv::Matx<double, 3, 3>{&gyro.transform[0][0]};
842842+ params->gyro.offset = cv::Matx<double, 3, 1>{&gyro.offset[0]};
843843+ params->gyro.bias_std = cv::Matx<double, 3, 1>{&gyro.bias_std[0]};
844844+ params->gyro.noise_std = cv::Matx<double, 3, 1>{&gyro.noise_std[0]};
845845+846846+ shared_ptr<FRESULT_AIC> result{};
847847+ t.slam->use_feature(F_ADD_IMU_CALIBRATION, params, result);
848848+}
849849+781850} // namespace xrt::auxiliary::tracking::slam
782851783852using namespace xrt::auxiliary::tracking::slam;
···9601029 config->prediction = t_slam_prediction_type(debug_get_num_option_slam_prediction_type());
9611030 config->write_csvs = debug_get_bool_option_slam_write_csvs();
9621031 config->csv_path = debug_get_option_slam_csv_path();
10321032+ config->stereo_calib = NULL;
10331033+ config->imu_calib = NULL;
10341034+ config->extra_calib = NULL;
9631035}
96410369651037extern "C" int
···9681040 struct xrt_tracked_slam **out_xts,
9691041 struct xrt_slam_sinks **out_sink)
9701042{
971971- struct t_slam_tracker_config *default_config = nullptr;
10431043+ struct t_slam_tracker_config default_config = {};
9721044 if (config == nullptr) {
973973- default_config = U_TYPED_CALLOC(struct t_slam_tracker_config);
974974- t_slam_fill_default_config(default_config);
975975- config = default_config;
10451045+ t_slam_fill_default_config(&default_config);
10461046+ config = &default_config;
9761047 }
97710489781049 enum u_logging_level log_level = config->log_level;
···99310649941065 // Check the user has provided a SLAM_CONFIG file
9951066 const char *config_file = config->slam_config;
996996- if (!config_file) {
997997- U_LOG_IFL_W(log_level,
998998- "SLAM tracker requires a config file set with the SLAM_CONFIG environment variable");
10671067+ bool some_calib = config->stereo_calib || config->imu_calib;
10681068+ if (!config_file && !some_calib) {
10691069+ U_LOG_IFL_W(log_level, "Unable to determine sensor calibration, did you forgot to set SLAM_CONFIG?");
9991070 return -1;
10711071+ }
10721072+10731073+ if (!config_file) {
10741074+ // Indicate the external system to use default (non-calibration) settings
10751075+ config_file = "DEFAULT";
10001076 }
1001107710021078 auto &t = *(new TrackerSlam{});
···10081084 std::string config_file_string = std::string(config_file);
10091085 t.slam = new slam_tracker{config_file_string};
1010108610871087+ // Try to send camera calibration data to the SLAM system
10881088+ if (config->stereo_calib && config->extra_calib && t.slam->supports_feature(F_ADD_CAMERA_CALIBRATION)) {
10891089+ SLAM_INFO("Sending Camera calibration from Monado");
10901090+ add_camera_calibration(t, config->stereo_calib, config->extra_calib);
10911091+ } else {
10921092+ SLAM_INFO("Cameras will use the calibration provided by the SLAM_CONFIG file");
10931093+ }
10941094+10951095+ // Try to send IMU calibration data to the SLAM system
10961096+ if (config->imu_calib && config->extra_calib && t.slam->supports_feature(F_ADD_IMU_CALIBRATION)) {
10971097+ SLAM_INFO("Sending IMU calibration from Monado");
10981098+ add_imu_calibration(t, config->imu_calib, config->extra_calib);
10991099+ } else {
11001100+ SLAM_INFO("The IMU will use the calibration provided by the SLAM_CONFIG file");
11011101+ }
11021102+10111103 t.slam->initialize();
1012110410131105 t.left_sink.push_frame = t_slam_frame_sink_push_left;
···10621154 t.filt_traj_writer = new TrajectoryWriter{dir, "filtering.csv", write_csvs};
1063115510641156 setup_ui(t);
10651065-10661066- if (default_config != nullptr) {
10671067- free(default_config);
10681068- }
1069115710701158 *out_xts = &t.base;
10711159 *out_sink = &t.sinks;
+31-4
src/xrt/auxiliary/tracking/t_tracking.h
···1212#pragma once
13131414#include "util/u_logging.h"
1515+#include "xrt/xrt_defines.h"
1516#include "xrt/xrt_frame.h"
1617#include "util/u_misc.h"
1718···422423423424424425425425-//! SLAM prediction type. Naming scheme as follows:
426426-//! P: position, O: orientation, A: angular velocity, L: linear velocity
427427-//! S: From SLAM poses (slow, precise), I: From IMU data (fast, noisy)
426426+/*!
427427+ * SLAM prediction type. Naming scheme as follows:
428428+ * P: position, O: orientation, A: angular velocity, L: linear velocity
429429+ * S: From SLAM poses (slow, precise), I: From IMU data (fast, noisy)
430430+ *
431431+ * @see xrt_tracked_slam
432432+ */
428433enum t_slam_prediction_type
429434{
430435 SLAM_PRED_NONE = 0, //!< No prediction, always return the last SLAM tracked pose
···435440};
436441437442/*!
443443+ * This struct complements calibration data from @ref
444444+ * t_stereo_camera_calibration and @ref t_imu_calibration
445445+ *
446446+ * @see xrt_tracked_slam
447447+ */
448448+struct t_slam_calib_extras
449449+{
450450+ double imu_frequency; //! IMU samples per second
451451+ struct
452452+ {
453453+ double frequency; //!< Camera FPS
454454+ struct xrt_matrix_4x4 T_imu_cam; //!< Transform IMU to camera. Column major.
455455+ float rpmax; //!< Used for rt8 calibrations. Rpmax or "metric_radius" property.
456456+ } cams[2];
457457+};
458458+459459+/*!
438460 * SLAM tracker configuration.
439461 *
440462 * @see xrt_tracked_slam
···444466 enum u_logging_level log_level; //!< SLAM tracking logging level
445467 const char *slam_config; //!< Config file path, format is specific to the SLAM implementation in use
446468 bool submit_from_start; //!< Whether to submit data to the SLAM tracker without user action
447447- enum t_slam_prediction_type prediction; //! Which level of prediction to use
469469+ enum t_slam_prediction_type prediction; //!< Which level of prediction to use
448470 bool write_csvs; //!< Whether to enable CSV writers from the start for later analysis
449471 const char *csv_path; //!< Path to write CSVs to
472472+473473+ // Instead of a slam_config file you can set custom calibration data
474474+ const struct t_stereo_camera_calibration *stereo_calib; //!< Camera calibration data
475475+ const struct t_imu_calibration *imu_calib; //!< IMU calibration data
476476+ const struct t_slam_calib_extras *extra_calib; //!< Extra calibration data
450477};
451478452479/*!