feat(transformations): support custom reference timestamp in motion (de)compensation#146
Merged
Merged
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
Collaborator
Author
|
This supersedes janickm#1 and addresses all the review feedback there:
Targets |
…de)compensation Add an optional `reference_timestamp_us` parameter to `MotionCompensator.motion_compensate_points` and `motion_decompensate_points`. It defaults to `frame_end_timestamp_us`, preserving the existing end-of-frame behavior used by the existing converters. Datasets that compensate to a different in-frame reference (e.g. the start of the frame) can now pass it explicitly. `motion_decompensate_points` is reimplemented as the exact inverse of `motion_compensate_points`: per point it evaluates the sensor pose at the point's own timestamp relative to the reference sensor pose (`T_sensor_reftime_sensor_pointtime = T_world_sensor_pointtime @ T_sensor_reftime_world`) rather than linearly interpolating the end->start relative transform. This generalizes to any reference and is at least as accurate (it uses the real trajectory at each point time). Naming / API cleanups: - `MotionCompensationResult` fields renamed from the misleading `xyz_s_sensorend` / `xyz_e_sensorend` to `xyz_s_reftime` / `xyz_e_reftime`, and the struct now carries `reference_timestamp_us` unconditionally. - `motion_decompensate_points` parameter `xyz_sensorend` -> `xyz_reftime`. - Internal transforms use the consistent `T_<source>[_time]_<target>[_time]` snake_case convention (no camelCase, no stray `sensorend`/`sensorRef`). - All callers updated: ncore/impl/data/v4/compat.py, the nuScenes and Waymo converters, structured_lidar_model.py, and the ncore_project_pc_to_img / ncore_evaluate_lidar_model tools. Tests: a custom-reference compensate/decompensate round-trip sweeping several references across the [frame_start, frame_end] range (boundaries plus interior fractions), and a check that the default reference matches an explicit end-of-frame reference. The existing idempotence test still passes.
ce1e5ef to
b0556d4
Compare
Collaborator
Author
|
/ok to test b0556d4 |
This was referenced Jun 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add an optional
reference_timestamp_usparameter toMotionCompensator.motion_compensate_pointsandmotion_decompensate_points, so callers can choose which in-frame timestamp the points are motion-compensated to / from.It defaults to
frame_end_timestamp_us, preserving the existing end-of-frame behavior used by the KITTI / nuScenes / Waymo converters.Motivation
Different datasets motion-compensate lidar sweeps to different in-frame references. The API previously hard-coded the end-of-frame reference. Argoverse 2, for example, compensates each sweep to the sweep reference timestamp, which is the start of the sweep (
offset_nsruns forward from it). Without an explicit reference, decompensating such data with the end-of-frame assumption applies the full intra-sweep ego motion (~1 m) as a systematic error.This makes the compensation reference an explicit, optional parameter so converters can express their dataset's convention directly.
Changes
motion_compensate_points/motion_decompensate_points: newreference_timestamp_us: Optional[int] = None(defaults toframe_end_timestamp_us), asserted to lie within[frame_start, frame_end].motion_decompensate_pointsis reimplemented as the exact inverse ofmotion_compensate_points: per point it evaluates the sensor pose at the point's own timestamp relative to the reference sensor pose (T_sensor_pointtime_world @ T_world_sensor_reftime) instead of linearly interpolating the end->start relative transform. This generalizes to any reference and is at least as accurate.MotionCompensationResult: fields renamed from the (now misleading)xyz_s_sensorend/xyz_e_sensorendtoxyz_s_reftime/xyz_e_reftime, and the struct now carriesreference_timestamp_usunconditionally.T_<source>[_time]_<target>[_time]snake_case convention (no camelCase, no straysensorend/sensorRef).ncore/impl/data/v4/compat.py, the nuScenes and Waymo converters,structured_lidar_model.py, and thencore_project_pc_to_img/ncore_evaluate_lidar_modeltools.Testing
bazel test //ncore/impl/common:test_3_11 \ //ncore/impl/data/v4:pytest_compat_3_11 \ //ncore/impl/sensors:pytest_lidar_3_11New tests:
test_idempotence_custom_reference_timestamp-- compensate to a non-default reference (frame start) and decompensate back recovers the original points.test_default_reference_matches_explicit_end_of_frame-- omittingreference_timestamp_usequals passingframe_endexplicitly.The existing
test_idempotencestill passes, as do the compat and lidar sensor tests (which consume the renamed result fields). All of//ncore/...and the affected//tools/...packages build and type-lint cleanly.This unblocks the Argoverse 2 converter (separate PR #145), which will call
motion_decompensate_points(..., reference_timestamp_us=sweep_ts).