mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2024-12-29 11:06:18 +00:00
t/slam: Implement CSV writers for trajectories and timing info
This CSV files can be used for offline analysis.
This commit is contained in:
parent
c9f7184d64
commit
2bb0c5cda5
|
@ -25,6 +25,8 @@
|
||||||
#include <opencv2/core/mat.hpp>
|
#include <opencv2/core/mat.hpp>
|
||||||
#include <opencv2/core/version.hpp>
|
#include <opencv2/core/version.hpp>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iomanip>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#define SLAM_TRACE(...) U_LOG_IFL_T(t.log_level, __VA_ARGS__)
|
#define SLAM_TRACE(...) U_LOG_IFL_T(t.log_level, __VA_ARGS__)
|
||||||
|
@ -61,14 +63,21 @@ DEBUG_GET_ONCE_OPTION(slam_config, "SLAM_CONFIG", NULL)
|
||||||
//! Whether to submit data to the SLAM tracker without user action
|
//! Whether to submit data to the SLAM tracker without user action
|
||||||
DEBUG_GET_ONCE_BOOL_OPTION(slam_submit_from_start, "SLAM_SUBMIT_FROM_START", false)
|
DEBUG_GET_ONCE_BOOL_OPTION(slam_submit_from_start, "SLAM_SUBMIT_FROM_START", false)
|
||||||
|
|
||||||
|
//! Whether to enable CSV writers from the start for later analysis
|
||||||
|
DEBUG_GET_ONCE_BOOL_OPTION(slam_write_csvs, "SLAM_WRITE_CSVS", false)
|
||||||
|
|
||||||
//! Namespace for the interface to the external SLAM tracking system
|
//! Namespace for the interface to the external SLAM tracking system
|
||||||
namespace xrt::auxiliary::tracking::slam {
|
namespace xrt::auxiliary::tracking::slam {
|
||||||
constexpr int UI_TIMING_POSE_COUNT = 192;
|
constexpr int UI_TIMING_POSE_COUNT = 192;
|
||||||
constexpr int UI_GTDIFF_POSE_COUNT = 192;
|
constexpr int UI_GTDIFF_POSE_COUNT = 192;
|
||||||
|
|
||||||
|
using std::ifstream;
|
||||||
|
using std::make_unique;
|
||||||
using std::map;
|
using std::map;
|
||||||
|
using std::ofstream;
|
||||||
using std::shared_ptr;
|
using std::shared_ptr;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
using std::unique_ptr;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using Trajectory = map<timepoint_ns, xrt_pose>;
|
using Trajectory = map<timepoint_ns, xrt_pose>;
|
||||||
|
|
||||||
|
@ -169,6 +178,95 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! Writes poses and their timestamps to a CSV file
|
||||||
|
class TrajectoryWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool enabled; // Modified through UI
|
||||||
|
|
||||||
|
private:
|
||||||
|
string filename;
|
||||||
|
ofstream file;
|
||||||
|
bool created = false;
|
||||||
|
|
||||||
|
void
|
||||||
|
create()
|
||||||
|
{
|
||||||
|
file = ofstream{filename};
|
||||||
|
file << "#timestamp [ns], p_RS_R_x [m], p_RS_R_y [m], p_RS_R_z [m], "
|
||||||
|
"q_RS_w [], q_RS_x [], q_RS_y [], q_RS_z []" CSV_EOL;
|
||||||
|
file << std::fixed << std::setprecision(CSV_PRECISION);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
TrajectoryWriter(const string &fn, bool e) : enabled(e), filename(fn) {}
|
||||||
|
|
||||||
|
void
|
||||||
|
push(timepoint_ns ts, const xrt_pose &pose)
|
||||||
|
{
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!created) {
|
||||||
|
created = true;
|
||||||
|
create();
|
||||||
|
}
|
||||||
|
|
||||||
|
xrt_vec3 p = pose.position;
|
||||||
|
xrt_quat r = pose.orientation;
|
||||||
|
file << ts << ",";
|
||||||
|
file << p.x << "," << p.y << "," << p.z << ",";
|
||||||
|
file << r.w << "," << r.x << "," << r.y << "," << r.z << CSV_EOL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Writes timestamps measured when estimating a new pose by the SLAM system
|
||||||
|
class TimingWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool enabled; // Modified through UI
|
||||||
|
|
||||||
|
private:
|
||||||
|
string filename;
|
||||||
|
vector<string> column_names;
|
||||||
|
ofstream file;
|
||||||
|
bool created = false;
|
||||||
|
|
||||||
|
void
|
||||||
|
create()
|
||||||
|
{
|
||||||
|
file = ofstream{filename};
|
||||||
|
file << "#";
|
||||||
|
for (const string &col : column_names) {
|
||||||
|
string delimiter = &col != &column_names.back() ? "," : CSV_EOL;
|
||||||
|
file << col << delimiter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
TimingWriter(const string &fn, bool e, const vector<string> &cn) : enabled(e), filename(fn), column_names(cn) {}
|
||||||
|
|
||||||
|
void
|
||||||
|
push(const vector<timepoint_ns> ×tamps)
|
||||||
|
{
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!created) {
|
||||||
|
created = true;
|
||||||
|
create();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const timepoint_ns &ts : timestamps) {
|
||||||
|
string delimiter = &ts != ×tamps.back() ? "," : CSV_EOL;
|
||||||
|
file << ts << delimiter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//! SLAM prediction type. Naming scheme as follows:
|
//! SLAM prediction type. Naming scheme as follows:
|
||||||
//! P: position, O: orientation, A: angular velocity, L: linear velocity
|
//! P: position, O: orientation, A: angular velocity, L: linear velocity
|
||||||
//! S: From SLAM poses (slow, precise), I: From IMU data (fast, noisy)
|
//! S: From SLAM poses (slow, precise), I: From IMU data (fast, noisy)
|
||||||
|
@ -261,6 +359,12 @@ struct TrackerSlam
|
||||||
|
|
||||||
// Stats and metrics
|
// Stats and metrics
|
||||||
|
|
||||||
|
// CSV writers for offline analysis (using pointers because of container_of)
|
||||||
|
TimingWriter *slam_times_writer; //!< Timestamps of the pipeline for performance analysis
|
||||||
|
TrajectoryWriter *slam_traj_writer; //!< Estimated poses from the SLAM system
|
||||||
|
TrajectoryWriter *pred_traj_writer; //!< Predicted poses
|
||||||
|
TrajectoryWriter *filt_traj_writer; //!< Predicted and filtered poses
|
||||||
|
|
||||||
//! Tracker timing info for performance evaluation
|
//! Tracker timing info for performance evaluation
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -510,8 +614,10 @@ flush_poses(TrackerSlam &t)
|
||||||
t.slam_rels.push(rel, nts);
|
t.slam_rels.push(rel, nts);
|
||||||
|
|
||||||
gt_ui_push(t, nts, rel.pose);
|
gt_ui_push(t, nts, rel.pose);
|
||||||
|
t.slam_traj_writer->push(nts, rel.pose);
|
||||||
|
|
||||||
auto tss = timing_ui_push(t, np);
|
auto tss = timing_ui_push(t, np);
|
||||||
|
t.slam_times_writer->push(tss);
|
||||||
|
|
||||||
dequeued = t.slam->try_dequeue_pose(tracked_pose);
|
dequeued = t.slam->try_dequeue_pose(tracked_pose);
|
||||||
}
|
}
|
||||||
|
@ -670,6 +776,10 @@ setup_ui(TrackerSlam &t)
|
||||||
u_var_add_f32(&t, &t.gravity_correction.z, "Gravity Correction");
|
u_var_add_f32(&t, &t.gravity_correction.z, "Gravity Correction");
|
||||||
|
|
||||||
u_var_add_gui_header(&t, NULL, "Stats");
|
u_var_add_gui_header(&t, NULL, "Stats");
|
||||||
|
u_var_add_bool(&t, &t.slam_traj_writer->enabled, "Record tracked trajectory");
|
||||||
|
u_var_add_bool(&t, &t.pred_traj_writer->enabled, "Record predicted trajectory");
|
||||||
|
u_var_add_bool(&t, &t.filt_traj_writer->enabled, "Record filtered trajectory");
|
||||||
|
u_var_add_bool(&t, &t.slam_times_writer->enabled, "Record tracker times");
|
||||||
timing_ui_setup(t);
|
timing_ui_setup(t);
|
||||||
// Later, gt_ui_setup will setup the tracking error UI if ground truth becomes available
|
// Later, gt_ui_setup will setup the tracking error UI if ground truth becomes available
|
||||||
}
|
}
|
||||||
|
@ -696,8 +806,12 @@ t_slam_get_tracked_pose(struct xrt_tracked_slam *xts, timepoint_ns when_ns, stru
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_poses(t);
|
flush_poses(t);
|
||||||
|
|
||||||
predict_pose(t, when_ns, out_relation);
|
predict_pose(t, when_ns, out_relation);
|
||||||
|
t.pred_traj_writer->push(when_ns, out_relation->pose);
|
||||||
|
|
||||||
filter_pose(t, when_ns, out_relation);
|
filter_pose(t, when_ns, out_relation);
|
||||||
|
t.filt_traj_writer->push(when_ns, out_relation->pose);
|
||||||
|
|
||||||
t.last_rel = *out_relation;
|
t.last_rel = *out_relation;
|
||||||
t.last_ts = when_ns;
|
t.last_ts = when_ns;
|
||||||
|
@ -812,6 +926,10 @@ t_slam_node_destroy(struct xrt_frame_node *node)
|
||||||
SLAM_DEBUG("Destroying SLAM tracker");
|
SLAM_DEBUG("Destroying SLAM tracker");
|
||||||
os_thread_helper_destroy(&t_ptr->oth);
|
os_thread_helper_destroy(&t_ptr->oth);
|
||||||
delete t.gt.trajectory;
|
delete t.gt.trajectory;
|
||||||
|
delete t.slam_times_writer;
|
||||||
|
delete t.slam_traj_writer;
|
||||||
|
delete t.pred_traj_writer;
|
||||||
|
delete t.filt_traj_writer;
|
||||||
u_var_remove_root(t_ptr);
|
u_var_remove_root(t_ptr);
|
||||||
m_ff_vec3_f32_free(&t.gyro_ff);
|
m_ff_vec3_f32_free(&t.gyro_ff);
|
||||||
m_ff_vec3_f32_free(&t.accel_ff);
|
m_ff_vec3_f32_free(&t.accel_ff);
|
||||||
|
@ -922,6 +1040,13 @@ t_slam_create(struct xrt_frame_context *xfctx, struct xrt_tracked_slam **out_xts
|
||||||
t.timing.columns.insert(t.timing.columns.begin() + 1, cols.begin(), cols.end());
|
t.timing.columns.insert(t.timing.columns.begin() + 1, cols.begin(), cols.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup CSV files
|
||||||
|
bool write_csvs = debug_get_bool_option_slam_write_csvs();
|
||||||
|
t.slam_times_writer = new TimingWriter{"timing.csv", write_csvs, t.timing.columns};
|
||||||
|
t.slam_traj_writer = new TrajectoryWriter{"tracking.csv", write_csvs};
|
||||||
|
t.pred_traj_writer = new TrajectoryWriter{"prediction.csv", write_csvs};
|
||||||
|
t.filt_traj_writer = new TrajectoryWriter{"filtering.csv", write_csvs};
|
||||||
|
|
||||||
setup_ui(t);
|
setup_ui(t);
|
||||||
|
|
||||||
*out_xts = &t.base;
|
*out_xts = &t.base;
|
||||||
|
|
Loading…
Reference in a new issue