Commit graph

2398 commits

Author SHA1 Message Date
Thomas Thron
f23d298e6f src/driver_global_scene_solver.c: add_scenes: clean up old scenes after tracker was turned off and on again 2026-07-22 10:05:00 -04:00
Thomas Thron
a1b32719d3 driver_vive.libusb.h: handle_transfer: goto object_turned_off if survive_device_is_rf is true for the object 2026-07-22 10:05:00 -04:00
Thomas Thron
4e8705d68b driver_vive.c: move survive_device_is_rf up 2026-07-22 10:05:00 -04:00
Mark Stalzer
1b9cef68db mp_fdjac2: guard non-finite numerical derivatives
The only protection against a non-finite finite-difference derivative
here was assert(isfinite(fjac[ij])), which a release build (-DNDEBUG)
strips out entirely, and the two-sided derivative path had no check at
all. If the user function returns a degenerate residual for some
parameter value, wa[i]/fvec[i] can be non-finite, writing NaN/Inf
straight into fjac.

That NaN then poisons fnorm/ratio in mpfit()'s outer Levenberg-Marquardt
loop. Since any comparison against NaN is false, the iteration counter
(which only advances inside the ratio>=p0001 success branch) never
increments, so the maxiter check that's supposed to bound the loop never
fires. The result is an unbounded CPU spin instead of a clean failure
return -- in our case, confirmed via gdb on a real reproduction: ~465k
spin iterations/sec with zero progress, instead of returning MP_MAXITER.

Fix: sanitize fjac to 0 on a non-finite derivative in all three
non-debug/debug, one-sided/two-sided paths, so the column is treated as
having no measurable gradient -- the same fallback mp_qrfac already uses
for a zero-norm column.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-13 14:03:09 -04:00
Thomas Thron
721a58d27c poser_mpfit.c: solve_global_scene: early out when bestObjForCal == -1 2026-07-13 11:08:26 -04:00
Ben E.
d230bf7bd2 Fix typo in survive_simple_object_charge_percet (percent) 2026-07-06 09:32:41 -04:00
Thomas Thron
0ee549cc25 apply patch from MPFit v1.4 2026-07-06 09:31:10 -04:00
Mark Stalzer
5588cadf5a macOS: plugin loading, hidapi, and alloca/stdlib.h fixes
survive_plugins.unix.h: use .dylib extension and _NSGetExecutablePath()
on Apple. Also fixes a latent Linux bug where readlink() return value
was used as an array index without checking for error (-1).

CMakeLists.txt: find hidapi on Apple via pkg-config rather than
hardcoded Homebrew paths, which differ between Apple Silicon
(/opt/homebrew) and Intel (/usr/local).

cn_matrix.h: replace <malloc.h> with <stdlib.h> unconditionally, but
guard the re-inclusion of <malloc.h> with _WIN32. <malloc.h> does not
exist on macOS; <stdlib.h> provides malloc on all platforms. MSVC does
not declare alloca in <stdlib.h> — it lives in <malloc.h>.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 15:05:38 +00:00
Mark Stalzer
3388071730 driver_vive: downgrade unknown lightcap report from error to warning
SV_ERROR with SURVIVE_ERROR_HARWARE_FAULT crashes the process when an
unrecognised USB lightcap report ID is received. New tracker firmware
routinely emits report IDs that older libsurvive versions do not know;
crashing on an unrecognised ID makes libsurvive incompatible with any
firmware newer than it was built against.

The adjacent VIVE_REPORT_USB_TRACKER_LIGHTCAP_V1 case already uses
SV_INFO and ignores the packet. Apply the same treatment to the unknown
case: log a warning and continue so tracking on all known report types
is unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 15:34:59 +00:00
Mark Stalzer
08b0d8c713 driver_vive: clear_halt before submit_transfer in AttachInterface
A stalled USB endpoint must be cleared before resubmitting a transfer.
Without libusb_clear_halt(), libusb_submit_transfer() will return
LIBUSB_ERROR_PIPE (-9) on any endpoint left halted from a previous
session or failed transfer, causing the interface attachment to fail.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 15:33:58 +00:00
Mark Stalzer
d63f79f1fe variance_measure_add: skip non-finite input instead of asserting
An assert(isfinite(d[i])) crash here corrupts the on-disk libsurvive
config because the process dies mid-write. Corrupt optical angles
(e.g. bad FPGA timestamps during USB disturbances) can produce NaN or
Inf values that reach this function; crashing is strictly worse than
dropping one sample, which has negligible effect on the variance estimate.

Replace the assert with an early-return guard that logs to stderr and
leaves the accumulator unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 19:33:43 +00:00
xu.chai
b41840d315 poser_mpfit: Skip disabled lighthouses to prevent matrix assertion failures 2026-05-08 19:07:16 +00:00
Mark Stalzer
2f4303c76f solve_global_scene: treat MP_MAXITER as calibration failure
MP_MAXITER (return code 5) means the solver exhausted its iteration
budget without converging. The current code treats this as success
(res <= 0 is false), so the unconverged — and potentially wrong —
lighthouse positions are written to disk via survive_recording and
the GSS result is accepted.

On the next launch those positions are loaded as the starting point
for calibration. If the unconverged solve is significantly wrong,
all subsequent tracking is corrupted and the only recovery is to
delete config.json.

Adding res == MP_MAXITER to the failure condition rejects unconverged
GSS solves the same way as explicit solver errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 20:55:11 +00:00
Mark Stalzer
bf27b41570 kalman: cap process noise dt to prevent t^7 explosion on tracking gaps
Cap dt at 0.05s (5x the normal ~8ms IMU interval) before computing the
power series. State prediction still uses the real dt; only uncertainty
growth (Q matrix) is bounded. Without this cap, a gap of ~1s yields
t^7 = 1.0 which inflates Q enough to cause NaN/Inf in the filter on the
next update (observed as a quatrotateabout assertion failure on cold start
or blackout recovery). This matches standard practice for discretised
continuous-time process noise models where large gaps should widen
uncertainty to a finite maximum rather than to infinity.

Fixes: tracker freezes after lighthouse occlusion / blackout recovery
       (collabora/libsurvive#346)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 20:51:39 +00:00
Eidenz
8f80f7fa5e feat: Beyond device to survive_default_devices 2026-03-20 03:01:08 +00:00
Mark Stalzer
1fb4276add fix quatdist clamp: swapped min/max caused function to always return 0
linmath_max(1., linmath_min(-1, rtn)) always clamps the dot product to
1.0: linmath_min(-1, x) is always ≤ -1 for any x, then
linmath_max(1, ≤-1) = 1, so acos(|1.0|) = 0 for every input.

Fix: linmath_min(1., linmath_max(-1., rtn)) correctly clamps to [-1, 1].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 11:19:53 -04:00
Mark Stalzer
eb409fcc63 fix quattomatrix33 row/column-major mismatch
quattomatrix33 outputs column-major (comment says "opengl major") but
quatfrommatrix33 reads row-major, and the 4x4 quattomatrix also outputs
row-major. This means a quat->matrix33->quat roundtrip produces the
conjugate (inverse rotation) instead of the original quaternion.

Fix by swapping the three off-diagonal pairs so quattomatrix33 outputs
row-major, consistent with the rest of the codebase.

The only runtime caller is barycentric_svd.c which passes the result to
cn_copy_in_row_major() — previously loading the transpose, now correct.
This doesn't affect tracking results because it only needs an arbitrary
valid rotation for control point initialization.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 20:33:04 +00:00
Mark Stalzer
477688f4e6 fix use-of-uninitialized-value in survive_kalman_tracker_stats
integration_variance[16] is stack-allocated but variance_tracker_calc()
may not write all elements when the tracker had zero observations
(counts == 0 or variance.size == 0). The uninitialized array is then
read by SV_VERBOSE via LINMATH_VEC7_EXPAND / LINMATH_VEC6_EXPAND.

Found by MSan when running test_replays.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 20:32:42 +00:00
Timo Witte
32cf62c527 initialize variables before logging 2025-04-07 14:14:44 +00:00
Simon Zeni
440518bb7b driver/gatt: upgrade to gattlib 0.7.2 2025-03-28 13:05:46 +00:00
Simon Zeni
8ef4e51654 cnkalman: upgrade to sciplot 0.3.1 2025-03-28 13:05:46 +00:00
Simon Zeni
8d4765a067 readme: remove recursive clone instruction 2025-03-26 13:41:11 +00:00
Simon Zeni
400d09e0f9 remove pybind11 submodule 2025-03-26 13:41:11 +00:00
Simon Zeni
7fb54776be cnkalman: remove python binding 2025-03-26 13:41:11 +00:00
Simon Zeni
3e6edf135b submodule cleanup 2025-03-17 11:29:22 -04:00
Simon Zeni
b283686e71 merge cnmatrix subtree 2025-03-17 10:15:36 -04:00
Simon Zeni
f686f09666 merge cnkalman subtree 2025-03-17 10:05:41 -04:00
Simon Zeni
0d46c0e9b2 ci: docker checkout recursive 2025-03-11 20:49:04 +00:00
Simon Zeni
f896c0a70d ci: skip tests on windows, missing DLL 2025-03-11 20:49:04 +00:00
Simon Zeni
af5ecd64f4 cmake: use CMAKE_VS_NUGET_PACKAGE_RESTORE on win32 2025-03-11 20:49:04 +00:00
Simon Zeni
8898910aa9 cnkalman: update submodule 2025-03-11 20:49:04 +00:00
Simon Zeni
4ca33a3b55 ci: rework build_wheels workflow 2025-03-11 20:49:04 +00:00
Simon Zeni
2ea4422060 ci: temporarily disable build wheels on aarch64 2025-03-11 20:49:04 +00:00
Simon Zeni
50922381e5 cmake: set C11 and C++20 requirements 2025-03-11 20:49:04 +00:00
Simon Zeni
a3aa1cec8e cnmatrix: update submodule 2025-03-11 15:41:49 -04:00
Simon Zeni
18407cb686 ci: overwrite asset upload 2025-03-11 15:21:18 -04:00
Simon Zeni
8b37e7793f ci: update to actions/upload-artifact@v4 2025-03-11 14:51:47 -04:00
Simon Zeni
a8801918f3 fix NAN constant initialization 2025-03-11 14:47:36 -04:00
Thomas Thron
c612dc1fba move examples to subfolder to avoid confusion of pysurvive import with virtual environment 2025-03-11 14:52:26 +00:00
Thomas Thron
5975608296 pyproject.toml: remove cmake_setuptools as build requirement 2025-03-11 14:52:26 +00:00
Thomas Thron
bfecd3270f setup.py: remove unnecessary import 2025-03-11 14:52:26 +00:00
Thomas Thron
db86783cb2 setup.py: refactor 2025-03-11 14:52:26 +00:00
Thomas Thron
9c3e6aa6bb Makefile: copy plugins also 2025-03-11 14:52:26 +00:00
Thomas Thron
859aff5a33 bindings: fix paths in makefile 2025-03-11 14:52:26 +00:00
Thomas Thron
1daedb3f68 move build depdendencies from setup.py to pyproject.toml 2025-03-11 14:52:26 +00:00
Thomas Thron
2beaa61d71 gitignore: add _skbuild folder 2025-03-11 14:52:26 +00:00
Simon Zeni
766d783de8 ci: use actions/upload-artifact@v4 2025-03-10 15:31:19 +00:00
KoenigSimon
9d8ec46f02 change buffer size to 64 to allow protocol switching on windows 2025-03-07 14:11:23 +00:00
Simon Zeni
4fb6d888d0 src/driver_usbmon: replace off64_t by z_off_t
`off64_t` is not a language defined type and is not available everywhere. Instead
the function should use `z_off_t` which is defined by zlib (and is most likely
`off_t`)
2024-05-10 16:53:37 +02:00
thetaengineering
037189ebbc Fix sensor data loss on linux caused by 464dd97 (#294) 2024-01-23 19:52:14 +01:00