mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-06 07:06:10 +00:00
t/euroc: Fix crash when recording euroc dataset by providing UI button
Previously, a crash occurred in some situations when the second sample was written before the first sample was able to create the necessary CSV files.
This commit is contained in:
parent
c80cf206c8
commit
2cf07dedf2
|
@ -12,6 +12,7 @@
|
||||||
#include "os/os_time.h"
|
#include "os/os_time.h"
|
||||||
#include "util/u_frame.h"
|
#include "util/u_frame.h"
|
||||||
#include "util/u_sink.h"
|
#include "util/u_sink.h"
|
||||||
|
#include "util/u_var.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
@ -34,7 +35,10 @@ struct euroc_recorder
|
||||||
{
|
{
|
||||||
struct xrt_frame_node node;
|
struct xrt_frame_node node;
|
||||||
string path; //!< Destination path for the dataset
|
string path; //!< Destination path for the dataset
|
||||||
bool first_received; //!< Whether we have received the first sample
|
|
||||||
|
bool recording; //!< Whether samples are being recorded
|
||||||
|
bool files_created; //!< Whether the dataset directory structure has been created
|
||||||
|
struct u_var_button recording_btn; //!< UI button to start/stop `recording`
|
||||||
|
|
||||||
// Cloner sinks: copy frame to heap for quick release of the original
|
// Cloner sinks: copy frame to heap for quick release of the original
|
||||||
struct xrt_slam_sinks cloner_queues; //!< Queue sinks that write into cloner sinks
|
struct xrt_slam_sinks cloner_queues; //!< Queue sinks that write into cloner sinks
|
||||||
|
@ -67,11 +71,11 @@ struct euroc_recorder
|
||||||
static void
|
static void
|
||||||
euroc_recorder_try_mkfiles(struct euroc_recorder *er)
|
euroc_recorder_try_mkfiles(struct euroc_recorder *er)
|
||||||
{
|
{
|
||||||
// Create directory structure and files only on first received frame
|
// Create directory structure and files only once
|
||||||
if (er->first_received) {
|
if (er->files_created) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
er->first_received = true;
|
er->files_created = true;
|
||||||
|
|
||||||
string path = er->path;
|
string path = er->path;
|
||||||
|
|
||||||
|
@ -110,7 +114,6 @@ extern "C" void
|
||||||
euroc_recorder_save_imu(xrt_imu_sink *sink, struct xrt_imu_sample *sample)
|
euroc_recorder_save_imu(xrt_imu_sink *sink, struct xrt_imu_sample *sample)
|
||||||
{
|
{
|
||||||
euroc_recorder *er = container_of(sink, euroc_recorder, writer_imu_sink);
|
euroc_recorder *er = container_of(sink, euroc_recorder, writer_imu_sink);
|
||||||
euroc_recorder_try_mkfiles(er);
|
|
||||||
|
|
||||||
timepoint_ns ts = sample->timestamp_ns;
|
timepoint_ns ts = sample->timestamp_ns;
|
||||||
xrt_vec3_f64 a = sample->accel_m_s2;
|
xrt_vec3_f64 a = sample->accel_m_s2;
|
||||||
|
@ -124,8 +127,6 @@ euroc_recorder_save_imu(xrt_imu_sink *sink, struct xrt_imu_sample *sample)
|
||||||
static void
|
static void
|
||||||
euroc_recorder_save_frame(euroc_recorder *er, struct xrt_frame *frame, bool is_left)
|
euroc_recorder_save_frame(euroc_recorder *er, struct xrt_frame *frame, bool is_left)
|
||||||
{
|
{
|
||||||
euroc_recorder_try_mkfiles(er);
|
|
||||||
|
|
||||||
string cam_name = is_left ? "cam0" : "cam1";
|
string cam_name = is_left ? "cam0" : "cam1";
|
||||||
uint64_t ts = frame->timestamp;
|
uint64_t ts = frame->timestamp;
|
||||||
|
|
||||||
|
@ -169,6 +170,11 @@ euroc_recorder_receive_imu(xrt_imu_sink *sink, struct xrt_imu_sample *sample)
|
||||||
// sinks so we use an std::queue to temporarily store IMU samples, later we
|
// sinks so we use an std::queue to temporarily store IMU samples, later we
|
||||||
// write them to disk when writing left frames.
|
// write them to disk when writing left frames.
|
||||||
euroc_recorder *er = container_of(sink, euroc_recorder, cloner_imu_sink);
|
euroc_recorder *er = container_of(sink, euroc_recorder, cloner_imu_sink);
|
||||||
|
|
||||||
|
if (!er->recording) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
er->imu_queue.push(*sample);
|
er->imu_queue.push(*sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +182,10 @@ euroc_recorder_receive_imu(xrt_imu_sink *sink, struct xrt_imu_sample *sample)
|
||||||
static void
|
static void
|
||||||
euroc_recorder_receive_frame(euroc_recorder *er, struct xrt_frame *src_frame, bool is_left)
|
euroc_recorder_receive_frame(euroc_recorder *er, struct xrt_frame *src_frame, bool is_left)
|
||||||
{
|
{
|
||||||
|
if (!er->recording) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Let's clone the frame so that we can release the src_frame quickly
|
// Let's clone the frame so that we can release the src_frame quickly
|
||||||
xrt_frame *copy = nullptr;
|
xrt_frame *copy = nullptr;
|
||||||
u_frame_clone(src_frame, ©);
|
u_frame_clone(src_frame, ©);
|
||||||
|
@ -228,10 +238,15 @@ euroc_recorder_node_destroy(struct xrt_frame_node *node)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern "C" xrt_slam_sinks *
|
extern "C" xrt_slam_sinks *
|
||||||
euroc_recorder_create(struct xrt_frame_context *xfctx, const char *record_path)
|
euroc_recorder_create(struct xrt_frame_context *xfctx, const char *record_path, bool record_from_start)
|
||||||
{
|
{
|
||||||
struct euroc_recorder *er = new euroc_recorder{};
|
struct euroc_recorder *er = new euroc_recorder{};
|
||||||
|
|
||||||
|
er->recording = record_from_start;
|
||||||
|
if (record_from_start) {
|
||||||
|
euroc_recorder_try_mkfiles(er);
|
||||||
|
}
|
||||||
|
|
||||||
struct xrt_frame_node *xfn = &er->node;
|
struct xrt_frame_node *xfn = &er->node;
|
||||||
xfn->break_apart = euroc_recorder_node_break_apart;
|
xfn->break_apart = euroc_recorder_node_break_apart;
|
||||||
xfn->destroy = euroc_recorder_node_destroy;
|
xfn->destroy = euroc_recorder_node_destroy;
|
||||||
|
@ -276,3 +291,22 @@ euroc_recorder_create(struct xrt_frame_context *xfctx, const char *record_path)
|
||||||
xrt_slam_sinks *public_sinks = &er->cloner_queues;
|
xrt_slam_sinks *public_sinks = &er->cloner_queues;
|
||||||
return public_sinks;
|
return public_sinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
euroc_recorder_btn_cb(void *ptr)
|
||||||
|
{
|
||||||
|
euroc_recorder *er = (euroc_recorder *)ptr;
|
||||||
|
euroc_recorder_try_mkfiles(er);
|
||||||
|
er->recording = !er->recording;
|
||||||
|
snprintf(er->recording_btn.label, sizeof(er->recording_btn.label),
|
||||||
|
er->recording ? "Stop recording" : "Record EuRoC dataset");
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
euroc_recorder_add_ui(struct xrt_slam_sinks *public_sinks, void *root)
|
||||||
|
{
|
||||||
|
euroc_recorder *er = container_of(public_sinks, euroc_recorder, cloner_queues);
|
||||||
|
er->recording_btn.cb = euroc_recorder_btn_cb;
|
||||||
|
er->recording_btn.ptr = er;
|
||||||
|
u_var_add_button(root, &er->recording_btn, er->recording ? "Stop recording" : "Record EuRoC dataset");
|
||||||
|
}
|
||||||
|
|
|
@ -24,12 +24,22 @@ extern "C" {
|
||||||
*
|
*
|
||||||
* @param xfctx Frame context for the sinks.
|
* @param xfctx Frame context for the sinks.
|
||||||
* @param record_path Directory name to save the dataset or NULL for a default based on the current datetime.
|
* @param record_path Directory name to save the dataset or NULL for a default based on the current datetime.
|
||||||
|
* @param record_from_start Whether to start recording immediately on creation.
|
||||||
* @return struct xrt_slam_sinks* Sinks to push samples to for recording.
|
* @return struct xrt_slam_sinks* Sinks to push samples to for recording.
|
||||||
*
|
*
|
||||||
* @ingroup aux_tracking
|
* @ingroup aux_tracking
|
||||||
*/
|
*/
|
||||||
struct xrt_slam_sinks *
|
struct xrt_slam_sinks *
|
||||||
euroc_recorder_create(struct xrt_frame_context *xfctx, const char *record_path);
|
euroc_recorder_create(struct xrt_frame_context *xfctx, const char *record_path, bool record_from_start);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Add EuRoC recorder UI button to start recording after creation.
|
||||||
|
*
|
||||||
|
* @param er The sinks returned by @ref euroc_recorder_create
|
||||||
|
* @param root The pointer to add UI button to
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
euroc_recorder_add_ui(struct xrt_slam_sinks *er, void *root);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,7 +302,6 @@ struct TrackerSlam
|
||||||
MatFrame *cv_wrapper; //!< Wraps a xrt_frame in a cv::Mat to send to the SLAM system
|
MatFrame *cv_wrapper; //!< Wraps a xrt_frame in a cv::Mat to send to the SLAM system
|
||||||
|
|
||||||
struct xrt_slam_sinks *euroc_recorder; //!< EuRoC dataset recording sinks
|
struct xrt_slam_sinks *euroc_recorder; //!< EuRoC dataset recording sinks
|
||||||
bool euroc_record; //!< When true, samples will be saved to disk in EuRoC format
|
|
||||||
|
|
||||||
// Used mainly for checking that the timestamps come in order
|
// Used mainly for checking that the timestamps come in order
|
||||||
timepoint_ns last_imu_ts = INT64_MIN; //!< Last received IMU sample timestamp
|
timepoint_ns last_imu_ts = INT64_MIN; //!< Last received IMU sample timestamp
|
||||||
|
@ -748,8 +747,8 @@ setup_ui(TrackerSlam &t)
|
||||||
u_var_add_root(&t, "SLAM Tracker", true);
|
u_var_add_root(&t, "SLAM Tracker", true);
|
||||||
u_var_add_log_level(&t, &t.log_level, "Log Level");
|
u_var_add_log_level(&t, &t.log_level, "Log Level");
|
||||||
u_var_add_bool(&t, &t.submit, "Submit data to SLAM");
|
u_var_add_bool(&t, &t.submit, "Submit data to SLAM");
|
||||||
u_var_add_bool(&t, &t.euroc_record, "Record as EuRoC");
|
|
||||||
u_var_add_bool(&t, &t.gt.override_tracking, "Track with ground truth (if available)");
|
u_var_add_bool(&t, &t.gt.override_tracking, "Track with ground truth (if available)");
|
||||||
|
euroc_recorder_add_ui(t.euroc_recorder, &t);
|
||||||
|
|
||||||
u_var_add_gui_header(&t, NULL, "Trajectory Filter");
|
u_var_add_gui_header(&t, NULL, "Trajectory Filter");
|
||||||
u_var_add_bool(&t, &t.filter.use_moving_average_filter, "Enable moving average filter");
|
u_var_add_bool(&t, &t.filter.use_moving_average_filter, "Enable moving average filter");
|
||||||
|
@ -850,9 +849,7 @@ t_slam_imu_sink_push(struct xrt_imu_sink *sink, struct xrt_imu_sample *s)
|
||||||
}
|
}
|
||||||
SLAM_TRACE("imu t=%ld a=[%f,%f,%f] w=[%f,%f,%f]", ts, a.x, a.y, a.z, w.x, w.y, w.z);
|
SLAM_TRACE("imu t=%ld a=[%f,%f,%f] w=[%f,%f,%f]", ts, a.x, a.y, a.z, w.x, w.y, w.z);
|
||||||
|
|
||||||
if (t.euroc_record) {
|
|
||||||
xrt_sink_push_imu(t.euroc_recorder->imu, s);
|
xrt_sink_push_imu(t.euroc_recorder->imu, s);
|
||||||
}
|
|
||||||
|
|
||||||
struct xrt_vec3 gyro = {(float)w.x, (float)w.y, (float)w.z};
|
struct xrt_vec3 gyro = {(float)w.x, (float)w.y, (float)w.z};
|
||||||
struct xrt_vec3 accel = {(float)a.x, (float)a.y, (float)a.z};
|
struct xrt_vec3 accel = {(float)a.x, (float)a.y, (float)a.z};
|
||||||
|
@ -890,22 +887,16 @@ t_slam_frame_sink_push_left(struct xrt_frame_sink *sink, struct xrt_frame *frame
|
||||||
{
|
{
|
||||||
auto &t = *container_of(sink, TrackerSlam, left_sink);
|
auto &t = *container_of(sink, TrackerSlam, left_sink);
|
||||||
push_frame(t, frame, true);
|
push_frame(t, frame, true);
|
||||||
|
|
||||||
if (t.euroc_record) {
|
|
||||||
xrt_sink_push_frame(t.euroc_recorder->left, frame);
|
xrt_sink_push_frame(t.euroc_recorder->left, frame);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
t_slam_frame_sink_push_right(struct xrt_frame_sink *sink, struct xrt_frame *frame)
|
t_slam_frame_sink_push_right(struct xrt_frame_sink *sink, struct xrt_frame *frame)
|
||||||
{
|
{
|
||||||
auto &t = *container_of(sink, TrackerSlam, right_sink);
|
auto &t = *container_of(sink, TrackerSlam, right_sink);
|
||||||
push_frame(t, frame, false);
|
push_frame(t, frame, false);
|
||||||
|
|
||||||
if (t.euroc_record) {
|
|
||||||
xrt_sink_push_frame(t.euroc_recorder->right, frame);
|
xrt_sink_push_frame(t.euroc_recorder->right, frame);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
t_slam_node_break_apart(struct xrt_frame_node *node)
|
t_slam_node_break_apart(struct xrt_frame_node *node)
|
||||||
|
@ -1039,7 +1030,7 @@ t_slam_create(struct xrt_frame_context *xfctx,
|
||||||
|
|
||||||
xrt_frame_context_add(xfctx, &t.node);
|
xrt_frame_context_add(xfctx, &t.node);
|
||||||
|
|
||||||
t.euroc_recorder = euroc_recorder_create(xfctx, NULL);
|
t.euroc_recorder = euroc_recorder_create(xfctx, NULL, false);
|
||||||
|
|
||||||
t.pred_type = config->prediction;
|
t.pred_type = config->prediction;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue