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
29#include <vector>
30#include <memory>
31#include <mutex>
32#include <shared_mutex>
33#include <optional>
34#include <stdexcept>
35#include <array>
36#include <fstream>
37
39#include "led_search_model.h"
40#include "pose_metrics.h"
43
44
45#define CT_TRACE(ct, ...) U_LOG_IFL_T(ct->log_level, __VA_ARGS__)
46#define CT_DEBUG(ct, ...) U_LOG_IFL_D(ct->log_level, __VA_ARGS__)
47#define CT_INFO(ct, ...) U_LOG_IFL_I(ct->log_level, __VA_ARGS__)
48#define CT_WARN(ct, ...) U_LOG_IFL_W(ct->log_level, __VA_ARGS__)
49#define CT_ERROR(ct, ...) U_LOG_IFL_E(ct->log_level, __VA_ARGS__)
50
51#define MIN_ROT_ERROR DEG_TO_RAD(30)
52#define MIN_POS_ERROR 0.10
53
54/*
55 *
56 * Forward declares for C callback functions
57 *
58 */
59
60extern "C" void
61constellation_tracker_camera_push_blobs(t_blob_sink *tbs, t_blob_observation *tbo);
62
63extern "C" void
64constellation_tracker_camera_destroy(t_blob_sink *tbs);
65
66extern "C" void *
67constellation_tracker_camera_slow_thread(void *ptr);
68
69extern "C" void *
70constellation_tracker_camera_fast_thread(void *ptr);
71
72extern "C" void
73constellation_tracker_node_break_apart(xrt_frame_node *node);
74
75extern "C" void
76constellation_tracker_node_destroy(xrt_frame_node *node);
77
78
79namespace xrt::tracking::constellation {
80
81using namespace xrt::tracking::constellation::optimizer;
82
83namespace os = xrt::auxiliary::os;
84
85// Forward-declares
86struct Camera;
87struct CameraMosaic;
89struct DataRecorder;
90struct Device;
91
93{
94 xrt_pose Tcv_cam_device XRT_POSE_IDENTITY;
95 float average_blob_brightness;
96 RawPoseCovarianceMatrix covariance;
97 RawPoseCovarianceMatrix whitening;
98};
99
101{
102 //! The ID of the device.
103 t_constellation_device_id_t device_id{XRT_CONSTELLATION_INVALID_DEVICE_ID};
104
105 //! The "predicted" pose, which is the pose the device expects itself to be at at the time of the blobservation.
106 std::optional<xrt_pose> Txr_world_device_prior{std::nullopt};
107
108 //! The final found pose of the device in this specific sample.
109 std::optional<FoundDevicePose> found_pose{std::nullopt};
110
111 //! Whether the device needs to have the slow processing thread run over it
113};
114
116{
117public: // Fields
118 t_blobwatch *source{nullptr};
119 uint64_t id{};
120 int64_t timestamp_ns{};
121 t_blob blobs[XRT_CONSTELLATION_MAX_BLOBS_PER_FRAME]{};
122 uint32_t blob_count{};
123
124 //! The camera's position in the constellation tracker's tracking origin
125 std::optional<xrt_pose> Txr_world_cam{std::nullopt};
126
127 std::array<DeviceState, XRT_CONSTELLATION_MAX_DEVICES> device_states{};
128 uint32_t device_count{};
129
130 uint32_t mosaic_index;
131 uint32_t camera_index;
132
133public: // Methods
134 std::optional<DeviceState *>
135 getDeviceState(t_constellation_device_id_t device_id);
136
138 putDeviceState(t_constellation_device_id_t device_id);
139
141
142 CameraSample() = default;
143
144 void
145 markMatchingBlobs(ConstellationTracker *ct,
147 t_constellation_device_id_t device_id,
148 pose_metrics_blob_match_info &blob_match_info);
149
151 toBlobObservation() const &
152 {
153 t_blob_observation obs = {
154 .source = this->source,
155 .id = this->id,
156 .timestamp_ns = this->timestamp_ns,
157 .blobs = const_cast<t_blob *>(this->blobs),
158 .num_blobs = this->blob_count,
159 };
160
161 return obs;
162 }
163
165 toBlobObservation() && = delete;
167 toBlobObservation() const && = delete;
168};
169
171{
172public: // Fields
173 //! Whether to draw the blobs in the sample
174 bool draw_blobs{true};
175 //! Whether to draw the raw blob IDs
176 bool draw_blob_ids{false};
177 //! Whether to draw the device IDs on the blobs where possible
178 bool draw_blob_device_ids{true};
179 //! Whether to draw the LED IDs on the blobs where possible
180 bool draw_blob_led_ids{false};
181
182 //! Whether to draw the prior device pose in the sample, if it exists.
183 bool draw_prior{false};
184 //! Whether to draw the final device pose in the sample, if it exists.
185 bool draw_found{false};
186
187public: // Methods
188 void
189 setupDebugTracking(void *root);
190};
191
193{
194 RawPoseCovarianceMatrix covariance;
195 RawPoseCovarianceMatrix whitening;
196};
197
198struct Camera
199{
200public: // Fields
201 t_blob_sink base = {
202 .push_blobs = constellation_tracker_camera_push_blobs,
203 .destroy = constellation_tracker_camera_destroy,
204 };
205
206 //! The owner tracker, so we can retrieve it from the blob sink callback
208 std::weak_ptr<CameraMosaic> mosaic;
209
210 t_camera_calibration calibration;
211
212 camera_model model;
213
214 CameraScribbleSettings scribble_settings{};
215
216 //! The index in the mosaic
217 size_t index;
218
219 //! Does "slow" processing for this camera when fast recovery paths fail.
220 os_thread_helper slow_processing_thread{};
221 struct
222 {
223 std::optional<CameraSample> sample{std::nullopt};
224
225 correspondence_search *cs{nullptr};
226
227 u_sink_debug debug_sink{};
228 } slow_processing_thread_data;
229
230 /*!
231 * Does "fast" processing for this camera, trying to recover a pose quickly. It's valid for this to happen at
232 * the same time as a slow process.
233 */
234 os_thread_helper fast_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 } fast_processing_thread_data;
243
244 //! Locks all processing data
245 mutable os::Mutex processing_lock;
246 //! All data protected by the processing lock
247 struct
248 {
249 xrt_pose Txr_origin_cam;
250 bool has_concrete_pose;
251 } locked_data;
252
253public: // Methods (t_constellation_tracker.cpp)
254 static Camera *
255 Get(t_blob_sink *tbs)
256 {
257 return container_of(tbs, Camera, base);
258 }
259
261 std::weak_ptr<CameraMosaic> mosaic,
262 const t_constellation_tracker_camera &camera_params,
263 enum u_logging_level *log_level_ptr,
264 size_t index);
265
266 ~Camera();
267
268 // Delete all copy/move ctors, since the pointers for `base` need to be stable
269 Camera(const Camera &) = delete;
270 Camera(Camera &&) = delete;
271 Camera &
272 operator=(const Camera &) = delete;
273 Camera &
274 operator=(Camera &&) = delete;
275
276 std::optional<xrt_pose>
277 getWorldPose(timepoint_ns when_ns);
278
279 void
280 deferSampleToSlowThread(CameraSample &sample);
281
282 //! Fast matching based on prior pose
283 bool
284 tryDevicePose(std::unique_ptr<Device> &device,
285 CameraSample &sample,
286 DeviceState &device_state,
287 const std::optional<xrt_pose> &Tcv_cam_device_prior,
288 const xrt_pose &Tcv_cam_device_candidate);
289
290 bool
291 tryDeviceBlobRecovery(std::unique_ptr<Device> &device,
292 CameraSample &sample,
293 DeviceState &device_state,
294 const std::optional<xrt_pose> &Tcv_cam_device_prior);
295
296 void
297 processSampleSlow(CameraSample &sample);
298
299 //! Returns whether a slow search is needed
300 bool
301 processSampleFast(CameraSample &sample);
302
303 void
304 pushPose(CameraSample &camera_sample,
305 DeviceState &device_state,
306 std::unique_ptr<Device> &device,
307 pose_metrics &score,
308 const xrt_pose &Tcv_cam_device,
309 std::optional<OldOptimizationData *> was_optimized);
310
311public: // Methods (constellation_debug_scribble.cpp)
312 void
313 debugScribbleSample(CameraSample &sample, bool fast);
314};
315
317{
318public: // Fields
319 std::vector<std::unique_ptr<Camera>> cameras;
320 //! The index of this mosaic in the tracker.
321 size_t index;
322
324
325public: // Methods
327 const t_constellation_tracker_camera_mosaic &mosaic_params,
328 size_t index);
329
330 ~CameraMosaic() = default;
331
332 std::optional<xrt_pose>
333 getTrackingOriginPose(timepoint_ns when_ns);
334};
335
337{
338public: // Fields
339 std::optional<xrt_pose> Txr_world_device;
340 xrt_pose Tcv_cam_device;
341 timepoint_ns timestamp_ns;
342
343public: // Methods
344 DeviceLastPose(std::optional<xrt_pose> Txr_world_device, xrt_pose Tcv_cam_device, timepoint_ns timestamp_ns);
345};
346
348{
349 xrt_imu_sink imu_sink;
350};
351
352struct Device : public DeviceBase
353{
354public: // Fields
357
358 t_constellation_device_id_t id;
359
360 //! The owner tracker, so we can retrieve it from the IMU sink callback
362
363 // @todo remove when clang-format is updated in CI
364 // clang-format off
365 t_constellation_search_model *search_model{nullptr};
366
367 // @todo These need to be pulled from the device and put into the sample.
368 // Right now we just hardcode them since we don't have any real sensor fusion.
369 xrt_vec3 prior_pos_error{MIN_POS_ERROR, MIN_POS_ERROR, MIN_POS_ERROR};
370 xrt_vec3 prior_rot_error{MIN_ROT_ERROR, MIN_ROT_ERROR, MIN_ROT_ERROR};
371 float gravity_error_rad{MIN_ROT_ERROR}; /* Gravity vector uncertainty in radians 0..M_PI */
372
373 mutable os::Mutex data_lock;
374 struct
375 {
376 std::optional<DeviceLastPose> last_known_pose;
377 } locked_data;
378 // clang-format on
379
380public: // Methods
384 t_constellation_device_id_t id);
385
386 ~Device();
387
388 // Delete move constructors
389 Device(const Device &) = delete;
390 Device(Device &&) = delete;
391 Device &
392 operator=(const Device &) = delete;
393 Device &
394 operator=(Device &&) = delete;
395
396 static Device *
397 fromXrtImuSink(xrt_imu_sink *sink)
398 {
399 // Go through DeviceBase* to Device* so that `Device` doesn't have to be a standard layout type and we
400 // can still use `container_of` safely.
401 return static_cast<Device *>(container_of(sink, DeviceBase, imu_sink));
402 }
403
404 void
405 pushImuSample(const xrt_imu_sample &sample);
406};
407
408// Separate base struct with our interface implementations so that `ConstellationTrackerBase` remains a standard layout
409// type and we can safely use `container_of` on it.
411{
412 xrt_frame_node node = {
413 .next = nullptr,
414 .break_apart = constellation_tracker_node_break_apart,
415 .destroy = constellation_tracker_node_destroy,
416 };
417 xrt_tracking_origin tracking_origin = {
418 .name = "Constellation Tracker",
420 .initial_offset = XRT_POSE_IDENTITY,
421 };
422};
423
425{
426public: // Fields
427 //! Whether the constellation tracker is running
428 bool running = true;
429
430 enum u_logging_level log_level = U_LOGGING_WARN;
431
433
434 bool single_threaded{false};
435 bool deterministic{false};
436
437 std::vector<std::shared_ptr<CameraMosaic>> mosaics;
438
439 std::shared_mutex device_lock;
440 std::vector<std::unique_ptr<Device>> devices;
441 t_constellation_device_id_t next_device_id{0};
442
443 std::unique_ptr<DataRecorder> data_recorder{};
444
445#ifdef XRT_FEATURE_RERUN
446 std::unique_ptr<struct RerunContext> rerun_stream{};
447#endif
448
449public: // Methods
450 static ConstellationTracker *
451 Get(xrt_frame_node *node)
452 {
453 return static_cast<ConstellationTracker *>(container_of(node, ConstellationTrackerBase, node));
454 }
455
456 static ConstellationTracker *
457 Get(t_constellation_tracker *tracker)
458 {
459 return reinterpret_cast<ConstellationTracker *>(tracker);
460 }
461
463
465
466 // Delete all copy/move ctors, since the pointers for `node` need to be stable
470 operator=(const ConstellationTracker &) = delete;
472 operator=(ConstellationTracker &&) = delete;
473
474 void
475 setupVariableTracking();
476
477 t_constellation_device_id_t
479
480 void
481 removeDevice(t_constellation_device_id_t device_id);
482};
483
484}; // namespace xrt::tracking::constellation
Definition device.hpp:68
Ab-initio blob<->LED correspondence search.
u_logging_level
Logging level enum.
Definition u_logging.h:45
@ U_LOGGING_WARN
Warning messages: indicating a potential problem.
Definition u_logging.h:49
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:68
LED search model management code.
C interface to math library.
Metrics for constellation tracking poses.
RANSAC PnP pose refinement.
Definition t_rift_blobwatch.c:88
Definition camera_model.h:19
Definition correspondence_search.h:95
All in one helper that handles locking, waiting for change and starting a thread.
Definition os_threading.h:499
Definition pose_metrics.h:105
Definition pose_metrics.h:79
Definition t_constellation.h:88
A generic interface to allow a tracking system to receive "snapshots" of seen t_blob in a frame.
Definition t_constellation.h:109
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:117
A blob is a 2d position in a camera sensor's view that is being tracked.
Definition t_constellation.h:45
Definition t_constellation.h:160
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:362
The LED model is a series of points which define the real-world positions of all LEDs.
Definition t_constellation.h:286
Definition t_constellation_tracker.h:110
A constellation tracker tracking source is an arbitrary source of tracking data for the constellation...
Definition t_constellation.h:229
Allows more safely to debug sink inputs and outputs.
Definition u_sink.h:214
Definition t_constellation_tracker_internal.hpp:199
os::Mutex processing_lock
Locks all processing data.
Definition t_constellation_tracker_internal.hpp:245
ConstellationTracker * tracker
The owner tracker, so we can retrieve it from the blob sink callback.
Definition t_constellation_tracker_internal.hpp:207
size_t index
The index in the mosaic.
Definition t_constellation_tracker_internal.hpp:217
Definition t_constellation_tracker_internal.hpp:317
size_t index
The index of this mosaic in the tracker.
Definition t_constellation_tracker_internal.hpp:321
Definition t_constellation_tracker_internal.hpp:116
std::optional< xrt_pose > Txr_world_cam
The camera's position in the constellation tracker's tracking origin.
Definition t_constellation_tracker_internal.hpp:125
Definition t_constellation_tracker_internal.hpp:171
Definition t_constellation_tracker_internal.hpp:411
Definition t_constellation_tracker_internal.hpp:425
Definition t_constellation_tracker_dataset.hpp:124
Definition t_constellation_tracker_internal.hpp:348
Definition t_constellation_tracker_internal.hpp:353
ConstellationTracker * tracker
The owner tracker, so we can retrieve it from the IMU sink callback.
Definition t_constellation_tracker_internal.hpp:361
Definition t_constellation_tracker_internal.hpp:337
Definition t_constellation_tracker_internal.hpp:101
t_constellation_device_id_t device_id
The ID of the device.
Definition t_constellation_tracker_internal.hpp:103
std::optional< xrt_pose > Txr_world_device_prior
The "predicted" pose, which is the pose the device expects itself to be at at the time of the blobser...
Definition t_constellation_tracker_internal.hpp:106
std::optional< FoundDevicePose > found_pose
The final found pose of the device in this specific sample.
Definition t_constellation_tracker_internal.hpp:109
bool needs_slow_processing
Whether the device needs to have the slow processing thread run over it.
Definition t_constellation_tracker_internal.hpp:112
Definition t_constellation_tracker_internal.hpp:93
Definition t_constellation_tracker_internal.hpp:193
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:139
An object to send IMU samples to.
Definition xrt_tracking.h:181
A pose composed of a position and orientation.
Definition xrt_defines.h:513
A tracking system or device origin.
Definition xrt_tracking.h:83
char name[256]
For debugging.
Definition xrt_tracking.h:85
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.