Skip to content

feat(parser_ros): emit OccupancyGrid + OccupancyGridUpdate#119

Closed
facontidavide wants to merge 1 commit into
mainfrom
feat/occupancy-grid-parser
Closed

feat(parser_ros): emit OccupancyGrid + OccupancyGridUpdate#119
facontidavide wants to merge 1 commit into
mainfrom
feat/occupancy-grid-parser

Conversation

@facontidavide
Copy link
Copy Markdown
Contributor

Emits the canonical 3D-scene grid objects from the ROS parser:

  • nav_msgs/OccupancyGridsdk::OccupancyGrid (kOccupancyGrid)
  • map_msgs/OccupancyGridUpdatesdk::OccupancyGridUpdate (kOccupancyGridUpdate)

Two entries in RosParser::catalog() + two parseObject handlers in
ros_builtin_object_handlers.cpp, mirroring parsePointCloud: read CDR
little-endian, build a zero-copy ObjectRecord{BuiltinObject{…}} whose data span
slices the payload (the anchor keeps it alive), with width*height validation
and embedded-timestamp handling. Adds the readPose/readU8/readF64 helpers
used by the grid handler.

This is the producer half of the PJ4 pj_scene3D occupancy-grid feature (the
consumer — OccupancyGridEntity + a stateful reconstructor + textured-quad render
pass — lives in the PJ4 repo).

Verification

  • Branched on origin/main; builds against plotjuggler_core/0.5.0.
  • 32/32 existing parser tests pass (no regression).
  • Independent of Pin ROS parser to rosx_introspection 3.1.0 and support IDL schemas #96 — compiles against main's rosx_introspection (uses the
    common Deserializer API), so it does not need the IDL/3.0.0 refactor.
  • ABI-level object-route unit tests (synthetic CDR → asserted sdk fields) are a
    follow-up: the repo has no ParserObjectWriteRecorder harness yet.

🤖 Generated with Claude Code

Add catalog entries for nav_msgs/OccupancyGrid (-> kOccupancyGrid) and map_msgs/OccupancyGridUpdate (-> kOccupancyGridUpdate), plus parseObject handlers mirroring parsePointCloud: read CDR little-endian, build a zero-copy ObjectRecord{BuiltinObject{...}} whose data span slices the payload (anchor keeps it alive), with width*height validation and embedded-timestamp handling.

Builds against plotjuggler_core 0.5.0; the existing 33 parser tests pass. ABI-level object-route unit tests await a ParserObjectWriteRecorder test helper not yet present in the repo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
facontidavide added a commit that referenced this pull request May 30, 2026
…Update

Port the one unique producer from #119 (feat/occupancy-grid-parser): the
incremental delta-patch counterpart to OccupancyGrid (e.g. costmap_updates).

map_msgs/OccupancyGridUpdate -> kOccupancyGridUpdate, dual datastore+object
route: x/y/width/height stay plottable while the large data[] patch is
discarded by parseScalarsDiscardingLargeArrays. Byte-backed zero-copy cells
(span pinned by the payload anchor) with a width*height bounds check.
kOccupancyGridUpdate is available in core 0.5.x (builtin type id 15).

#119's OccupancyGrid half is redundant with this branch and is dropped;
its readPose/readF64 helpers were only needed there, so they are not ported.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@facontidavide
Copy link
Copy Markdown
Contributor Author

The unique map_msgs/OccupancyGridUpdate → kOccupancyGridUpdate producer from this PR has been ported into #122 (commit 419ff90), including the width*height bounds check. The nav_msgs/OccupancyGrid half is already covered there. Closing in favor of #122.

facontidavide added a commit that referenced this pull request May 30, 2026
…Update

Port the one unique producer from #119 (feat/occupancy-grid-parser): the
incremental delta-patch counterpart to OccupancyGrid (e.g. costmap_updates).

map_msgs/OccupancyGridUpdate -> kOccupancyGridUpdate, dual datastore+object
route: x/y/width/height stay plottable while the large data[] patch is
discarded by parseScalarsDiscardingLargeArrays. Byte-backed zero-copy cells
(span pinned by the payload anchor) with a width*height bounds check.
kOccupancyGridUpdate is available in core 0.5.x (builtin type id 15).

#119's OccupancyGrid half is redundant with this branch and is dropped;
its readPose/readF64 helpers were only needed there, so they are not ported.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
facontidavide added a commit that referenced this pull request Jun 1, 2026
…Marker→SceneEntities producers (#122)

* feat(parser_ros): emit FrameTransforms object for tf2_msgs/TFMessage

tf2_msgs/TFMessage now produces BOTH a canonical sdk::FrameTransforms object
(objectstore — for the 3D scene's per-dataset TF buffer) AND its existing
flattened scalar fields (datastore — for plotting transforms as time series).
This is dual registration in the schema catalog: object_type + parse_object
added alongside the existing parse_scalars, the same pattern Image/PointCloud2
already use.

parseFrameTransforms decodes the CDR TFMessage into one FrameTransform per
TransformStamped, each carrying its OWN Header.stamp — the per-sample time the
TF buffer needs for zero-order-hold scrub lookups — independent of the message
receive time.

Test: TFMessageProducesFrameTransformsObject verifies classifySchema reports
kFrameTransforms and that parseObject decodes a 2-transform message with the
correct per-transform timestamps, parent/child frames, translation, and
rotation. 29/29 parser_ros tests pass against plotjuggler_core 0.3.1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(parser_ros): add OccupancyGrid, TransformStamped, RobotDescription producers

Extends the dual datastore+objectstore producer set with three more
unambiguous, self-contained canonical types (all present in core 0.3.1):

- nav_msgs/OccupancyGrid -> kOccupancyGrid: byte-backed, cells zero-copied as
  a Span over the payload; dual-registered with discard-large-array scalars.
- geometry_msgs/TransformStamped -> kFrameTransforms: single-element, sharing
  the new readStampedTransform helper with the TFMessage producer.
- std_msgs/String on a robot_description topic -> kRobotDescription, with a
  best-effort urdf/sdf/mjcf format hint sniffed from the root element.
  Topic-gated in bindSchema (a generic String stays a scalar), resolving the
  dispatch ambiguity by topic name.

Deferred (ambiguous / stateful, or not in 0.3.1): Markers (type switch +
action/lifetime/identity), DepthImage (encoding dispatch + CameraInfo),
CameraInfo / OccupancyGridUpdate.

Tests: object-route decode for each, plus a negative test that a String on a
non-robot_description topic is NOT classified as RobotDescription. 33/33
parser_ros tests pass against plotjuggler_core 0.3.1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(parser_ros): OccupancyGrid + RobotDescription object-only; match namespaced robot_description

Routing per design: only TFMessage and TransformStamped are dual
datastore+objectstore (their transforms are useful plotted as time series).
OccupancyGrid and RobotDescription are object-store only — a map/costmap and a
URDF/SDF/MJCF document aren't useful as scalar columns — so their parse_scalars
is dropped (SchemaHandler permits a null scalar route).

robot_description topic-gating already matched namespace-prefixed topics via
ends_with("/robot_description"); make that explicit in the comment and cover it
with a test for "/my_robot/robot_description" (which also exercises the SDF
format sniff).

34/34 parser_ros tests pass against plotjuggler_core 0.3.1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(parser_ros): visualization_msgs/Marker(Array) -> SceneEntities

Per-message, stateless conversion of Marker / MarkerArray into the canonical
sdk::SceneEntities object (one SceneEntity per ADD/MODIFY marker, one
SceneEntityDeletion per DELETE/DELETEALL). Decoders in a new
ros_marker_handlers.cpp; catalog + bindSchema wiring; tests; MARKER_NOTES.md
captures the design.

- Type map: CUBE/SPHERE/CYLINDER/LINE_*/TRIANGLE_LIST/TEXT_VIEW_FACING ->
  matching primitives; MESH_RESOURCE -> ModelPrimitive; CUBE_LIST/SPHERE_LIST
  expand to N primitives; POINTS/ARROW_STRIP skipped (no canonical mapping).
- (ns,id) -> length-prefixed entity id; lifetime/frame_locked carried through;
  ColorRGBA float->uint8; per-vertex colors only when sized to the points.
- Positional CDR decode with a bindSchema sniff (uv_coordinates / mesh_file)
  so the humble+ texture/mesh_file tail is consumed correctly on every distro,
  keeping MarkerArray elements aligned.

Statefulness (accumulation, lifetime expiry) is intentionally left to a future
3D scene consumer, not the parser; see MARKER_NOTES.md. Requires the
SceneEntities ModelPrimitive + deletions[] additions in plotjuggler_core.

Parser-side groundwork: no kSceneEntities renderer exists yet, so this is
exercised by unit tests only (not yet built in this environment due to an
unrelated plugin-dependency build issue).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(parser_ros,data_load_mcap): object-route timestamps, OccupancyGrid ingest fix, MCAP latched-stamp clamp

parser_ros: object producers (FrameTransforms, TransformStamped, OccupancyGrid,
RobotDescription, Marker, MarkerArray) now return ObjectRecord, threading the
parser-controlled embedded timestamp (use_embedded_timestamp_) through the
object route instead of returning a bare BuiltinObject.

parser_ros: nav_msgs/OccupancyGrid keeps its parse_scalars route
(parseScalarsDiscardingLargeArrays). An object-only entry (no parse_scalars)
aborts the message push before the object route runs, so the scalar handler is
required for the grid to reach the ObjectStore; metadata stays plottable while
the large data[] array is discarded.

data_load_mcap: clamp header (publishTime) stamps that fall outside the
recording's log-time window to its first timestamp. Latched / long-running
publishers (static TF, robot_description, pre-computed maps) would otherwise
drag the playback range off the actual recording. useMcapLogTime() still forces
the message's own logTime.

* feat(parser_ros): emit OccupancyGridUpdate for map_msgs/OccupancyGridUpdate

Port the one unique producer from #119 (feat/occupancy-grid-parser): the
incremental delta-patch counterpart to OccupancyGrid (e.g. costmap_updates).

map_msgs/OccupancyGridUpdate -> kOccupancyGridUpdate, dual datastore+object
route: x/y/width/height stay plottable while the large data[] patch is
discarded by parseScalarsDiscardingLargeArrays. Byte-backed zero-copy cells
(span pinned by the payload anchor) with a width*height bounds check.
kOccupancyGridUpdate is available in core 0.5.x (builtin type id 15).

#119's OccupancyGrid half is redundant with this branch and is dropped;
its readPose/readF64 helpers were only needed there, so they are not ported.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(parser_ros): silence nodiscard deserializer warnings

* Fix parser_ros object RTTI on macOS

---------

Co-authored-by: Davide Faconti <dfaconti@aurynrobotics.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant