Monado OpenXR Runtime
Loading...
Searching...
No Matches
t_constellation_tracker_internal.hpp
Go to the documentation of this file.
1// Copyright 2026, Beyley Cardellio
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Internal ures for the constellation tracker.
6 * @author Beyley Cardellio <ep1cm1n10n123@gmail.com>
7 * @ingroup tracking
8 */
9
10#pragma once
11
12#include "xrt/xrt_config_build.h"
13#include "xrt/xrt_frame.h"
14#include "xrt/xrt_tracking.h"
15
16#include "util/u_debug.h"
17#include "util/u_logging.h"
18#include "util/u_var.h"
19#include "util/u_threading.h"
20#include "util/u_weak_ptr.hpp"
21#include "util/u_sink.h"
22#include "util/u_frame.h"
24
26
27#include "math/m_api.h"
28
30#include "led_search_model.h"
31#include "pose_metrics.h"
36
37#include <array>
38#include <atomic>
39#include <ceres/context.h>
40#include <fstream>
41#include <memory>
42#include <mutex>
43#include <optional>
44#include <shared_mutex>
45#include <stdexcept>
46#include <vector>
47
48
49#define CT_TRACE(ct, ...) U_LOG_IFL_T(ct->log_level, __VA_ARGS__)
50#define CT_DEBUG(ct, ...) U_LOG_IFL_D(ct->log_level, __VA_ARGS__)
51#define CT_INFO(ct, ...) U_LOG_IFL_I(ct->log_level, __VA_ARGS__)
52#define CT_WARN(ct, ...) U_LOG_IFL_W(ct->log_level, __VA_ARGS__)
53#define CT_ERROR(ct, ...) U_LOG_IFL_E(ct->log_level, __VA_ARGS__)
54
55#define MIN_ROT_ERROR DEG_TO_RAD(30)
56#define MIN_POS_ERROR 0.10
57
58/*
59 *
60 * Forward declares for C callback functions
61 *
62 */
63
64extern "C" void
65constellation_tracker_camera_push_blobs(t_blob_sink *tbs, t_blob_observation *tbo);
66
67extern "C" void
68constellation_tracker_camera_destroy(t_blob_sink *tbs);
69
70extern "C" void *
71constellation_tracker_camera_slow_thread(void *ptr);
72
73extern "C" void *
74constellation_tracker_camera_fast_thread(void *ptr);
75
76extern "C" void
77constellation_tracker_node_break_apart(xrt_frame_node *node);
78
79extern "C" void
80constellation_tracker_node_destroy(xrt_frame_node *node);
81
82
83namespace xrt::tracking::constellation {
84
85using namespace xrt::tracking::constellation::optimizer;
86
87namespace os = xrt::auxiliary::os;
88
89// Forward-declares
90struct Camera;
91struct CameraMosaic;
93struct DataRecorder;
94struct Device;
95
97{
98 xrt_pose Tcv_cam_device XRT_POSE_IDENTITY;
99 float average_blob_brightness;
100 RawPoseCovarianceMatrix covariance;
101
102 /*!
103 * Whether a found pose was already handled, this is present so that if a single sample is torn between some
104 * devices fast recovering and some devices slow recovering, we push the fast recovery poses the moment they're
105 * found rather than at the end of the slow recovery where the sample is "terminated".
106 */
107 bool handled{false};
108};
109
111{
112 //! The ID of the device.
113 t_constellation_device_id_t device_id{XRT_CONSTELLATION_INVALID_DEVICE_ID};
114
115 //! The predicted pose of the device in the world at the time of the sample.
116 std::optional<xrt_pose> Txr_world_device_prior{std::nullopt};
117 //! The predicted pose of the device relative to the camera at the time of the sample.
118 std::optional<xrt_space_relation> Tcv_cam_device_predicted{std::nullopt};
119
120 //! The final found pose of the device in this specific sample.
121 std::optional<FoundDevicePose> found_pose{std::nullopt};
122
123 //! Whether the device needs to have the slow processing thread run over it
125};
126
128{
129public: // Fields
130 t_blobwatch *source{nullptr};
131 uint64_t id{};
132 uint64_t sequence_id{};
133 int64_t timestamp_ns{};
134 t_blob blobs[XRT_CONSTELLATION_MAX_BLOBS_PER_FRAME]{};
135 uint32_t blob_count{};
136
137 //! The camera's position in the constellation tracker's tracking origin
138 std::optional<xrt_pose> Txr_world_cam{std::nullopt};
139
140 std::array<DeviceState, XRT_CONSTELLATION_MAX_DEVICES> device_states{};
141 uint32_t device_count{};
142
143 uint32_t mosaic_index;
144 uint32_t camera_index;
145
146public: // Methods
147 std::optional<DeviceState *>
148 getDeviceState(t_constellation_device_id_t device_id);
149
151 putDeviceState(t_constellation_device_id_t device_id);
152
154
155 CameraSample() = default;
156
157 void
158 markMatchingBlobs(ConstellationTracker *ct,
160 t_constellation_device_id_t device_id,
161 pose_metrics_blob_match_info &blob_match_info);
162
164 toBlobObservation() const &
165 {
166 t_blob_observation obs = {
167 .source = this->source,
168 .id = this->id,
169 .sequence_id = this->sequence_id,
170 .timestamp_ns = this->timestamp_ns,
171 .blobs = const_cast<t_blob *>(this->blobs),
172 .num_blobs = this->blob_count,
173 .frame = nullptr,
174 };
175
176 return obs;
177 }
178
180 toBlobObservation() && = delete;
182 toBlobObservation() const && = delete;
183};
184
186{
187public: // Fields
188 //! Whether to draw the blobs in the sample
189 bool draw_blobs{true};
190 //! Whether to draw the raw blob IDs
191 bool draw_blob_ids{false};
192 //! Whether to draw the device IDs on the blobs where possible
193 bool draw_blob_device_ids{true};
194 //! Whether to draw the LED IDs on the blobs where possible
195 bool draw_blob_led_ids{false};
196
197 //! Whether to draw the prior device pose in the sample, if it exists.
198 bool draw_prior{false};
199 //! Whether to draw the final device pose in the sample, if it exists.
200 bool draw_found{false};
201
202public: // Methods
203 void
204 setupDebugTracking(void *root);
205};
206
208{
209 RawPoseCovarianceMatrix covariance;
210};
211
212struct Camera
213{
214public: // Fields
215 t_blob_sink base = {
216 .push_blobs = constellation_tracker_camera_push_blobs,
217 .destroy = constellation_tracker_camera_destroy,
218 };
219
220 //! The owner tracker, so we can retrieve it from the blob sink callback
222 std::weak_ptr<CameraMosaic> mosaic;
223
224 t_camera_calibration calibration;
225
226 camera_model model;
227
228 CameraScribbleSettings scribble_settings{};
229
230 //! The index in the mosaic
231 uint32_t index;
232
233 //! Does "slow" processing for this camera when fast recovery paths fail.
234 os_thread_helper slow_processing_thread{};
235 struct
236 {
237 std::optional<CameraSample> sample{std::nullopt};
238
239 correspondence_search *cs{nullptr};
240
241 u_sink_debug debug_sink{};
242 } slow_processing_thread_data;
243
244 /*!
245 * Does "fast" processing for this camera, trying to recover a pose quickly. It's valid for this to happen at
246 * the same time as a slow process.
247 */
248 os_thread_helper fast_processing_thread{};
249 struct
250 {
251 std::optional<CameraSample> sample{std::nullopt};
252
253 correspondence_search *cs{nullptr};
254
255 u_sink_debug debug_sink{};
256 } fast_processing_thread_data;
257
258 //! Locks all processing data
259 mutable os::Mutex processing_lock;
260 //! All data protected by the processing lock
261 struct
262 {
263 xrt_pose Txr_origin_cam;
264 bool has_concrete_pose;
265 } locked_data;
266
267 std::atomic<uint32_t> shallow_searches_failed{0};
268
269public: // Methods (t_constellation_tracker.cpp)
270 static Camera *
271 Get(t_blob_sink *tbs)
272 {
273 return container_of(tbs, Camera, base);
274 }
275
277 std::weak_ptr<CameraMosaic> mosaic,
278 const t_constellation_tracker_camera &camera_params,
279 enum u_logging_level *log_level_ptr,
280 uint32_t index);
281
282 ~Camera();
283
284 // Delete all copy/move ctors, since the pointers for `base` need to be stable
285 Camera(const Camera &) = delete;
286 Camera(Camera &&) = delete;
287 Camera &
288 operator=(const Camera &) = delete;
289 Camera &
290 operator=(Camera &&) = delete;
291
292 std::optional<xrt_pose>
293 getWorldPose(timepoint_ns when_ns);
294
295 void
296 deferSampleToSlowThread(CameraSample &sample);
297
298 //! Fast matching based on prior pose
299 bool
300 tryDevicePose(Device *device,
301 CameraSample &sample,
302 DeviceState &device_state,
303 const std::optional<xrt_space_relation> &Tcv_cam_device_prior,
304 const xrt_pose &Tcv_cam_device_candidate);
305
306 bool
307 tryDeviceBlobRecovery(Device *device,
308 CameraSample &sample,
309 DeviceState &device_state,
310 const std::optional<xrt_space_relation> &Tcv_cam_device_prior);
311
312 void
313 handleProcessingComplete(CameraSample &sample);
314
315 void
316 processSampleSlow(CameraSample &sample);
317
318 //! Returns whether a slow search is needed
319 bool
320 processSampleFast(CameraSample &sample);
321
322 void
323 pushPose(CameraSample &camera_sample,
324 DeviceState &device_state,
325 Device *device,
326 pose_metrics &score,
327 const xrt_pose &Tcv_cam_device,
328 std::optional<OldOptimizationData *> was_optimized);
329
330public: // Methods (constellation_debug_scribble.cpp)
331 void
332 debugScribbleSample(CameraSample &sample, bool fast);
333};
334
336{
337public: // Fields
338 std::vector<std::unique_ptr<Camera>> cameras;
339 //! The index of this mosaic in the tracker.
340 uint32_t index;
341
343
344public: // Methods
346 const t_constellation_tracker_camera_mosaic &mosaic_params,
347 uint32_t index);
348
349 ~CameraMosaic() = default;
350
351 std::optional<xrt_pose>
352 getTrackingOriginPose(timepoint_ns when_ns);
353};
354
356{
357public: // Fields
358 xrt_pose Txr_world_device;
359 xrt_pose Tcv_cam_device;
360 timepoint_ns timestamp_ns;
361
362public: // Methods
363 DeviceLastPose(xrt_pose Txr_world_device, xrt_pose Tcv_cam_device, timepoint_ns timestamp_ns);
364};
365
367{
368 xrt_imu_sink imu_sink;
369};
370
371struct Device : public DeviceBase
372{
373public: // Fields
376
377 t_constellation_device_id_t id;
378
379 //! Devices are disabled by default, and the constellation tracker must choose to enable them.
380 std::atomic<bool> enabled{false};
381
382 //! The owner tracker, so we can retrieve it from the IMU sink callback
384
385 std::unique_ptr<sensor_fusion::SensorFusion> sensor_fusion{};
386
387 // @todo remove when clang-format is updated in CI
388 // clang-format off
389 t_constellation_search_model *search_model{nullptr};
390
391 // @todo These need to be pulled from the device and put into the sample.
392 // Right now we just hardcode them since we don't have any real sensor fusion.
393 xrt_vec3 prior_pos_error{MIN_POS_ERROR, MIN_POS_ERROR, MIN_POS_ERROR};
394 xrt_vec3 prior_rot_error{MIN_ROT_ERROR, MIN_ROT_ERROR, MIN_ROT_ERROR};
395 float gravity_error_rad{MIN_ROT_ERROR}; /* Gravity vector uncertainty in radians 0..M_PI */
396
397 mutable os::Mutex data_lock;
398 struct
399 {
400 std::optional<DeviceLastPose> last_known_pose;
401 } locked_data;
402 // clang-format on
403
404public: // Methods
408 t_constellation_device_id_t id);
409
410 ~Device();
411
412 // Delete move constructors
413 Device(const Device &) = delete;
414 Device(Device &&) = delete;
415 Device &
416 operator=(const Device &) = delete;
417 Device &
418 operator=(Device &&) = delete;
419
420 static Device *
421 fromXrtImuSink(xrt_imu_sink *sink)
422 {
423 // Go through DeviceBase* to Device* so that `Device` doesn't have to be a standard layout type and we
424 // can still use `container_of` safely.
425 return static_cast<Device *>(container_of(sink, DeviceBase, imu_sink));
426 }
427
428 void
429 pushImuSample(const xrt_imu_sample &sample);
430};
431
432// Separate base struct with our interface implementations so that `ConstellationTrackerBase` remains a standard layout
433// type and we can safely use `container_of` on it.
435{
436 xrt_frame_node node = {
437 .next = nullptr,
438 .break_apart = constellation_tracker_node_break_apart,
439 .destroy = constellation_tracker_node_destroy,
440 };
441 xrt_tracking_origin tracking_origin = {
442 .name = "Constellation Tracker",
444 .initial_offset =
445 {
446 .orientation = XRT_QUAT_IDENTITY,
447 .position = {.x = 0, .y = 1.2, .z = 0},
448 },
449 };
450};
451
453{
454public: // Fields
455 //! Whether the constellation tracker is running
456 bool running = true;
457
458 enum u_logging_level log_level;
459
461
462 bool single_threaded{false};
463 bool deterministic{false};
464
465 std::vector<std::shared_ptr<CameraMosaic>> mosaics;
466
467 // Put here to be destroyed before devices (reverse declaration order)
468 std::unique_ptr<ceres::Context> ceres_context{};
469
470 std::shared_mutex device_lock;
471 std::vector<std::unique_ptr<Device>> devices;
472 t_constellation_device_id_t next_device_id{0};
473
474 std::unique_ptr<DataRecorder> data_recorder{};
475
476 mutable os::Mutex rig_calibration_lock{};
477 os_thread_helper rig_calibration_thread{};
478 bool running_calibration{false};
479 std::unique_ptr<rig_calibration::RigCalibration> rig_calibration{};
480
481#ifdef XRT_FEATURE_RERUN
482 std::unique_ptr<struct RerunContext> rerun_stream{};
483#endif
484
485public: // Methods
486 static ConstellationTracker *
487 Get(xrt_frame_node *node)
488 {
489 return static_cast<ConstellationTracker *>(container_of(node, ConstellationTrackerBase, node));
490 }
491
492 static ConstellationTracker *
493 Get(t_constellation_tracker *tracker)
494 {
495 return reinterpret_cast<ConstellationTracker *>(tracker);
496 }
497
499
501
502 // Delete all copy/move ctors, since the pointers for `node` need to be stable
506 operator=(const ConstellationTracker &) = delete;
508 operator=(ConstellationTracker &&) = delete;
509
510 bool
511 needSensorCalibration();
512
513 bool
514 checkSensorCalibration();
515
516 void
517 setupVariableTracking();
518
519 t_constellation_device_id_t
521
522 void
523 removeDevice(t_constellation_device_id_t device_id);
524
525 void
526 getTrackedPose(t_constellation_device_id_t device_id, timepoint_ns when_ns, xrt_space_relation &out_relation);
527};
528
529}; // namespace xrt::tracking::constellation
Definition device.hpp:73
Ab-initio blob<->LED correspondence search.
u_logging_level
Logging level enum.
Definition u_logging.h:45
int64_t timepoint_ns
Integer timestamp type.
Definition u_time.h:77
#define container_of(ptr, type, field)
Get the holder from a pointer to a field.
Definition xrt_compiler.h:298
@ XRT_TRACKING_TYPE_CONSTELLATION
The device(s) are tracked through a constellation of lights as seen by cameras.
Definition xrt_tracking.h:72
LED search model management code.
C interface to math library.
Metrics for constellation tracking poses.
RANSAC PnP pose refinement.
Constellation tracker rig calibration.
Constellation tracker sensor fusion.
Definition t_rift_blobwatch.c:85
Definition camera_model.h:21
Definition correspondence_search.h:95
Definition u_pacing_compositor.c:58
All in one helper that handles locking, waiting for change and starting a thread.
Definition os_threading.h:500
Definition pose_metrics.h:105
Definition pose_metrics.h:79
Definition t_constellation.h:102
A generic interface to allow a tracking system to receive "snapshots" of seen t_blob in a frame.
Definition t_constellation.h:134
void(* push_blobs)(struct t_blob_sink *tbs, struct t_blob_observation *observation)
Push a set of blobs into the sink.
Definition t_constellation.h:142
A blob is a 2d position in a camera sensor's view that is being tracked.
Definition t_constellation.h:51
Definition t_constellation.h:185
Essential calibration data for a single camera, or single lens/sensor of a stereo camera.
Definition t_tracking.h:269
Definition led_search_model.h:40
A constellation tracker camera mosaic is a set of cameras that may or may not be physically attached,...
Definition t_constellation_tracker.h:60
A constellation tracker camera is a single camera that the constellation tracker will use to track de...
Definition t_constellation_tracker.h:34
Parameters for adding a device to the constellation tracker.
Definition t_constellation_tracker.h:79
A constellation tracker device is a device that the constellation tracker will attempt to track in 6d...
Definition t_constellation.h:396
The LED model is a series of points which define the real-world positions of all LEDs.
Definition t_constellation.h:311
Definition t_constellation_tracker.h:104
A constellation tracker tracking source is an arbitrary source of tracking data for the constellation...
Definition t_constellation.h:254
Allows more safely to debug sink inputs and outputs.
Definition u_sink.h:214
Definition t_constellation_tracker_internal.hpp:213
os::Mutex processing_lock
Locks all processing data.
Definition t_constellation_tracker_internal.hpp:259
uint32_t index
The index in the mosaic.
Definition t_constellation_tracker_internal.hpp:231
ConstellationTracker * tracker
The owner tracker, so we can retrieve it from the blob sink callback.
Definition t_constellation_tracker_internal.hpp:221
Definition t_constellation_tracker_internal.hpp:336
uint32_t index
The index of this mosaic in the tracker.
Definition t_constellation_tracker_internal.hpp:340
Definition t_constellation_tracker_internal.hpp:128
std::optional< xrt_pose > Txr_world_cam
The camera's position in the constellation tracker's tracking origin.
Definition t_constellation_tracker_internal.hpp:138
Definition t_constellation_tracker_internal.hpp:186
Definition t_constellation_tracker_internal.hpp:435
Definition t_constellation_tracker_internal.hpp:453
Definition t_constellation_tracker_dataset.hpp:124
Definition t_constellation_tracker_internal.hpp:367
Definition t_constellation_tracker_internal.hpp:372
ConstellationTracker * tracker
The owner tracker, so we can retrieve it from the IMU sink callback.
Definition t_constellation_tracker_internal.hpp:383
Definition t_constellation_tracker_internal.hpp:356
Definition t_constellation_tracker_internal.hpp:111
std::optional< xrt_space_relation > Tcv_cam_device_predicted
The predicted pose of the device relative to the camera at the time of the sample.
Definition t_constellation_tracker_internal.hpp:118
t_constellation_device_id_t device_id
The ID of the device.
Definition t_constellation_tracker_internal.hpp:113
std::optional< xrt_pose > Txr_world_device_prior
The predicted pose of the device in the world at the time of the sample.
Definition t_constellation_tracker_internal.hpp:116
std::optional< FoundDevicePose > found_pose
The final found pose of the device in this specific sample.
Definition t_constellation_tracker_internal.hpp:121
bool needs_slow_processing
Whether the device needs to have the slow processing thread run over it.
Definition t_constellation_tracker_internal.hpp:124
Definition t_constellation_tracker_internal.hpp:97
bool handled
Whether a found pose was already handled, this is present so that if a single sample is torn between ...
Definition t_constellation_tracker_internal.hpp:107
Definition t_constellation_tracker_internal.hpp:208
A interface object used for destroying a frame graph.
Definition xrt_frame.h:87
void(* break_apart)(struct xrt_frame_node *node)
Called first in when the graph is being destroyed, remove any references frames and other objects and...
Definition xrt_frame.h:94
IMU Sample.
Definition xrt_tracking.h:143
An object to send IMU samples to.
Definition xrt_tracking.h:184
A pose composed of a position and orientation.
Definition xrt_defines.h:522
A relation with two spaces, includes velocity and acceleration.
Definition xrt_defines.h:713
A tracking system or device origin.
Definition xrt_tracking.h:87
char name[256]
For debugging.
Definition xrt_tracking.h:89
A 3 element vector with single floats.
Definition xrt_defines.h:310
Header defining the tracking system integration in Monado.
Header defining the constellation tracker parameters and functions.
Small debug helpers.
xrt_frame helpers.
xrt_frame helpers for scribbling onto frames.
Basic logging functionality.
xrt_frame_sink converters and other helpers.
Slightly higher level thread safe helpers.
Variable tracking code.
C++ helpers for weak pointers.
Data frame header.
Header defining the tracking system integration in Monado.