feat(recording): go2_mid360 + mid360_realsense_30 recorders#2588
feat(recording): go2_mid360 + mid360_realsense_30 recorders#2588jeff-hykin wants to merge 5 commits into
Conversation
Add memory2-based record blueprints for the Go2+Mid-360 and RealSense D435i+Mid-360 rigs: - PointlioPoseRecorder: shared Recorder base stamping each lidar frame with the latest odometry pose. - StaticTfPublisher: republishes a rig's static mount frames onto /tf on an interval (PubSubTF has no latched static tf), so they're captured in the recording's tf stream. - Go2Mid360Recorder / Mid360RealsenseRecorder + their static-transform trees and record blueprints (unitree-go2-mid360-record, mid360-realsense-record). Pygame WASD teleop on the go2 rig. - Raw Livox capture is opt-in via RECORD_PCAP=1 (reuses the existing Mid360PcapRecorder); default off. - Recording doc moved to experimental/docs/nav/map_recording/go2_mid360.md (post-processing stripped). Regenerated all_blueprints.py.
Greptile SummaryThis PR adds two new map-recording blueprints —
Confidence Score: 4/5Safe to merge; the only open issue is that The
Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Mid360
participant PointLio
participant PointlioPoseRecorder
participant StaticTfPublisher
participant Memory2DB
Mid360->>PointLio: livox_lidar / livox_imu
PointLio->>PointlioPoseRecorder: pointlio_odometry
PointlioPoseRecorder->>PointlioPoseRecorder: _odom_pose() stores pose + raw_ts
PointLio->>PointlioPoseRecorder: pointlio_lidar
PointlioPoseRecorder->>PointlioPoseRecorder: _lidar_pose() checks staleness (≤0.1s)
PointlioPoseRecorder->>Memory2DB: frame + pose (or unposed if stale)
loop every 1/publish_hz seconds
StaticTfPublisher->>StaticTfPublisher: stamp transforms with time.now()
StaticTfPublisher->>Memory2DB: tf.publish(mount frames)
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Mid360
participant PointLio
participant PointlioPoseRecorder
participant StaticTfPublisher
participant Memory2DB
Mid360->>PointLio: livox_lidar / livox_imu
PointLio->>PointlioPoseRecorder: pointlio_odometry
PointlioPoseRecorder->>PointlioPoseRecorder: _odom_pose() stores pose + raw_ts
PointLio->>PointlioPoseRecorder: pointlio_lidar
PointlioPoseRecorder->>PointlioPoseRecorder: _lidar_pose() checks staleness (≤0.1s)
PointlioPoseRecorder->>Memory2DB: frame + pose (or unposed if stale)
loop every 1/publish_hz seconds
StaticTfPublisher->>StaticTfPublisher: stamp transforms with time.now()
StaticTfPublisher->>Memory2DB: tf.publish(mount frames)
end
Reviews (4): Last reviewed commit: "refactor(recording): mid360_realsense as..." | Re-trigger Greptile |
| config: PointlioPoseRecorderConfig | ||
|
|
||
| pointlio_odometry: In[Odometry] | ||
| pointlio_lidar: In[PointCloud2] | ||
|
|
There was a problem hiding this comment.
No staleness guard on
_lidar_pose — stale odometry silently mis-stamps frames
_lidar_pose returns _last_odom_pose unconditionally, with no check on how old that pose is. If Point-LIO temporarily drops its odometry output (degenerate geometry, topic lag, process hiccup), every subsequent lidar frame will be stamped with the last known pose rather than None. None causes the frame to be map-skipped, which is the correct fallback; a stale pose causes it to be registered at the wrong location, silently corrupting the map.
The existing PointlioRecorder uses _POSE_MATCH_TOL = 0.1 s on the raw sensor timestamps (abs(raw_ts - self._last_odom_raw_ts) <= _POSE_MATCH_TOL) to detect exactly this case. The same guard — tracking _last_odom_raw_ts and comparing it against the lidar frame's raw ts — should be applied here so the behavior is consistent.
| class Go2Mid360Recorder(PointlioPoseRecorder): | ||
| pointlio_odometry: In[Odometry] | ||
| pointlio_lidar: In[PointCloud2] | ||
| go2_lidar: In[PointCloud2] |
There was a problem hiding this comment.
These two ports are already declared on
PointlioPoseRecorder; re-declaring them here is redundant and could confuse readers into thinking the subclass owns them. The same applies to Mid360RealsenseRecorder.
| class Go2Mid360Recorder(PointlioPoseRecorder): | |
| pointlio_odometry: In[Odometry] | |
| pointlio_lidar: In[PointCloud2] | |
| go2_lidar: In[PointCloud2] | |
| class Go2Mid360Recorder(PointlioPoseRecorder): | |
| go2_lidar: In[PointCloud2] |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
|
||
| def _default_recording_dir() -> Path: | ||
| now = datetime.now() | ||
| stamp = now.strftime("%Y-%m-%d") + "_" + now.strftime("%I-%M%p").lower() + "-PST" |
There was a problem hiding this comment.
The
-PST suffix is hardcoded regardless of the machine's actual timezone. datetime.now() returns local time, so on a machine set to UTC or any other zone the label is misleading. The same issue exists in mid360_realsense_30/mid360_realsense_record.py at the same line. The simplest fix is to drop the suffix, or use datetime.now().astimezone().strftime("%Z") to pick up the real zone abbreviation.
| stamp = now.strftime("%Y-%m-%d") + "_" + now.strftime("%I-%M%p").lower() + "-PST" | |
| stamp = now.strftime("%Y-%m-%d") + "_" + now.strftime("%I-%M%p").lower() |
Codecov Report❌ Patch coverage is @@ Coverage Diff @@
## main #2588 +/- ##
==========================================
+ Coverage 69.61% 70.76% +1.15%
==========================================
Files 878 875 -3
Lines 79326 77630 -1696
Branches 7126 6893 -233
==========================================
- Hits 55220 54936 -284
+ Misses 22301 20890 -1411
+ Partials 1805 1804 -1
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 16 files with indirect coverage changes 🚀 New features to boost your workflow:
|
…z label Address Greptile review on PR #2588: - pose_recorder: guard pointlio_lidar pose-stamping with _POSE_MATCH_TOL (0.1s) on raw odom ts, matching PointlioRecorder. Stale odometry now yields an unposed (map-skipped) frame instead of mis-stamping at the last pose. - go2/realsense recorders: drop redundant pointlio_odometry/pointlio_lidar port re-declarations (inherited from PointlioPoseRecorder). - record blueprints: use datetime.now().astimezone() + %Z for the recordings dir label instead of a hardcoded -PST suffix.
mid360_realsense_30/__init__.py was license-header only; the repo forbids __init__.py under dimos/. Namespace-package import still works.
Rename mid360_realsense_record.py -> blueprints.py, drop the __main__ runner, and expose two blueprints instead of the RECORD_PCAP env toggle: - mid360_realsense_record (db only) - mid360_realsense_record_with_pcap (db + raw Mid-360 pcap) Matches the repo's blueprints.py convention (e.g. virtual_mid360). Regenerated all_blueprints.py.
go2_mid360andmid360_realsenserecording blueprints