Skip to content

Feat/ivan/recordergo2livox#2266

Closed
leshy wants to merge 34 commits into
mainfrom
feat/ivan/recordergo2livox
Closed

Feat/ivan/recordergo2livox#2266
leshy wants to merge 34 commits into
mainfrom
feat/ivan/recordergo2livox

Conversation

@leshy

@leshy leshy commented May 27, 2026

Copy link
Copy Markdown
Member

support scripts for #2202

2026-05-27_16-31

mem2 streams:

  • odom - go2 odom
  • lidar emits lidar frames in world frame, pose is go2 odom
  • color_image topic logs as OPTICAL_FRAME derived from go2 odom base_link information

this ensures all go2 blueprints work

  • fastlio_odometry - fastlio odom
  • fastlio_lidar lidar frames in world frame, pose for this mem2 entry is set to fastlio odometry

this recording was created by me corecting @KrishnaH96 recording. (topic names, poses for messages)

there is no need to solve how we deal with transforms broadly

(I will in post-rebind image optical_frame to fastlio odom for fastlio calib,ration no worries about this)

for a recorder basically we don't want solution on how to treat frames in general, we want to start running recordings immediately with a few lines like this https://gist.github.com/leshy/56a27ef6eeebc16a5ecd2c2c7229d9ae

I'm sure above needs cleanup (don't have robot to test) but should create topics above

you can convert your recordings into rrd files you can open with rerun like this, they should look like my sample recording
uv run python -m dimos.mapping.loop_closure.utils.map_rrd mid360_sample --out map.rrd --camera-hz 0 && rerun map.rrd - check it out!

when recording apriltags pls look at them from a few angles (check my hk_village recordings), make sure to sit in place for a bit for blur to stabilize

the most important thing is that all messages use time.time()

other small tools like summary:

uv run python -m dimos.mapping.loop_closure.utils.summary mid360_sample
Stream("color_image"): 3899 items, 2026-05-27 01:53:172026-05-27 01:57:50 (273.4s)
Stream("fastlio_lidar"): 2386 items, 2026-05-27 01:53:172026-05-27 01:57:50 (273.4s)
Stream("fastlio_odometry"): 5283 items, 2026-05-27 01:53:172026-05-27 01:57:50 (273.5s)
Stream("lidar"): 2095 items, 2026-05-27 01:53:172026-05-27 01:57:50 (273.3s)
Stream("odom"): 5109 items, 2026-05-27 01:53:172026-05-27 01:57:50 (273.5s)

interactive trim tool in the same dir

leshy added 30 commits May 24, 2026 18:53
Replaces the monolithic pgo_then_voxels with four primitives over
mem2 Streams and Transforms:

  pgo_keyframes(lidar)            -> Stream[Keyframe]
  keyframes_to_corrections(kfs)   -> Stream[Transform]   (world_corrected <- world_raw)
  make_interpolator(corrections)  -> (ts) -> Transform   (SLERP + linear, endpoint-clipped)
  apply_corrections(stream, corr) -> Stream[T]           (shuffles obs.pose)

Drift correction is now a first-class, reusable Stream[Transform] that
any pose-stamped consumer can apply — same math as before (rigid
T_corr = T_global @ T_local^-1 per keyframe, SLERP + linear interpolation
between bracketing keyframes), just composable.

dimos map --pgo migrates to the new primitives; pgo_then_voxels is
deleted. The internal _SimplePGO / PGOConfig / _KeyPose machinery stays
in pgo.py and is imported by pgo2.
Renames:
  pgo.py  -> pgo_internals.py   (gtsam/ICP machinery)
  pgo2.py -> pgo.py             (public Stream-shaped API)

`dimos.mapping.relocalization.pgo` is now the canonical import path
(`pgo_keyframes`, `keyframes_to_corrections`, `make_interpolator`,
`apply_corrections`, `correction_at`, `Keyframe`). The internal
_SimplePGO / PGOConfig / _KeyPose / _icp / _voxel_downsample helpers
live in pgo_internals.py and are imported lazily inside pgo.py to keep
gtsam off the public-API import path.
Adds test_pgo.py covering pose normalization on Observation, the Transform↔Pose3
conversion helpers, the interpolator edge cases, apply_corrections behavior, and
a real-recording smoke test (skipped when data/go2_short.db is absent).
Annotates the two map.py helpers so they pass mypy. Removes leftover section
divider comments to satisfy the no-section-markers project rule.
The colors-copy block in `PointCloud2.transform` calls `self.pointcloud`
to check `has_colors()`, which forces a tensor->legacy conversion on
every invocation. With `pgo --full-pgo` rebuilding from hundreds of
lidar frames, that hidden allocation dominates the per-frame cost. The
colors path was lidar-irrelevant (lidar clouds have no colors anyway)
and the feature it was meant to support never landed; remove it so
transform() stays a clean numpy round-trip.
@codecov

codecov Bot commented May 27, 2026

Copy link
Copy Markdown

❌ 3 Tests Failed:

Tests completed Failed Passed Skipped
1865 3 1862 27
View the top 3 failed test(s) by shortest run time
::dimos.navigation.nav_stack.tests.test_cross_wall_planning_far
Stack Traces | 0s run time
.../nav_stack/tests/test_cross_wall_planning_far.py:24: in <module>
    from dimos.robot.unitree.g1.blueprints.navigation.unitree_g1_nav_sim import (
        __builtins__ = <builtins>
        __cached__ = '.../tests/__pycache__/test_cross_wall_planning_far.cpython-312.pyc'
        __doc__    = None
        __file__   = '/home/runner/work/dimos/dimos/.../nav_stack/tests/test_cross_wall_planning_far.py'
        __loader__ = <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7fc24640dc10>
        __name__   = 'dimos.navigation.nav_stack.tests.test_cross_wall_planning_far'
        __package__ = 'dimos.navigation.nav_stack.tests'
        __spec__   = ModuleSpec(name='dimos.navigation.nav_stack.tests.test_cross_wall_planning_far', loader=<_pytest.assertion.rewrite.Ass...7fc24640dc10>, origin='/home/runner/work/dimos/dimos/.../nav_stack/tests/test_cross_wall_planning_far.py')
        annotations = _Feature((3, 7, 0, 'beta', 1), None, 16777216)
        autoconnect = <function autoconnect at 0x7fc112a8e840>
        create_nav_stack = <function create_nav_stack at 0x7fbffe139080>
        pytest     = <module 'pytest' from '.../dimos/dimos/.venv/lib/python3.12.../site-packages/pytest/__init__.py'>
        run_cross_wall_test = <function run_cross_wall_test at 0x7fbffe2a54e0>
.../blueprints/navigation/unitree_g1_nav_sim.py:41: in <module>
    "paths_dir": str(G1_LOCAL_PLANNER_PRECOMPUTED_PATHS),
        Any        = typing.Any
        G1         = RobotConfig(name='unitree_g1', model_path=PosixPath('.../unitree/g1/g1.urdf'), e...}, auto_convert_meshes=True, tf_extra_links=[], task_type='trajectory', task_priority=10, collision_exclusion_pairs=[])
        G1_LOCAL_PLANNER_PRECOMPUTED_PATHS = <[RuntimeError('Missing required tools: git-lfs.\n\nGit LFS installation instructions: https://git-lfs.github.io/') raised in repr()] LfsPath object at 0x7fbffe0ae8d0>
        MovementManager = <class 'dimos.navigation.movement_manager.movement_manager.MovementManager'>
        UnityBridgeModule = <class 'dimos.simulation.unity.module.UnityBridgeModule'>
        __annotations__ = {}
        __builtins__ = <builtins>
        __cached__ = '.../navigation/__pycache__/unitree_g1_nav_sim.cpython-312.pyc'
        __doc__    = None
        __file__   = '/home/runner/work/dimos/dimos/.../blueprints/navigation/unitree_g1_nav_sim.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7fbffe098260>
        __name__   = 'dimos.robot.unitree.g1.blueprints.navigation.unitree_g1_nav_sim'
        __package__ = 'dimos.robot.unitree.g1.blueprints.navigation'
        __spec__   = ModuleSpec(name='dimos.robot.unitree.g1.blueprints.navigation.unitree_g1_nav_sim', loader=<_frozen_importlib_external....bffe098260>, origin='/home/runner/work/dimos/dimos/.../blueprints/navigation/unitree_g1_nav_sim.py')
        annotations = _Feature((3, 7, 0, 'beta', 1), None, 16777216)
        autoconnect = <function autoconnect at 0x7fc112a8e840>
        create_nav_stack = <function create_nav_stack at 0x7fbffe139080>
        g1_static_robot = <function g1_static_robot at 0x7fbffe0a8ae0>
        global_config = GlobalConfig(robot_ip=None, robot_ips=None, xarm7_ip=None, xarm6_ip=None, can_port=None, device_path=None, simulation=...e, obstacle_avoidance=True, detection_model='moondream', listen_host='127.0.0.1', dimsim_scene='apt', dimsim_port=8090)
        nav_stack_rerun_config = <function nav_stack_rerun_config at 0x7fbffe13b380>
        vis_module = <function vis_module at 0x7fbffe0ddbc0>
dimos/utils/data.py:336: in __str__
    return str(self._ensure_downloaded())
        self       = <[RuntimeError('Missing required tools: git-lfs.\n\nGit LFS installation instructions: https://git-lfs.github.io/') raised in repr()] LfsPath object at 0x7fbffe0ae8d0>
dimos/utils/data.py:314: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = 'unitree_g1_local_planner_precomputed_paths'
        self       = <[RuntimeError('Missing required tools: git-lfs.\n\nGit LFS installation instructions: https://git-lfs.github.io/') raised in repr()] LfsPath object at 0x7fbffe0ae8d0>
dimos/utils/data.py:271: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'unitree_g1_local_planner_precomputed_paths'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/unitree_g1_local_planner_precomputed_paths')
        name       = 'unitree_g1_local_planner_precomputed_paths'
        nested_path = None
        path_parts = ('unitree_g1_local_planner_precomputed_paths',)
dimos/utils/data.py:198: in _pull_lfs_archive
    _check_git_lfs_available()
        filename   = 'unitree_g1_local_planner_precomputed_paths'
dimos/utils/data.py:147: in _check_git_lfs_available
    raise RuntimeError(
E   RuntimeError: Missing required tools: git-lfs.
E   
E   Git LFS installation instructions: https://git-lfs.github.io/
        missing    = ['git-lfs']
::dimos.navigation.nav_stack.tests.test_cross_wall_planning_simple
Stack Traces | 0s run time
.../nav_stack/tests/test_cross_wall_planning_simple.py:24: in <module>
    from dimos.robot.unitree.g1.blueprints.navigation.unitree_g1_nav_sim import (
        __builtins__ = <builtins>
        __cached__ = '.../tests/__pycache__/test_cross_wall_planning_simple.cpython-312.pyc'
        __doc__    = None
        __file__   = '/home/runner/work/dimos/dimos/.../nav_stack/tests/test_cross_wall_planning_simple.py'
        __loader__ = <_pytest.assertion.rewrite.AssertionRewritingHook object at 0x7fc24640dc10>
        __name__   = 'dimos.navigation.nav_stack.tests.test_cross_wall_planning_simple'
        __package__ = 'dimos.navigation.nav_stack.tests'
        __spec__   = ModuleSpec(name='dimos.navigation.nav_stack.tests.test_cross_wall_planning_simple', loader=<_pytest.assertion.rewrite....24640dc10>, origin='/home/runner/work/dimos/dimos/.../nav_stack/tests/test_cross_wall_planning_simple.py')
        annotations = _Feature((3, 7, 0, 'beta', 1), None, 16777216)
        autoconnect = <function autoconnect at 0x7fc112a8e840>
        create_nav_stack = <function create_nav_stack at 0x7fbffe139080>
        pytest     = <module 'pytest' from '.../dimos/dimos/.venv/lib/python3.12.../site-packages/pytest/__init__.py'>
        run_cross_wall_test = <function run_cross_wall_test at 0x7fbffe2a54e0>
.../blueprints/navigation/unitree_g1_nav_sim.py:41: in <module>
    "paths_dir": str(G1_LOCAL_PLANNER_PRECOMPUTED_PATHS),
        Any        = typing.Any
        G1         = RobotConfig(name='unitree_g1', model_path=PosixPath('.../unitree/g1/g1.urdf'), e...}, auto_convert_meshes=True, tf_extra_links=[], task_type='trajectory', task_priority=10, collision_exclusion_pairs=[])
        G1_LOCAL_PLANNER_PRECOMPUTED_PATHS = <[RuntimeError('Missing required tools: git-lfs.\n\nGit LFS installation instructions: https://git-lfs.github.io/') raised in repr()] LfsPath object at 0x7fbffe0ae8d0>
        MovementManager = <class 'dimos.navigation.movement_manager.movement_manager.MovementManager'>
        UnityBridgeModule = <class 'dimos.simulation.unity.module.UnityBridgeModule'>
        __annotations__ = {}
        __builtins__ = <builtins>
        __cached__ = '.../navigation/__pycache__/unitree_g1_nav_sim.cpython-312.pyc'
        __doc__    = None
        __file__   = '/home/runner/work/dimos/dimos/.../blueprints/navigation/unitree_g1_nav_sim.py'
        __loader__ = <_frozen_importlib_external.SourceFileLoader object at 0x7fbffb3f7260>
        __name__   = 'dimos.robot.unitree.g1.blueprints.navigation.unitree_g1_nav_sim'
        __package__ = 'dimos.robot.unitree.g1.blueprints.navigation'
        __spec__   = ModuleSpec(name='dimos.robot.unitree.g1.blueprints.navigation.unitree_g1_nav_sim', loader=<_frozen_importlib_external....bffb3f7260>, origin='/home/runner/work/dimos/dimos/.../blueprints/navigation/unitree_g1_nav_sim.py')
        annotations = _Feature((3, 7, 0, 'beta', 1), None, 16777216)
        autoconnect = <function autoconnect at 0x7fc112a8e840>
        create_nav_stack = <function create_nav_stack at 0x7fbffe139080>
        g1_static_robot = <function g1_static_robot at 0x7fbffe0a8ae0>
        global_config = GlobalConfig(robot_ip=None, robot_ips=None, xarm7_ip=None, xarm6_ip=None, can_port=None, device_path=None, simulation=...e, obstacle_avoidance=True, detection_model='moondream', listen_host='127.0.0.1', dimsim_scene='apt', dimsim_port=8090)
        nav_stack_rerun_config = <function nav_stack_rerun_config at 0x7fbffe13b380>
        vis_module = <function vis_module at 0x7fbffe0ddbc0>
dimos/utils/data.py:336: in __str__
    return str(self._ensure_downloaded())
        self       = <[RuntimeError('Missing required tools: git-lfs.\n\nGit LFS installation instructions: https://git-lfs.github.io/') raised in repr()] LfsPath object at 0x7fbffe0ae8d0>
dimos/utils/data.py:314: in _ensure_downloaded
    cache = get_data(filename)
        cache      = None
        filename   = 'unitree_g1_local_planner_precomputed_paths'
        self       = <[RuntimeError('Missing required tools: git-lfs.\n\nGit LFS installation instructions: https://git-lfs.github.io/') raised in repr()] LfsPath object at 0x7fbffe0ae8d0>
dimos/utils/data.py:271: in get_data
    archive_path = _decompress_archive(_pull_lfs_archive(archive_name))
        archive_name = 'unitree_g1_local_planner_precomputed_paths'
        data_dir   = PosixPath('.../dimos/dimos/data')
        file_path  = PosixPath('.../dimos/dimos/data/unitree_g1_local_planner_precomputed_paths')
        name       = 'unitree_g1_local_planner_precomputed_paths'
        nested_path = None
        path_parts = ('unitree_g1_local_planner_precomputed_paths',)
dimos/utils/data.py:198: in _pull_lfs_archive
    _check_git_lfs_available()
        filename   = 'unitree_g1_local_planner_precomputed_paths'
dimos/utils/data.py:147: in _check_git_lfs_available
    raise RuntimeError(
E   RuntimeError: Missing required tools: git-lfs.
E   
E   Git LFS installation instructions: https://git-lfs.github.io/
        missing    = ['git-lfs']
dimos.project.test_no_sections::test_no_section_markers
Stack Traces | 0.29s run time
def test_no_section_markers():
        """
        Fail if any file contains section-style comment markers.
    
        If a file is too complicated to be understood without sections, then the
        sections should be files. We don't need "subfiles".
        """
        violations = find_section_markers()
        if violations:
            report_lines = [
                f"Found {len(violations)} section marker(s). "
                "If a file is too complicated to be understood without sections, "
                'then the sections should be files. We don\'t need "subfiles".',
                "",
            ]
            for path, lineno, text in violations:
                report_lines.append(f"  {path}:{lineno}: {text.strip()}")
>           raise AssertionError("\n".join(report_lines))
E           AssertionError: Found 11 section marker(s). If a file is too complicated to be understood without sections, then the sections should be files. We don't need "subfiles".
E           
E             .../mapping/loop_closure/eval.py:82: # --- PGO (timed) ---
E             .../mapping/loop_closure/eval.py:94: # --- Marker detection (same pipeline as dimos map / markers_rrd) ---
E             .../loop_closure/utils/map_rrd.py:212: # ---- per-frame raw clouds ----
E             .../loop_closure/utils/map_rrd.py:217: # ---- accumulated voxel maps (--map only) ----
E             .../loop_closure/utils/map_rrd.py:248: # ---- fastlio pose axis + path from fastlio_odometry stream ----
E             .../loop_closure/utils/map_rrd.py:272: # ---- Go2 native odom pose axis + path ----
E             .../loop_closure/utils/map_rrd.py:296: # ---- pass 2: camera pose + image per color_image ----
E             .../loop_closure/utils/markers_rrd.py:85: # ---- pass 1: robot base pose over time (from lidar.pose) ----
E             .../loop_closure/utils/markers_rrd.py:98: # ---- pass 2: camera pose + image per color_image frame ----
E             .../loop_closure/utils/markers_rrd.py:120: # ---- pass 3: marker detections (filtered same way as `dimos map`) ----
E             .../loop_closure/utils/markers_rrd.py:178: # ---- pass 4: averaged tracks (smoothing_window > 0 → per-track ids) ----

lineno     = 178
path       = '.../loop_closure/utils/markers_rrd.py'
report_lines = ['Found 11 section marker(s). If a file is too complicated to be understood without sections, then the sections should...louds ----', '  .../loop_closure/utils/map_rrd.py:217: # ---- accumulated voxel maps (--map only) ----', ...]
text       = '        # ---- pass 4: averaged tracks (smoothing_window > 0 → per-track ids) ----'
violations = [('.../mapping/loop_closure/eval.py', 82, '        # --- PGO (timed) ---'), ('.../mapping/loop_closure/eval.py', 9...-'), ('.../loop_closure/utils/map_rrd.py', 272, '        # ---- Go2 native odom pose axis + path ----'), ...]

dimos/project/test_no_sections.py:145: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs.

@github-actions github-actions Bot added the stale label Jun 20, 2026
@leshy leshy closed this Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant