···1111#include "xrt/xrt_tracking.h"
1212#include "xrt/xrt_frameserver.h"
1313#include "util/u_debug.h"
1414+#include "util/u_logging.h"
1515+#include "util/u_misc.h"
1416#include "util/u_var.h"
1517#include "os/os_threading.h"
1618#include "math/m_filter_fifo.h"
···2022#include "math/m_space.h"
2123#include "math/m_vec3.h"
2224#include "tracking/t_euroc_recorder.h"
2525+#include "tracking/t_tracking.h"
23262427#include <slam_tracker.hpp>
2528#include <opencv2/core/mat.hpp>
···5558#define SLAM_DASSERT_(predicate) SLAM_ASSERT_(predicate)
5659#endif
57605858-//! SLAM tracking logging level
6161+//! @see t_slam_tracker_config
5962DEBUG_GET_ONCE_LOG_OPTION(slam_log, "SLAM_LOG", U_LOGGING_WARN)
6060-6161-//! Config file path, format is specific to the SLAM implementation in use
6262-DEBUG_GET_OPTION(slam_config, "SLAM_CONFIG", NULL)
6363-6464-//! Whether to submit data to the SLAM tracker without user action
6363+DEBUG_GET_ONCE_OPTION(slam_config, "SLAM_CONFIG", nullptr)
6564DEBUG_GET_ONCE_BOOL_OPTION(slam_submit_from_start, "SLAM_SUBMIT_FROM_START", false)
6666-6767-//! Which level of prediction to use, @see prediction_type.
6868-DEBUG_GET_ONCE_NUM_OPTION(slam_prediction_type, "SLAM_PREDICTION_TYPE", 2)
6969-7070-//! Whether to enable CSV writers from the start for later analysis
6565+DEBUG_GET_ONCE_NUM_OPTION(slam_prediction_type, "SLAM_PREDICTION_TYPE", long(SLAM_PRED_SP_SO_IA_SL))
7166DEBUG_GET_ONCE_BOOL_OPTION(slam_write_csvs, "SLAM_WRITE_CSVS", false)
7272-7373-//! Path to write CSVs to
7474-DEBUG_GET_OPTION(slam_csv_path, "SLAM_CSV_PATH", "evaluation/")
6767+DEBUG_GET_ONCE_OPTION(slam_csv_path, "SLAM_CSV_PATH", "evaluation/")
75687669//! Namespace for the interface to the external SLAM tracking system
7770namespace xrt::auxiliary::tracking::slam {
···193186 bool enabled; // Modified through UI
194187195188private:
189189+ string directory;
196190 string filename;
197191 ofstream file;
198192 bool created = false;
···200194 void
201195 create()
202196 {
203203- string csv_path = debug_get_option_slam_csv_path();
204204- create_directories(csv_path);
205205- file = ofstream{csv_path + "/" + filename};
197197+ create_directories(directory);
198198+ file = ofstream{directory + "/" + filename};
206199 file << "#timestamp [ns], p_RS_R_x [m], p_RS_R_y [m], p_RS_R_z [m], "
207200 "q_RS_w [], q_RS_x [], q_RS_y [], q_RS_z []" CSV_EOL;
208201 file << std::fixed << std::setprecision(CSV_PRECISION);
···210203211204212205public:
213213- TrajectoryWriter(const string &fn, bool e) : enabled(e), filename(fn) {}
206206+ TrajectoryWriter(const string &dir, const string &fn, bool e) : enabled(e), directory(dir), filename(fn) {}
214207215208 void
216209 push(timepoint_ns ts, const xrt_pose &pose)
···239232 bool enabled; // Modified through UI
240233241234private:
235235+ string directory;
242236 string filename;
243237 vector<string> column_names;
244238 ofstream file;
···247241 void
248242 create()
249243 {
250250- string csv_path = debug_get_option_slam_csv_path();
251251- create_directories(csv_path);
252252- file = ofstream{csv_path + "/" + filename};
244244+ create_directories(directory);
245245+ file = ofstream{directory + "/" + filename};
253246 file << "#";
254247 for (const string &col : column_names) {
255248 string delimiter = &col != &column_names.back() ? "," : CSV_EOL;
···258251 }
259252260253public:
261261- TimingWriter(const string &fn, bool e, const vector<string> &cn) : enabled(e), filename(fn), column_names(cn) {}
254254+ TimingWriter(const string &dir, const string &fn, bool e, const vector<string> &cn)
255255+ : enabled(e), directory(dir), filename(fn), column_names(cn)
256256+ {}
262257263258 void
264259 push(const vector<timepoint_ns> ×tamps)
···279274 }
280275};
281276282282-//! SLAM prediction type. Naming scheme as follows:
283283-//! P: position, O: orientation, A: angular velocity, L: linear velocity
284284-//! S: From SLAM poses (slow, precise), I: From IMU data (fast, noisy)
285285-enum prediction_type
286286-{
287287- PREDICTION_NONE = 0, //!< No prediction, always return the last SLAM tracked pose
288288- PREDICTION_SP_SO_SA_SL, //!< Predicts from last two SLAM poses only
289289- PREDICTION_SP_SO_IA_SL, //!< Predicts from last SLAM pose with angular velocity computed from IMU
290290- PREDICTION_SP_SO_IA_IL, //!< Predicts from last SLAM pose with angular and linear velocity computed from IMU
291291- PREDICTION_COUNT,
292292-};
293293-294277/*!
295278 * Main implementation of @ref xrt_tracked_slam. This is an adapter class for
296279 * SLAM tracking that wraps an external SLAM implementation.
···328311329312 // Prediction
330313331331- //!< Type of prediction to use
332332- prediction_type pred_type;
314314+ //! Type of prediction to use
315315+ t_slam_prediction_type pred_type;
333316 u_var_combo pred_combo; //!< UI combo box to select @ref pred_type
334317 RelationHistory slam_rels{}; //!< A history of relations produced purely from external SLAM tracker data
335318 struct m_ff_vec3_f32 *gyro_ff; //!< Last gyroscope samples
···645628static void
646629predict_pose(TrackerSlam &t, timepoint_ns when_ns, struct xrt_space_relation *out_relation)
647630{
648648- bool valid_pred_type = t.pred_type >= PREDICTION_NONE && t.pred_type <= PREDICTION_SP_SO_IA_IL;
631631+ bool valid_pred_type = t.pred_type >= SLAM_PRED_NONE && t.pred_type <= SLAM_PRED_SP_SO_IA_IL;
649632 SLAM_DASSERT(valid_pred_type, "Invalid prediction type (%d)", t.pred_type);
650633651634 // Get last relation computed purely from SLAM data
···660643 }
661644662645 // Use only last SLAM pose without prediction if PREDICTION_NONE
663663- if (t.pred_type == PREDICTION_NONE) {
646646+ if (t.pred_type == SLAM_PRED_NONE) {
664647 *out_relation = rel;
665648 return;
666649 }
667650668651 // Use only SLAM data if asking for an old point in time or PREDICTION_SP_SO_SA_SL
669652 SLAM_DASSERT_(rel_ts < INT64_MAX);
670670- if (t.pred_type == PREDICTION_SP_SO_SA_SL || when_ns <= (int64_t)rel_ts) {
653653+ if (t.pred_type == SLAM_PRED_SP_SO_SA_SL || when_ns <= (int64_t)rel_ts) {
671654 t.slam_rels.get(when_ns, out_relation);
672655 return;
673656 }
674657675658 // Update angular velocity with gyro data
676676- if (t.pred_type >= PREDICTION_SP_SO_IA_SL) {
659659+ if (t.pred_type >= SLAM_PRED_SP_SO_IA_SL) {
677660 xrt_vec3 avg_gyro{};
678661 m_ff_vec3_f32_filter(t.gyro_ff, rel_ts, when_ns, &avg_gyro);
679662 math_quat_rotate_derivative(&rel.pose.orientation, &avg_gyro, &rel.angular_velocity);
680663 }
681664682665 // Update linear velocity with accel data
683683- if (t.pred_type >= PREDICTION_SP_SO_IA_IL) {
666666+ if (t.pred_type >= SLAM_PRED_SP_SO_IA_IL) {
684667 xrt_vec3 avg_accel{};
685668 m_ff_vec3_f32_filter(t.accel_ff, rel_ts, when_ns, &avg_accel);
686669 xrt_vec3 world_accel{};
···754737static void
755738setup_ui(TrackerSlam &t)
756739{
757757- t.pred_combo.count = PREDICTION_COUNT;
740740+ t.pred_combo.count = SLAM_PRED_COUNT;
758741 t.pred_combo.options = "None\0Interpolate SLAM poses\0Also gyro\0Also accel (needs gravity correction)\0\0";
759742 t.pred_combo.value = (int *)&t.pred_type;
760743 m_ff_vec3_f32_alloc(&t.gyro_ff, 1000);
···977960 return ret;
978961}
979962963963+extern "C" void
964964+t_slam_fill_default_config(struct t_slam_tracker_config *config)
965965+{
966966+ config->log_level = debug_get_log_option_slam_log();
967967+ config->slam_config = debug_get_option_slam_config();
968968+ config->submit_from_start = debug_get_bool_option_slam_submit_from_start();
969969+ config->prediction = t_slam_prediction_type(debug_get_num_option_slam_prediction_type());
970970+ config->write_csvs = debug_get_bool_option_slam_write_csvs();
971971+ config->csv_path = debug_get_option_slam_csv_path();
972972+}
973973+980974extern "C" int
981981-t_slam_create(struct xrt_frame_context *xfctx, struct xrt_tracked_slam **out_xts, struct xrt_slam_sinks **out_sink)
975975+t_slam_create(struct xrt_frame_context *xfctx,
976976+ struct t_slam_tracker_config *config,
977977+ struct xrt_tracked_slam **out_xts,
978978+ struct xrt_slam_sinks **out_sink)
982979{
983983- enum u_logging_level log_level = debug_get_log_option_slam_log();
980980+ struct t_slam_tracker_config *default_config = nullptr;
981981+ if (config == nullptr) {
982982+ default_config = U_TYPED_CALLOC(struct t_slam_tracker_config);
983983+ t_slam_fill_default_config(default_config);
984984+ config = default_config;
985985+ }
986986+987987+ enum u_logging_level log_level = config->log_level;
984988985989 // Check that the external SLAM system built is compatible
986990 int ima = IMPLEMENTATION_VERSION_MAJOR;
···9971001 U_LOG_IFL_I(log_level, "Initializing compatible external SLAM system.");
99810029991003 // Check the user has provided a SLAM_CONFIG file
10001000- const char *config_file = debug_get_option_slam_config();
10041004+ const char *config_file = config->slam_config;
10011005 if (!config_file) {
10021006 U_LOG_IFL_W(log_level,
10031007 "SLAM tracker requires a config file set with the SLAM_CONFIG environment variable");
···10251029 t.sinks.imu = &t.imu_sink;
10261030 t.sinks.gt = &t.gt_sink;
1027103110281028- t.submit = debug_get_bool_option_slam_submit_from_start();
10321032+ t.submit = config->submit_from_start;
1029103310301034 t.node.break_apart = t_slam_node_break_apart;
10311035 t.node.destroy = t_slam_node_destroy;
···1037104110381042 t.euroc_recorder = euroc_recorder_create(xfctx, NULL);
1039104310401040- t.pred_type = (prediction_type)debug_get_num_option_slam_prediction_type();
10441044+ t.pred_type = config->prediction;
1041104510421046 m_filter_euro_vec3_init(&t.filter.pos_oe, t.filter.min_cutoff, t.filter.beta, t.filter.min_dcutoff);
10431047 m_filter_euro_quat_init(&t.filter.rot_oe, t.filter.min_cutoff, t.filter.beta, t.filter.min_dcutoff);
···10591063 }
1060106410611065 // Setup CSV files
10621062- bool write_csvs = debug_get_bool_option_slam_write_csvs();
10631063- t.slam_times_writer = new TimingWriter{"timing.csv", write_csvs, t.timing.columns};
10641064- t.slam_traj_writer = new TrajectoryWriter{"tracking.csv", write_csvs};
10651065- t.pred_traj_writer = new TrajectoryWriter{"prediction.csv", write_csvs};
10661066- t.filt_traj_writer = new TrajectoryWriter{"filtering.csv", write_csvs};
10661066+ bool write_csvs = config->write_csvs;
10671067+ string dir = config->csv_path;
10681068+ t.slam_times_writer = new TimingWriter{dir, "timing.csv", write_csvs, t.timing.columns};
10691069+ t.slam_traj_writer = new TrajectoryWriter{dir, "tracking.csv", write_csvs};
10701070+ t.pred_traj_writer = new TrajectoryWriter{dir, "prediction.csv", write_csvs};
10711071+ t.filt_traj_writer = new TrajectoryWriter{dir, "filtering.csv", write_csvs};
1067107210681073 setup_ui(t);
10741074+10751075+ if (default_config != nullptr) {
10761076+ free(default_config);
10771077+ }
1069107810701079 *out_xts = &t.base;
10711080 *out_sink = &t.sinks;
+40-1
src/xrt/auxiliary/tracking/t_tracking.h
···11111212#pragma once
13131414+#include "util/u_logging.h"
1415#include "xrt/xrt_frame.h"
1516#include "util/u_misc.h"
1617···382383int
383384t_hand_start(struct xrt_tracked_hand *xth);
384385386386+//! SLAM prediction type. Naming scheme as follows:
387387+//! P: position, O: orientation, A: angular velocity, L: linear velocity
388388+//! S: From SLAM poses (slow, precise), I: From IMU data (fast, noisy)
389389+enum t_slam_prediction_type
390390+{
391391+ SLAM_PRED_NONE = 0, //!< No prediction, always return the last SLAM tracked pose
392392+ SLAM_PRED_SP_SO_SA_SL, //!< Predicts from last two SLAM poses only
393393+ SLAM_PRED_SP_SO_IA_SL, //!< Predicts from last SLAM pose with angular velocity computed from IMU
394394+ SLAM_PRED_SP_SO_IA_IL, //!< Predicts from last SLAM pose with angular and linear velocity computed from IMU
395395+ SLAM_PRED_COUNT,
396396+};
397397+398398+/*!
399399+ * SLAM tracker configuration.
400400+ *
401401+ * @see xrt_tracked_slam
402402+ */
403403+struct t_slam_tracker_config
404404+{
405405+ enum u_logging_level log_level; //!< SLAM tracking logging level
406406+ const char *slam_config; //!< Config file path, format is specific to the SLAM implementation in use
407407+ bool submit_from_start; //!< Whether to submit data to the SLAM tracker without user action
408408+ enum t_slam_prediction_type prediction; //! Which level of prediction to use
409409+ bool write_csvs; //!< Whether to enable CSV writers from the start for later analysis
410410+ const char *csv_path; //!< Path to write CSVs to
411411+};
412412+413413+/*!
414414+ * Fills in a @ref t_slam_tracker_config with default values.
415415+ *
416416+ * @see xrt_tracked_Slam
417417+ */
418418+void
419419+t_slam_fill_default_config(struct t_slam_tracker_config *config);
420420+385421/*!
386422 * @public @memberof xrt_tracked_slam
387423 */
388424int
389389-t_slam_create(struct xrt_frame_context *xfctx, struct xrt_tracked_slam **out_xts, struct xrt_slam_sinks **out_sink);
425425+t_slam_create(struct xrt_frame_context *xfctx,
426426+ struct t_slam_tracker_config *config,
427427+ struct xrt_tracked_slam **out_xts,
428428+ struct xrt_slam_sinks **out_sink);
390429391430/*!
392431 * @public @memberof xrt_tracked_slam
···264264 assert(fact->xfs->source_id == 0xECD0FEED && "xfs is not Euroc, unsynced open_video_device?");
265265266266#ifdef XRT_HAVE_SLAM
267267- int ret = t_slam_create(&fact->xfctx, &fact->xts, &sinks);
267267+ int ret = t_slam_create(&fact->xfctx, NULL, &fact->xts, &sinks);
268268 if (ret != 0) {
269269 U_LOG_W("Unable to initialize SLAM tracking, the Euroc driver will not be tracked");
270270 }
···289289 assert(fact->xfs->source_id == 0x2EA15E115E && "xfs is not RealSense, unsynced open_video_device?");
290290291291#ifdef XRT_HAVE_SLAM
292292- int ret = t_slam_create(&fact->xfctx, &fact->xts, &sinks);
292292+ int ret = t_slam_create(&fact->xfctx, NULL, &fact->xts, &sinks);
293293 if (ret != 0) {
294294 U_LOG_W("Unable to initialize SLAM tracking, the RealSense driver will not be tracked");
295295 }