From 932bc6e82ac1ff238425b4be8ed81ff98bfff201 Mon Sep 17 00:00:00 2001 From: cc Date: Wed, 30 Sep 2026 23:02:57 -0700 Subject: [PATCH 01/11] refactor: assemble legacy message retirement with M20 gate explicitly pending --- dimos/msgs/foxglove_msgs/CompressedVideo.py | 107 --- dimos/msgs/geometry_msgs/Point.py | 33 - dimos/msgs/geometry_msgs/PointStamped.py | 102 --- dimos/msgs/geometry_msgs/Pose.py | 265 ------- .../msgs/geometry_msgs/PoseWithCovariance.py | 201 ----- .../PoseWithCovarianceStamped.py | 98 --- dimos/msgs/geometry_msgs/Quaternion.py | 325 -------- dimos/msgs/geometry_msgs/Transform.py | 329 -------- dimos/msgs/geometry_msgs/Twist.py | 132 ---- dimos/msgs/geometry_msgs/TwistStamped.py | 85 --- .../msgs/geometry_msgs/TwistWithCovariance.py | 181 ----- .../TwistWithCovarianceStamped.py | 106 --- dimos/msgs/geometry_msgs/Vector3.py | 434 ----------- dimos/msgs/geometry_msgs/Wrench.py | 121 --- dimos/msgs/geometry_msgs/WrenchStamped.py | 97 --- .../msgs/manipulation_msgs/GraspCandidate.py | 40 - .../manipulation_msgs/GraspCandidateArray.py | 48 -- dimos/msgs/nav_msgs/OccupancyGrid.py | 598 --------------- dimos/msgs/nav_msgs/Odometry.py | 249 ------- dimos/msgs/nav_msgs/Path.py | 214 ------ dimos/msgs/sensor_msgs/CompressedImage.py | 175 ----- dimos/msgs/sensor_msgs/Image.py | 700 ------------------ dimos/msgs/sensor_msgs/Imu.py | 125 ---- dimos/msgs/sensor_msgs/ImuInfo.py | 158 ---- dimos/msgs/sensor_msgs/JointCommand.py | 143 ---- dimos/msgs/sensor_msgs/JointState.py | 144 ---- dimos/msgs/sensor_msgs/Joy.py | 130 ---- dimos/msgs/sensor_msgs/MotorCommandArray.py | 133 ---- dimos/msgs/sensor_msgs/RobotState.py | 188 ----- .../sensor_msgs/image_impls/AbstractImage.py | 17 - dimos/msgs/std_msgs/Bool.py | 28 - dimos/msgs/std_msgs/Float32.py | 30 - dimos/msgs/std_msgs/Header.py | 106 --- dimos/msgs/std_msgs/Int32.py | 32 - dimos/msgs/std_msgs/Int8.py | 32 - dimos/msgs/std_msgs/String.py | 30 - dimos/msgs/std_msgs/UInt32.py | 30 - dimos/msgs/trajectory_msgs/JointTrajectory.py | 211 ------ dimos/msgs/trajectory_msgs/TrajectoryPoint.py | 136 ---- .../msgs/trajectory_msgs/TrajectoryStatus.py | 170 ----- dimos/msgs/vision_msgs/BoundingBox2DArray.py | 21 - dimos/msgs/vision_msgs/BoundingBox3DArray.py | 21 - dimos/msgs/vision_msgs/Detection2D.py | 27 - dimos/msgs/vision_msgs/Detection3D.py | 31 - .../msgs/visualization_msgs/EntityMarkers.py | 145 ---- examples/language-interop/lua/.gitignore | 3 - examples/language-interop/lua/main.lua | 59 -- examples/language-interop/lua/setup.sh | 100 --- examples/language-interop/ts/deno.json | 9 - examples/language-interop/ts/deno.lock | 21 - examples/language-interop/ts/main.ts | 43 -- examples/language-interop/ts/web/index.html | 213 ------ examples/language-interop/ts/web/server.ts | 69 -- 53 files changed, 7245 deletions(-) delete mode 100644 dimos/msgs/foxglove_msgs/CompressedVideo.py delete mode 100644 dimos/msgs/geometry_msgs/Point.py delete mode 100644 dimos/msgs/geometry_msgs/PointStamped.py delete mode 100644 dimos/msgs/geometry_msgs/Pose.py delete mode 100644 dimos/msgs/geometry_msgs/PoseWithCovariance.py delete mode 100644 dimos/msgs/geometry_msgs/PoseWithCovarianceStamped.py delete mode 100644 dimos/msgs/geometry_msgs/Quaternion.py delete mode 100644 dimos/msgs/geometry_msgs/Transform.py delete mode 100644 dimos/msgs/geometry_msgs/Twist.py delete mode 100644 dimos/msgs/geometry_msgs/TwistStamped.py delete mode 100644 dimos/msgs/geometry_msgs/TwistWithCovariance.py delete mode 100644 dimos/msgs/geometry_msgs/TwistWithCovarianceStamped.py delete mode 100644 dimos/msgs/geometry_msgs/Vector3.py delete mode 100644 dimos/msgs/geometry_msgs/Wrench.py delete mode 100644 dimos/msgs/geometry_msgs/WrenchStamped.py delete mode 100644 dimos/msgs/manipulation_msgs/GraspCandidate.py delete mode 100644 dimos/msgs/manipulation_msgs/GraspCandidateArray.py delete mode 100644 dimos/msgs/nav_msgs/OccupancyGrid.py delete mode 100644 dimos/msgs/nav_msgs/Odometry.py delete mode 100644 dimos/msgs/nav_msgs/Path.py delete mode 100644 dimos/msgs/sensor_msgs/CompressedImage.py delete mode 100644 dimos/msgs/sensor_msgs/Image.py delete mode 100644 dimos/msgs/sensor_msgs/Imu.py delete mode 100644 dimos/msgs/sensor_msgs/ImuInfo.py delete mode 100644 dimos/msgs/sensor_msgs/JointCommand.py delete mode 100644 dimos/msgs/sensor_msgs/JointState.py delete mode 100644 dimos/msgs/sensor_msgs/Joy.py delete mode 100644 dimos/msgs/sensor_msgs/MotorCommandArray.py delete mode 100644 dimos/msgs/sensor_msgs/RobotState.py delete mode 100644 dimos/msgs/sensor_msgs/image_impls/AbstractImage.py delete mode 100644 dimos/msgs/std_msgs/Bool.py delete mode 100644 dimos/msgs/std_msgs/Float32.py delete mode 100644 dimos/msgs/std_msgs/Header.py delete mode 100644 dimos/msgs/std_msgs/Int32.py delete mode 100644 dimos/msgs/std_msgs/Int8.py delete mode 100644 dimos/msgs/std_msgs/String.py delete mode 100644 dimos/msgs/std_msgs/UInt32.py delete mode 100644 dimos/msgs/trajectory_msgs/JointTrajectory.py delete mode 100644 dimos/msgs/trajectory_msgs/TrajectoryPoint.py delete mode 100644 dimos/msgs/trajectory_msgs/TrajectoryStatus.py delete mode 100644 dimos/msgs/vision_msgs/BoundingBox2DArray.py delete mode 100644 dimos/msgs/vision_msgs/BoundingBox3DArray.py delete mode 100644 dimos/msgs/vision_msgs/Detection2D.py delete mode 100644 dimos/msgs/vision_msgs/Detection3D.py delete mode 100644 dimos/msgs/visualization_msgs/EntityMarkers.py delete mode 100644 examples/language-interop/lua/.gitignore delete mode 100644 examples/language-interop/lua/main.lua delete mode 100755 examples/language-interop/lua/setup.sh delete mode 100644 examples/language-interop/ts/deno.json delete mode 100644 examples/language-interop/ts/deno.lock delete mode 100644 examples/language-interop/ts/main.ts delete mode 100644 examples/language-interop/ts/web/index.html delete mode 100644 examples/language-interop/ts/web/server.ts diff --git a/dimos/msgs/foxglove_msgs/CompressedVideo.py b/dimos/msgs/foxglove_msgs/CompressedVideo.py deleted file mode 100644 index b13089c303b..00000000000 --- a/dimos/msgs/foxglove_msgs/CompressedVideo.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""foxglove_msgs::msg::CompressedVideo — one encoded video packet. - -Just the encoded bytes + codec name. Inter-frame codecs (h264) can't be decoded -one packet at a time — feed the ordered stream through -:class:`~dimos.robot.unitree.go2.dds.video.H264Decoder` to get ``Image`` frames, -or let the rerun bridge log it as a ``VideoStream`` and decode in-viewer. -""" - -from __future__ import annotations - -import time -from typing import TYPE_CHECKING - -from dimos_lcm.foxglove_msgs import CompressedVideo as LCMCompressedVideo -import numpy as np - -from dimos.types.timestamped import Timestamped - -if TYPE_CHECKING: - from dimos.visualization.rerun.bridge import RerunData - - -class CompressedVideo(Timestamped): - """One encoded video packet (Annex-B for h264).""" - - msg_name = "foxglove_msgs.CompressedVideo" - - def __init__( - self, - data: np.ndarray | bytes, - format: str = "h264", - frame_id: str = "", - ts: float | None = None, - ) -> None: - """Initialize a CompressedVideo. - - Args: - data: The encoded packet, u8 - format: Codec name, e.g. "h264" - frame_id: Frame ID - ts: Timestamp in seconds - """ - self.data = data if isinstance(data, np.ndarray) else np.frombuffer(data, dtype=np.uint8) - self.format = format - self.frame_id = frame_id - self.ts = ts if ts is not None else time.time() - - def lcm_encode(self) -> bytes: - msg = LCMCompressedVideo() - msg.timestamp.sec = int(self.ts) - msg.timestamp.nanosec = int((self.ts - int(self.ts)) * 1e9) - msg.frame_id = self.frame_id - msg.data = self.data.tobytes() - msg.data_length = len(msg.data) - msg.format = self.format - return msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes) -> CompressedVideo: - msg = LCMCompressedVideo.lcm_decode(data) - return cls( - data=bytes(msg.data), - format=msg.format, - frame_id=msg.frame_id, - ts=msg.timestamp.sec + msg.timestamp.nanosec * 1e-9, - ) - - def to_rerun(self) -> RerunData: - """Log the encoded packet as a rerun ``VideoStream`` sample (viewer decodes). - - rerun decodes the stream in-viewer, so this stays per-packet and cheap — - no server-side decode, and the .rrd holds the compressed bytes. Iterate - from the start (or a keyframe) so the first sample the viewer sees is one. - """ - import rerun as rr - - codecs = { - "h264": rr.VideoCodec.H264, - "h265": rr.VideoCodec.H265, - "av1": rr.VideoCodec.AV1, - "vp8": rr.VideoCodec.VP8, - "vp9": rr.VideoCodec.VP9, - } - codec = codecs.get(self.format.lower()) - if codec is None: - raise ValueError(f"no rerun VideoCodec for format {self.format!r}") - return rr.VideoStream(codec, sample=self.data.tobytes()) - - def __repr__(self) -> str: - return ( - f"CompressedVideo(format='{self.format}', bytes={self.data.size}, " - f"frame_id='{self.frame_id}', ts={self.ts})" - ) diff --git a/dimos/msgs/geometry_msgs/Point.py b/dimos/msgs/geometry_msgs/Point.py deleted file mode 100644 index 84f260dc8a4..00000000000 --- a/dimos/msgs/geometry_msgs/Point.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from dimos_lcm.geometry_msgs import Point as LCMPoint - - -class Point(LCMPoint): # type: ignore[misc] - """DimOS wrapper for geometry_msgs.Point (3D position). - - Inherits x/y/z from LCMPoint. Wire-identical to Vector3 but - semantically represents a position, not a direction/displacement. - """ - - msg_name = "geometry_msgs.Point" - - def __init__(self, x: float = 0.0, y: float = 0.0, z: float = 0.0) -> None: - super().__init__(float(x), float(y), float(z)) - - def __repr__(self) -> str: - return f"Point(x={self.x}, y={self.y}, z={self.z})" diff --git a/dimos/msgs/geometry_msgs/PointStamped.py b/dimos/msgs/geometry_msgs/PointStamped.py deleted file mode 100644 index 8d305d99493..00000000000 --- a/dimos/msgs/geometry_msgs/PointStamped.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import time -from typing import TYPE_CHECKING, BinaryIO - -if TYPE_CHECKING: - from rerun._baseclasses import Archetype - - from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped - -from dimos_lcm.geometry_msgs import PointStamped as LCMPointStamped - -from dimos.msgs.geometry_msgs.Point import Point -from dimos.types.timestamped import Timestamped - - -class PointStamped(Point, Timestamped): - """A 3D point with timestamp and frame_id. - - Follows the same pattern as PoseStamped(Pose, Timestamped) and - TwistStamped(Twist, Timestamped). Inherits x/y/z from Point - (which inherits from LCMPoint). - """ - - msg_name = "geometry_msgs.PointStamped" - ts: float - frame_id: str - - def __init__( - self, - x: float = 0.0, - y: float = 0.0, - z: float = 0.0, - ts: float | None = None, - frame_id: str = "", - ) -> None: - self.frame_id = frame_id - self.ts = time.time() if ts is None else ts - super().__init__(float(x), float(y), float(z)) - - # -- LCM encode / decode -- - - def lcm_encode(self) -> bytes: - """Encode to LCM binary format.""" - lcm_msg = LCMPointStamped() - lcm_msg.point = self # Works because Point inherits from LCMPoint - [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = self.ros_timestamp() - lcm_msg.header.frame_id = self.frame_id - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes | BinaryIO) -> PointStamped: - """Decode from LCM binary format.""" - lcm_msg = LCMPointStamped.lcm_decode(data) - return cls( - x=lcm_msg.point.x, - y=lcm_msg.point.y, - z=lcm_msg.point.z, - ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), - frame_id=lcm_msg.header.frame_id, - ) - - # -- Conversion methods -- - - def to_rerun(self) -> Archetype: - """Convert to rerun Points3D archetype for visualization.""" - import rerun as rr - - return rr.Points3D(positions=[[self.x, self.y, self.z]]) - - def to_pose_stamped(self) -> PoseStamped: - """Convert to PoseStamped with identity quaternion orientation.""" - from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped - - return PoseStamped( - ts=self.ts, - frame_id=self.frame_id, - position=[self.x, self.y, self.z], - orientation=[0.0, 0.0, 0.0, 1.0], - ) - - # -- String representations -- - - def __str__(self) -> str: - return f"PointStamped(point=[{self.x:.3f}, {self.y:.3f}, {self.z:.3f}], frame_id={self.frame_id!r})" - - def __repr__(self) -> str: - return f"PointStamped(x={self.x}, y={self.y}, z={self.z}, ts={self.ts}, frame_id={self.frame_id!r})" diff --git a/dimos/msgs/geometry_msgs/Pose.py b/dimos/msgs/geometry_msgs/Pose.py deleted file mode 100644 index 985a677c70f..00000000000 --- a/dimos/msgs/geometry_msgs/Pose.py +++ /dev/null @@ -1,265 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from typing import Any, TypeAlias, overload - -from dimos_lcm.geometry_msgs import ( - Pose as LCMPose, - Transform as LCMTransform, -) -from plum import dispatch - -from dimos.msgs.geometry_msgs.Quaternion import Quaternion, QuaternionConvertable -from dimos.msgs.geometry_msgs.Transform import Transform -from dimos.msgs.geometry_msgs.Vector3 import Vector3, VectorConvertable - -# Types that can be converted to/from Pose -PoseConvertable: TypeAlias = ( - tuple[VectorConvertable, QuaternionConvertable] - | LCMPose - | Vector3 - | dict[str, VectorConvertable | QuaternionConvertable] -) - - -def _is_position_orientation_pair(value: Any) -> bool: - """True for a 2-element (position, orientation) pair, false for a 2D position.""" - return ( - isinstance(value, tuple | list) - and len(value) == 2 - and not isinstance(value[0], int | float) - and not isinstance(value[1], int | float) - ) - - -class Pose(LCMPose): # type: ignore[misc] - position: Vector3 - orientation: Quaternion - msg_name = "geometry_msgs.Pose" - - @overload - def __init__(self) -> None: ... - - @overload - def __init__(self, x: int | float, y: int | float, z: int | float) -> None: ... - - @overload - def __init__( - self, - x: int | float, - y: int | float, - z: int | float, - qx: int | float, - qy: int | float, - qz: int | float, - qw: int | float, - ) -> None: ... - - @overload - def __init__( - self, - position: VectorConvertable | Vector3 | None = ..., - orientation: QuaternionConvertable | Quaternion | None = ..., - ) -> None: ... - - @overload - def __init__(self, value: PoseConvertable | Pose, /) -> None: ... - - def __init__(self, *args: Any, **kwargs: Any) -> None: - """Initialize a pose. - - Supported forms: - Pose() # origin, identity orientation - Pose(x, y, z) - Pose(x, y, z, qx, qy, qz, qw) - Pose(position) # any Vector3-convertable - Pose(position, orientation) - Pose(position=..., orientation=...) # keyword args - Pose((position, orientation)) # pair - Pose({"position": ..., "orientation": ...}) - Pose(other_pose) # copy constructor - Pose(lcm_pose) # from LCM message - """ - position: Any = None - orientation: Any = None - - if len(args) == 3: - position = args - elif len(args) == 7: - position, orientation = args[:3], args[3:] - elif len(args) == 2: - position, orientation = args - elif len(args) == 1: - value = args[0] - # Pose before LCMPose (it is a subclass); dict and pair before the - # generic "it is a position" fallback. - if isinstance(value, Pose): - position, orientation = value.position, value.orientation - elif isinstance(value, LCMPose): - position = (value.position.x, value.position.y, value.position.z) - orientation = ( - value.orientation.x, - value.orientation.y, - value.orientation.z, - value.orientation.w, - ) - elif isinstance(value, dict): - position, orientation = value["position"], value["orientation"] - elif _is_position_orientation_pair(value): - position, orientation = value - else: - position = value - elif args: - raise TypeError(f"Pose takes 1, 2, 3 or 7 positional arguments ({len(args)} given)") - - if kwargs: - position = kwargs.pop("position", position) - orientation = kwargs.pop("orientation", orientation) - if kwargs: - raise TypeError(f"Pose got unexpected keyword arguments {sorted(kwargs)}") - - self.position = Vector3(0.0, 0.0, 0.0) if position is None else Vector3(position) - self.orientation = ( - Quaternion(0.0, 0.0, 0.0, 1.0) if orientation is None else Quaternion(orientation) - ) - - @property - def x(self) -> float: - """X coordinate of position.""" - return self.position.x - - @property - def y(self) -> float: - """Y coordinate of position.""" - return self.position.y - - @property - def z(self) -> float: - """Z coordinate of position.""" - return self.position.z - - @property - def roll(self) -> float: - """Roll angle in radians.""" - return self.orientation.to_euler().roll - - @property - def pitch(self) -> float: - """Pitch angle in radians.""" - return self.orientation.to_euler().pitch - - @property - def yaw(self) -> float: - """Yaw angle in radians.""" - return self.orientation.to_euler().yaw - - def __repr__(self) -> str: - return f"Pose(position={self.position!r}, orientation={self.orientation!r})" - - def __str__(self) -> str: - return ( - f"Pose(pos=[{self.x:.3f}, {self.y:.3f}, {self.z:.3f}], " - f"euler=[{self.roll:.3f}, {self.pitch:.3f}, {self.yaw:.3f}]), " - f"quaternion=[{self.orientation}])" - ) - - def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] - """Check if two poses are equal.""" - if not isinstance(other, Pose): - return False - return self.position == other.position and self.orientation == other.orientation - - def __matmul__(self, transform: LCMTransform | Transform) -> Pose: - return self + transform - - def __add__(self, other: Pose | PoseConvertable | LCMTransform | Transform) -> Pose: - """Compose two poses or apply a transform (transform composition). - - The operation self + other represents applying transformation 'other' - in the coordinate frame defined by 'self'. This is equivalent to: - - First apply transformation 'self' (from world to self's frame) - - Then apply transformation 'other' (from self's frame to other's frame) - - This matches ROS tf convention where: - T_world_to_other = T_world_to_self * T_self_to_other - - Args: - other: The pose or transform to compose with this one - - Returns: - A new Pose representing the composed transformation - - Example: - robot_pose = Pose(1, 0, 0) # Robot at (1,0,0) facing forward - object_in_robot = Pose(2, 0, 0) # Object 2m in front of robot - object_in_world = robot_pose + object_in_robot # Object at (3,0,0) in world - - # Or with a Transform: - transform = Transform() - transform.translation = Vector3(2, 0, 0) - transform.rotation = Quaternion(0, 0, 0, 1) - new_pose = pose + transform - """ - # Handle Transform objects - if isinstance(other, LCMTransform | Transform): - # Convert Transform to Pose using its translation and rotation - other_position = Vector3(other.translation) - other_orientation = Quaternion(other.rotation) - elif isinstance(other, Pose): - other_position = other.position - other_orientation = other.orientation - else: - # Convert to Pose if it's a convertible type - other_pose = Pose(other) - other_position = other_pose.position - other_orientation = other_pose.orientation - - # Compose orientations: self.orientation * other.orientation - new_orientation = self.orientation * other_orientation - - # Transform other's position by self's orientation, then add to self's position - rotated_position = self.orientation.rotate_vector(other_position) - new_position = self.position + rotated_position - - return Pose(new_position, new_orientation) - - def __sub__(self, other: Pose) -> Pose: - """Compute the delta pose: self - other. - - For position: simple subtraction. - For orientation: delta_quat = self.orientation * inverse(other.orientation) - - Returns: - A new Pose representing the delta transformation - """ - delta_position = self.position - other.position - delta_orientation = self.orientation * other.orientation.inverse() - return Pose(delta_position, delta_orientation) - - -@dispatch -def to_pose(value: Pose) -> Pose: - """Pass through Pose objects.""" - return value - - -@dispatch # type: ignore[no-redef] -def to_pose(value: PoseConvertable) -> Pose: - """Convert a pose-compatible value to a Pose object.""" - return Pose(value) - - -PoseLike: TypeAlias = PoseConvertable | Pose diff --git a/dimos/msgs/geometry_msgs/PoseWithCovariance.py b/dimos/msgs/geometry_msgs/PoseWithCovariance.py deleted file mode 100644 index f26a987bee1..00000000000 --- a/dimos/msgs/geometry_msgs/PoseWithCovariance.py +++ /dev/null @@ -1,201 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, TypeAlias - -from dimos_lcm.geometry_msgs import ( - PoseWithCovariance as LCMPoseWithCovariance, -) -import numpy as np - -from dimos.msgs.geometry_msgs.Pose import Pose, PoseConvertable - -if TYPE_CHECKING: - from dimos.msgs.geometry_msgs.Quaternion import Quaternion - from dimos.msgs.geometry_msgs.Vector3 import Vector3 - -# Types that can be converted to/from PoseWithCovariance -PoseWithCovarianceConvertable: TypeAlias = ( - tuple[PoseConvertable, list[float] | np.ndarray] - | LCMPoseWithCovariance - | dict[str, PoseConvertable | list[float] | np.ndarray] -) - -COVARIANCE_SIZE = 36 - - -def _is_value_covariance_pair(value: Any) -> bool: - """True for a 2-element (value, covariance) pair, where covariance is 36 long.""" - if not isinstance(value, tuple | list) or len(value) != 2: - return False - covariance = value[1] - return isinstance(covariance, list | np.ndarray) and np.size(covariance) == COVARIANCE_SIZE - - -class PoseWithCovariance(LCMPoseWithCovariance): # type: ignore[misc] - pose: Pose - covariance: np.ndarray[tuple[int], np.dtype[np.floating[Any]]] - msg_name = "geometry_msgs.PoseWithCovariance" - - def __init__( - self, - pose: Pose | PoseConvertable | PoseWithCovarianceConvertable | None = None, - covariance: list[float] | np.ndarray | None = None, - ) -> None: - """Initialize a pose with covariance. - - Supported forms: - PoseWithCovariance() # origin, zero covariance - PoseWithCovariance(pose) - PoseWithCovariance(pose, covariance) - PoseWithCovariance(pose=..., covariance=...) - PoseWithCovariance((pose, covariance)) # pair - PoseWithCovariance({"pose": ..., "covariance": ...}) - PoseWithCovariance(other) # copy constructor - PoseWithCovariance(lcm_pose_with_cov) # from LCM message - """ - source: Any = pose - cov: Any = covariance - - # PoseWithCovariance before LCMPoseWithCovariance (it is a subclass). - if isinstance(source, PoseWithCovariance): - if cov is None: - cov = np.array(source.covariance).copy() - source = Pose(source.pose) # copy constructor: don't alias the source pose - elif isinstance(source, LCMPoseWithCovariance): - if cov is None: - cov = np.array(source.covariance) - source = source.pose - elif isinstance(source, dict) and "pose" in source: - cov = source.get("covariance", cov) - source = source["pose"] - elif _is_value_covariance_pair(source): - source, cov = source - - self.pose = source if isinstance(source, Pose) else Pose(source) - self.covariance = ( - np.zeros(COVARIANCE_SIZE) - if cov is None - else np.array(cov, dtype=float).reshape(COVARIANCE_SIZE) - ) - - def __getattribute__(self, name: str): # type: ignore[no-untyped-def] - """Override to ensure covariance is always returned as numpy array.""" - if name == "covariance": - cov = object.__getattribute__(self, "covariance") - if not isinstance(cov, np.ndarray): - return np.array(cov, dtype=float) - return cov - return super().__getattribute__(name) - - def __setattr__(self, name: str, value) -> None: # type: ignore[no-untyped-def] - """Override to ensure covariance is stored as numpy array.""" - if name == "covariance": - if not isinstance(value, np.ndarray): - value = np.array(value, dtype=float).reshape(36) - super().__setattr__(name, value) - - @property - def x(self) -> float: - """X coordinate of position.""" - return self.pose.x - - @property - def y(self) -> float: - """Y coordinate of position.""" - return self.pose.y - - @property - def z(self) -> float: - """Z coordinate of position.""" - return self.pose.z - - @property - def position(self) -> Vector3: - """Position vector.""" - return self.pose.position - - @property - def orientation(self) -> Quaternion: - """Orientation quaternion.""" - return self.pose.orientation - - @property - def roll(self) -> float: - """Roll angle in radians.""" - return self.pose.roll - - @property - def pitch(self) -> float: - """Pitch angle in radians.""" - return self.pose.pitch - - @property - def yaw(self) -> float: - """Yaw angle in radians.""" - return self.pose.yaw - - @property - def covariance_matrix(self) -> np.ndarray: - """Get covariance as 6x6 matrix.""" - return self.covariance.reshape(6, 6) - - @covariance_matrix.setter - def covariance_matrix(self, value: np.ndarray) -> None: - """Set covariance from 6x6 matrix.""" - self.covariance = np.array(value).reshape(36) - - def __repr__(self) -> str: - return f"PoseWithCovariance(pose={self.pose!r}, covariance=<{self.covariance.shape[0] if isinstance(self.covariance, np.ndarray) else len(self.covariance)} elements>)" - - def __str__(self) -> str: - return ( - f"PoseWithCovariance(pos=[{self.x:.3f}, {self.y:.3f}, {self.z:.3f}], " - f"euler=[{self.roll:.3f}, {self.pitch:.3f}, {self.yaw:.3f}], " - f"cov_trace={np.trace(self.covariance_matrix):.3f})" - ) - - def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] - """Check if two PoseWithCovariance are equal.""" - if not isinstance(other, PoseWithCovariance): - return False - return self.pose == other.pose and np.allclose(self.covariance, other.covariance) - - def lcm_encode(self) -> bytes: - """Encode to LCM binary format.""" - lcm_msg = LCMPoseWithCovariance() - lcm_msg.pose = self.pose - # LCM expects list, not numpy array - if isinstance(self.covariance, np.ndarray): - lcm_msg.covariance = self.covariance.tolist() - else: - lcm_msg.covariance = list(self.covariance) - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes) -> PoseWithCovariance: - """Decode from LCM binary format.""" - lcm_msg = LCMPoseWithCovariance.lcm_decode(data) - pose = Pose( - position=[lcm_msg.pose.position.x, lcm_msg.pose.position.y, lcm_msg.pose.position.z], - orientation=[ - lcm_msg.pose.orientation.x, - lcm_msg.pose.orientation.y, - lcm_msg.pose.orientation.z, - lcm_msg.pose.orientation.w, - ], - ) - return cls(pose, lcm_msg.covariance) diff --git a/dimos/msgs/geometry_msgs/PoseWithCovarianceStamped.py b/dimos/msgs/geometry_msgs/PoseWithCovarianceStamped.py deleted file mode 100644 index 17f3f2b6d41..00000000000 --- a/dimos/msgs/geometry_msgs/PoseWithCovarianceStamped.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import time -from typing import TypeAlias - -from dimos_lcm.geometry_msgs import ( - PoseWithCovarianceStamped as LCMPoseWithCovarianceStamped, -) -import numpy as np - -from dimos.msgs.geometry_msgs.Pose import Pose, PoseConvertable -from dimos.msgs.geometry_msgs.PoseWithCovariance import PoseWithCovariance -from dimos.types.timestamped import Timestamped - -# Types that can be converted to/from PoseWithCovarianceStamped -PoseWithCovarianceStampedConvertable: TypeAlias = ( - tuple[PoseConvertable, list[float] | np.ndarray] - | LCMPoseWithCovarianceStamped - | dict[str, PoseConvertable | list[float] | np.ndarray | float | str] -) - - -def sec_nsec(ts): # type: ignore[no-untyped-def] - s = int(ts) - return [s, int((ts - s) * 1_000_000_000)] - - -class PoseWithCovarianceStamped(PoseWithCovariance, Timestamped): - msg_name = "geometry_msgs.PoseWithCovarianceStamped" - ts: float - frame_id: str - - def __init__( - self, - ts: float | None = None, - frame_id: str = "", - pose: Pose | PoseConvertable | None = None, - covariance: list[float] | np.ndarray | None = None, - ) -> None: - """Initialize with timestamp, frame_id, pose and covariance.""" - self.frame_id = frame_id - self.ts = time.time() if ts is None else ts - super().__init__(pose, covariance) - - def lcm_encode(self) -> bytes: - lcm_msg = LCMPoseWithCovarianceStamped() - lcm_msg.pose.pose = self.pose - # LCM expects list, not numpy array - if isinstance(self.covariance, np.ndarray): - lcm_msg.pose.covariance = self.covariance.tolist() - else: - lcm_msg.pose.covariance = list(self.covariance) - [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] - lcm_msg.header.frame_id = self.frame_id - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes) -> PoseWithCovarianceStamped: - lcm_msg = LCMPoseWithCovarianceStamped.lcm_decode(data) - return cls( - ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), - frame_id=lcm_msg.header.frame_id, - pose=Pose( - position=[ - lcm_msg.pose.pose.position.x, - lcm_msg.pose.pose.position.y, - lcm_msg.pose.pose.position.z, - ], - orientation=[ - lcm_msg.pose.pose.orientation.x, - lcm_msg.pose.pose.orientation.y, - lcm_msg.pose.pose.orientation.z, - lcm_msg.pose.pose.orientation.w, - ], - ), - covariance=lcm_msg.pose.covariance, - ) - - def __str__(self) -> str: - return ( - f"PoseWithCovarianceStamped(pos=[{self.x:.3f}, {self.y:.3f}, {self.z:.3f}], " - f"euler=[{self.roll:.3f}, {self.pitch:.3f}, {self.yaw:.3f}], " - f"cov_trace={np.trace(self.covariance_matrix):.3f})" - ) diff --git a/dimos/msgs/geometry_msgs/Quaternion.py b/dimos/msgs/geometry_msgs/Quaternion.py deleted file mode 100644 index e782bc71142..00000000000 --- a/dimos/msgs/geometry_msgs/Quaternion.py +++ /dev/null @@ -1,325 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from collections.abc import Sequence -from io import BytesIO -import math -import struct -from typing import TYPE_CHECKING, Any, BinaryIO, TypeAlias, overload - -if TYPE_CHECKING: - import rerun as rr - -from dimos_lcm.geometry_msgs import Quaternion as LCMQuaternion -import numpy as np - -from dimos.msgs.geometry_msgs.Vector3 import Vector3 - -# Types that can be converted to/from Quaternion -QuaternionConvertable: TypeAlias = Sequence[int | float] | LCMQuaternion | np.ndarray - - -def _four_components(value: Any) -> tuple[float, float, float, float]: - """Unpack a length-4 sequence or array into (x, y, z, w).""" - if not isinstance(value, np.ndarray | Sequence): - raise TypeError(f"Cannot initialize Quaternion from {type(value)}") - size = value.size if isinstance(value, np.ndarray) else len(value) - if size != 4: - raise ValueError("Quaternion requires exactly 4 components [x, y, z, w]") - return (float(value[0]), float(value[1]), float(value[2]), float(value[3])) - - -class Quaternion(LCMQuaternion): # type: ignore[misc] - x: float = 0.0 - y: float = 0.0 - z: float = 0.0 - w: float = 1.0 - msg_name = "geometry_msgs.Quaternion" - - @classmethod - def lcm_decode(cls, data: bytes | BinaryIO): # type: ignore[no-untyped-def] - if not hasattr(data, "read"): - data = BytesIO(data) - if data.read(8) != cls._get_packed_fingerprint(): - raise ValueError("Decode error") - return cls._lcm_decode_one(data) # type: ignore[no-untyped-call] - - @classmethod - def _lcm_decode_one(cls, buf): # type: ignore[no-untyped-def] - return cls(struct.unpack(">dddd", buf.read(32))) - - @overload - def __init__(self) -> None: ... - - @overload - def __init__( - self, - x: int | float = ..., - y: int | float = ..., - z: int | float = ..., - w: int | float = ..., - ) -> None: ... - - @overload - def __init__(self, value: QuaternionConvertable | Quaternion, /) -> None: ... - - def __init__(self, *args: Any, **kwargs: Any) -> None: - """Initialize a quaternion. - - Supported forms: - Quaternion() # identity (0, 0, 0, 1) - Quaternion(x, y, z, w) - Quaternion(x=1, y=2, z=3, w=4) # keyword args - Quaternion([x, y, z, w]) # sequence - Quaternion(np.array([x, y, z, w])) # numpy array - Quaternion(other_quaternion) # copy constructor - Quaternion(lcm_quaternion) # from LCM message - """ - if len(args) == 4: - self.x = float(args[0]) - self.y = float(args[1]) - self.z = float(args[2]) - self.w = float(args[3]) - elif len(args) == 1: - value = args[0] - # Quaternion before LCMQuaternion (it is a subclass) and before the - # generic sequence branch (a Quaternion is indexable). - if isinstance(value, Quaternion): - self.x, self.y, self.z, self.w = value.x, value.y, value.z, value.w - elif isinstance(value, LCMQuaternion): - self.x, self.y, self.z, self.w = value.x, value.y, value.z, value.w - else: - self.x, self.y, self.z, self.w = _four_components(value) - elif args: - raise TypeError( - f"Quaternion takes 1 sequence or 4 components ({len(args)} positional given)" - ) - elif kwargs: - self.x = float(kwargs.pop("x", 0.0)) - self.y = float(kwargs.pop("y", 0.0)) - self.z = float(kwargs.pop("z", 0.0)) - self.w = float(kwargs.pop("w", 1.0)) - # else: no arguments — the class defaults already spell the identity. - - if kwargs: - raise TypeError(f"Quaternion got unexpected keyword arguments {sorted(kwargs)}") - - def to_tuple(self) -> tuple[float, float, float, float]: - """Tuple representation of the quaternion (x, y, z, w).""" - return (self.x, self.y, self.z, self.w) - - def to_list(self) -> list[float]: - """List representation of the quaternion (x, y, z, w).""" - return [self.x, self.y, self.z, self.w] - - def to_numpy(self) -> np.ndarray: - """Numpy array representation of the quaternion (x, y, z, w).""" - return np.array([self.x, self.y, self.z, self.w]) - - @property - def euler(self) -> Vector3: - return self.to_euler() - - @property - def radians(self) -> Vector3: - return self.to_euler() - - def to_radians(self) -> Vector3: - """Radians representation of the quaternion (x, y, z, w).""" - return self.to_euler() - - def to_rerun(self) -> rr.Quaternion: - import rerun as rr - - return rr.Quaternion(xyzw=[self.x, self.y, self.z, self.w]) - - @classmethod - def from_euler(cls, vector: Vector3) -> Quaternion: - """Convert Euler angles (roll, pitch, yaw) in radians to quaternion. - - Args: - vector: Vector3 containing (roll, pitch, yaw) in radians - - Returns: - Quaternion representation - """ - - # Calculate quaternion components - cy = np.cos(vector.yaw * 0.5) - sy = np.sin(vector.yaw * 0.5) - cp = np.cos(vector.pitch * 0.5) - sp = np.sin(vector.pitch * 0.5) - cr = np.cos(vector.roll * 0.5) - sr = np.sin(vector.roll * 0.5) - - w = cr * cp * cy + sr * sp * sy - x = sr * cp * cy - cr * sp * sy - y = cr * sp * cy + sr * cp * sy - z = cr * cp * sy - sr * sp * cy - - return cls(x, y, z, w) - - @classmethod - def from_rotation_matrix(cls, matrix: np.ndarray) -> Quaternion: - """Convert a 3x3 rotation matrix to quaternion. - - Args: - matrix: 3x3 rotation matrix (numpy array) - - Returns: - Quaternion representation - """ - from scipy.spatial.transform import ( - Rotation, # ~330ms: deferred to avoid startup cost - ) - - rotation = Rotation.from_matrix(matrix) - quat = rotation.as_quat() # Returns [x, y, z, w] - return cls(quat[0], quat[1], quat[2], quat[3]) - - def to_rotation_matrix(self) -> np.ndarray: - """Convert quaternion to a 3x3 rotation matrix.""" - from scipy.spatial.transform import ( - Rotation, # ~330ms: deferred to avoid startup cost - ) - - return np.asarray(Rotation.from_quat([self.x, self.y, self.z, self.w]).as_matrix()) - - def to_euler(self) -> Vector3: - """Convert quaternion to Euler angles (roll, pitch, yaw) in radians. - - Returns: - Vector3: Euler angles as (roll, pitch, yaw) in radians - """ - # Use scipy for accurate quaternion to euler conversion - from scipy.spatial.transform import ( - Rotation, # ~330ms: deferred to avoid startup cost - ) - - quat = [self.x, self.y, self.z, self.w] - rotation = Rotation.from_quat(quat) - euler_angles = rotation.as_euler("xyz") # roll, pitch, yaw - - return Vector3(euler_angles[0], euler_angles[1], euler_angles[2]) - - def __getitem__(self, idx: int) -> float: - """Allow indexing into quaternion components: 0=x, 1=y, 2=z, 3=w.""" - if idx == 0: - return self.x - elif idx == 1: - return self.y - elif idx == 2: - return self.z - elif idx == 3: - return self.w - else: - raise IndexError(f"Quaternion index {idx} out of range [0-3]") - - def __repr__(self) -> str: - return f"Quaternion({self.x:.6f}, {self.y:.6f}, {self.z:.6f}, {self.w:.6f})" - - def __str__(self) -> str: - return self.__repr__() - - def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] - if not isinstance(other, Quaternion): - return False - return self.x == other.x and self.y == other.y and self.z == other.z and self.w == other.w - - def is_zero(self) -> bool: - """All components are zero — i.e. an uninitialized placeholder, not a valid rotation.""" - return self.x == 0.0 and self.y == 0.0 and self.z == 0.0 and self.w == 0.0 - - def __mul__(self, other: Quaternion) -> Quaternion: - """Multiply two quaternions (Hamilton product). - - The result represents the composition of rotations: - q1 * q2 represents rotating by q2 first, then by q1. - """ - if not isinstance(other, Quaternion): - raise TypeError(f"Cannot multiply Quaternion with {type(other)}") - - # Hamilton product formula - w = self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z - x = self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y - y = self.w * other.y - self.x * other.z + self.y * other.w + self.z * other.x - z = self.w * other.z + self.x * other.y - self.y * other.x + self.z * other.w - - return Quaternion(x, y, z, w) - - def dot(self, other: Quaternion) -> float: - return float(self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w) - - def angle_to(self, other: Quaternion) -> float: - """Smallest rotation angle (radians) between two unit quaternions. - - ``abs(self.dot(other))`` collapses the double-cover sign ambiguity; - the ``min(1.0, ...)`` clamps against numerical drift past 1. - """ - return 2.0 * math.acos(min(1.0, abs(self.dot(other)))) - - def conjugate(self) -> Quaternion: - """Return the conjugate of the quaternion. - - For unit quaternions, the conjugate represents the inverse rotation. - """ - return Quaternion(-self.x, -self.y, -self.z, self.w) - - def inverse(self) -> Quaternion: - """Return the inverse of the quaternion. - - For unit quaternions, this is equivalent to the conjugate. - For non-unit quaternions, this is conjugate / norm^2. - """ - norm_sq = self.x**2 + self.y**2 + self.z**2 + self.w**2 - if norm_sq == 0: - raise ZeroDivisionError("Cannot invert zero quaternion") - - # For unit quaternions (norm_sq ≈ 1), this simplifies to conjugate - if np.isclose(norm_sq, 1.0): - return self.conjugate() - - # For non-unit quaternions - conj = self.conjugate() - return Quaternion(conj.x / norm_sq, conj.y / norm_sq, conj.z / norm_sq, conj.w / norm_sq) - - def normalize(self) -> Quaternion: - """Return a normalized (unit) quaternion.""" - norm = np.sqrt(self.x**2 + self.y**2 + self.z**2 + self.w**2) - if norm == 0: - raise ZeroDivisionError("Cannot normalize zero quaternion") - return Quaternion(self.x / norm, self.y / norm, self.z / norm, self.w / norm) - - def rotate_vector(self, vector: Vector3) -> Vector3: - """Rotate a 3D vector by this quaternion. - - Args: - vector: The vector to rotate - - Returns: - The rotated vector - """ - # For unit quaternions, conjugate equals inverse, so we use conjugate for efficiency - # The rotation formula is: q * v * q^* where q^* is the conjugate - - # Convert vector to pure quaternion (w=0) - v_quat = Quaternion(vector.x, vector.y, vector.z, 0) - - # Apply rotation: q * v * q^* (conjugate for unit quaternions) - rotated = self * v_quat * self.conjugate() - - # Extract vector components - return Vector3(rotated.x, rotated.y, rotated.z) diff --git a/dimos/msgs/geometry_msgs/Transform.py b/dimos/msgs/geometry_msgs/Transform.py deleted file mode 100644 index 6499905da1a..00000000000 --- a/dimos/msgs/geometry_msgs/Transform.py +++ /dev/null @@ -1,329 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import time -from typing import TYPE_CHECKING, Any, BinaryIO - -if TYPE_CHECKING: - import numpy as np - import rerun as rr - - from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped - -from dimos_lcm.geometry_msgs import ( - Transform as LCMTransform, - TransformStamped as LCMTransformStamped, -) - -from dimos.msgs.geometry_msgs.Quaternion import Quaternion -from dimos.msgs.geometry_msgs.Vector3 import Vector3 -from dimos.msgs.std_msgs.Header import Header -from dimos.types.timestamped import Timestamped - - -class Transform(Timestamped): - translation: Vector3 - rotation: Quaternion - ts: float - frame_id: str - child_frame_id: str - msg_name = "tf2_msgs.TFMessage" - - def __init__( # type: ignore[no-untyped-def] - self, - translation: Vector3 | None = None, - rotation: Quaternion | None = None, - frame_id: str = "world", - child_frame_id: str = "unset", - ts: float | None = None, - **kwargs, - ) -> None: - self.frame_id = frame_id - self.child_frame_id = child_frame_id - self.ts = time.time() if ts is None else ts - self.translation = translation if translation is not None else Vector3() - self.rotation = rotation if rotation is not None else Quaternion() - - def now(self) -> Transform: - """Return a copy of this Transform with the current timestamp.""" - return Transform( - translation=self.translation, - rotation=self.rotation, - frame_id=self.frame_id, - child_frame_id=self.child_frame_id, - ts=time.time(), - ) - - def __repr__(self) -> str: - return f"Transform(translation={self.translation!r}, rotation={self.rotation!r})" - - def __str__(self) -> str: - return f"{self.frame_id} -> {self.child_frame_id}\n Translation: {self.translation}\n Rotation: {self.rotation}" - - def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] - """Check if two transforms are equal.""" - if not isinstance(other, Transform): - return False - return self.translation == other.translation and self.rotation == other.rotation - - @classmethod - def identity(cls) -> Transform: - """Create an identity transform.""" - return cls() - - def lcm_transform(self) -> LCMTransformStamped: - return LCMTransformStamped( - child_frame_id=self.child_frame_id, - header=Header(self.ts, self.frame_id), - transform=LCMTransform( - translation=self.translation, - rotation=self.rotation, - ), - ) - - def apply(self, other: Transform) -> Transform: - return self.__add__(other) - - def __add__(self, other: Transform) -> Transform: - """Compose two transforms (transform composition). - - The operation self + other represents applying transformation 'other' - in the coordinate frame defined by 'self'. This is equivalent to: - - First apply transformation 'self' (from frame A to frame B) - - Then apply transformation 'other' (from frame B to frame C) - - Args: - other: The transform to compose with this one - - Returns: - A new Transform representing the composed transformation - - Example: - t1 = Transform(Vector3(1, 0, 0), Quaternion(0, 0, 0, 1)) - t2 = Transform(Vector3(2, 0, 0), Quaternion(0, 0, 0, 1)) - t3 = t1 + t2 # Combined transform: translation (3, 0, 0) - """ - if not isinstance(other, Transform): - raise TypeError(f"Cannot add Transform and {type(other).__name__}") - - # Compose orientations: self.rotation * other.rotation - new_rotation = self.rotation * other.rotation - - # Transform other's translation by self's rotation, then add to self's translation - rotated_translation = self.rotation.rotate_vector(other.translation) - new_translation = self.translation + rotated_translation - - return Transform( - translation=new_translation, - rotation=new_rotation, - frame_id=self.frame_id, - child_frame_id=other.child_frame_id, - ts=self.ts, - ) - - def inverse(self) -> Transform: - """Compute the inverse transform. - - The inverse transform reverses the direction of the transformation. - If this transform goes from frame A to frame B, the inverse goes from B to A. - - Returns: - A new Transform representing the inverse transformation - """ - # Inverse rotation - inv_rotation = self.rotation.inverse() - - # Inverse translation: -R^(-1) * t - inv_translation = inv_rotation.rotate_vector(self.translation) - inv_translation = Vector3(-inv_translation.x, -inv_translation.y, -inv_translation.z) - - return Transform( - translation=inv_translation, - rotation=inv_rotation, - frame_id=self.child_frame_id, # Swap frame references - child_frame_id=self.frame_id, - ts=self.ts, - ) - - def __neg__(self) -> Transform: - """Unary minus operator returns the inverse transform.""" - return self.inverse() - - @classmethod - def from_pose(cls, frame_id: str, pose: Pose | PoseStamped) -> Transform: # type: ignore[name-defined] - """Create a Transform from a Pose or PoseStamped. - - Args: - pose: A Pose or PoseStamped object to convert - - Returns: - A Transform with the same translation and rotation as the pose - """ - # Import locally to avoid circular imports - from dimos.msgs.geometry_msgs.Pose import Pose - from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped - - # Handle both Pose and PoseStamped - if isinstance(pose, PoseStamped): - return cls( - translation=pose.position, - rotation=pose.orientation, - frame_id=pose.frame_id, - child_frame_id=frame_id, - ts=pose.ts, - ) - elif isinstance(pose, Pose): - return cls( - translation=pose.position, - rotation=pose.orientation, - child_frame_id=frame_id, - ) - else: - raise TypeError(f"Expected Pose or PoseStamped, got {type(pose).__name__}") - - def to_pose(self, **kwargs: Any) -> PoseStamped: - """Create a Transform from a Pose or PoseStamped. - - Args: - pose: A Pose or PoseStamped object to convert - - Returns: - A Transform with the same translation and rotation as the pose - """ - # Import locally to avoid circular imports - from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped as _PoseStamped - - # Handle both Pose and PoseStamped - fields: dict[str, Any] = { - "position": self.translation, - "orientation": self.rotation, - "frame_id": self.frame_id, - } - result: PoseStamped = _PoseStamped(**fields, **kwargs) - return result - - @classmethod - def from_matrix( - cls, - matrix: np.ndarray, - *, - ts: float | None = None, - frame_id: str = "world", - child_frame_id: str = "unset", - ) -> Transform: - """Build a Transform from a 4x4 homogeneous transformation matrix.""" - return cls( - translation=Vector3(matrix[:3, 3]), - rotation=Quaternion.from_rotation_matrix(matrix[:3, :3]), - frame_id=frame_id, - child_frame_id=child_frame_id, - ts=ts, - ) - - def to_matrix(self) -> np.ndarray: # type: ignore[name-defined] - """Convert Transform to a 4x4 transformation matrix. - - Returns a homogeneous transformation matrix that represents both - the rotation and translation of this transform. - - Returns: - np.ndarray: A 4x4 homogeneous transformation matrix - """ - import numpy as np - - # Extract quaternion components - x, y, z, w = self.rotation.x, self.rotation.y, self.rotation.z, self.rotation.w - - # Build rotation matrix from quaternion using standard formula - # This avoids numerical issues compared to converting to axis-angle first - rotation_matrix = np.array( - [ - [1 - 2 * (y * y + z * z), 2 * (x * y - z * w), 2 * (x * z + y * w)], - [2 * (x * y + z * w), 1 - 2 * (x * x + z * z), 2 * (y * z - x * w)], - [2 * (x * z - y * w), 2 * (y * z + x * w), 1 - 2 * (x * x + y * y)], - ] - ) - - # Build 4x4 homogeneous transformation matrix - matrix = np.eye(4) - matrix[:3, :3] = rotation_matrix - matrix[:3, 3] = [self.translation.x, self.translation.y, self.translation.z] - - return matrix - - def lcm_encode(self) -> bytes: - # we get a circular import otherwise - from dimos.msgs.tf2_msgs.TFMessage import TFMessage - - return TFMessage(self).lcm_encode() - - @classmethod - def lcm_decode(cls, data: bytes | BinaryIO) -> Transform: - """Decode from LCM TFMessage bytes.""" - from dimos_lcm.tf2_msgs import TFMessage as LCMTFMessage - - lcm_msg = LCMTFMessage.lcm_decode(data) - - if not lcm_msg.transforms: - raise ValueError("No transforms found in LCM message") - - # Get the first transform from the message - lcm_transform_stamped = lcm_msg.transforms[0] - - # Extract timestamp from header - ts = lcm_transform_stamped.header.stamp.sec + ( - lcm_transform_stamped.header.stamp.nsec / 1_000_000_000 - ) - - # Create and return Transform instance - return cls( - translation=Vector3( - lcm_transform_stamped.transform.translation.x, - lcm_transform_stamped.transform.translation.y, - lcm_transform_stamped.transform.translation.z, - ), - rotation=Quaternion( - lcm_transform_stamped.transform.rotation.x, - lcm_transform_stamped.transform.rotation.y, - lcm_transform_stamped.transform.rotation.z, - lcm_transform_stamped.transform.rotation.w, - ), - frame_id=lcm_transform_stamped.header.frame_id, - child_frame_id=lcm_transform_stamped.child_frame_id, - ts=ts, - ) - - def to_rerun(self, frameless: bool = False) -> rr.Transform3D: - """Convert to a rerun Transform3D. - - Args: - frameless: omit ``parent_frame``/``child_frame``. By default the - transform carries its frame IDs (resolved via rerun's tf-graph); - set this when positioning by entity-path hierarchy instead, where - the named frames would not compose. - """ - import rerun as rr - - translation = [self.translation.x, self.translation.y, self.translation.z] - rotation = self.rotation.to_rerun() - if frameless: - return rr.Transform3D(translation=translation, rotation=rotation) - return rr.Transform3D( - translation=translation, - rotation=rotation, - parent_frame="tf#/" + self.frame_id, - child_frame="tf#/" + self.child_frame_id, - ) diff --git a/dimos/msgs/geometry_msgs/Twist.py b/dimos/msgs/geometry_msgs/Twist.py deleted file mode 100644 index d08f61211f0..00000000000 --- a/dimos/msgs/geometry_msgs/Twist.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from typing import Any, overload - -from dimos_lcm.geometry_msgs import Twist as LCMTwist - -from dimos.msgs.geometry_msgs.Quaternion import Quaternion -from dimos.msgs.geometry_msgs.Vector3 import Vector3, VectorLike - - -class Twist(LCMTwist): # type: ignore[misc] - linear: Vector3 - angular: Vector3 - msg_name = "geometry_msgs.Twist" - - @overload - def __init__(self) -> None: ... - - @overload - def __init__( - self, - linear: VectorLike | None = ..., - angular: VectorLike | Quaternion | None = ..., - ) -> None: ... - - @overload - def __init__(self, twist: Twist | LCMTwist, /) -> None: ... - - def __init__(self, *args: Any, **kwargs: Any) -> None: - """Initialize a twist. - - Supported forms: - Twist() # zero twist - Twist(linear, angular) - Twist(linear=..., angular=...) # keyword args, either optional - Twist(linear, quaternion) # angular converted to euler - Twist(other_twist) # copy constructor - Twist(lcm_twist) # from LCM message - """ - linear: Any = None - angular: Any = None - - if len(args) == 2: - linear, angular = args - elif len(args) == 1: - value = args[0] - # Twist before LCMTwist (it is a subclass); anything else is a - # linear velocity, same as the `linear=` keyword. - if isinstance(value, Twist | LCMTwist): - linear, angular = value.linear, value.angular - else: - linear = value - elif args: - raise TypeError(f"Twist takes 1 or 2 positional arguments ({len(args)} given)") - - if kwargs: - linear = kwargs.pop("linear", linear) - angular = kwargs.pop("angular", angular) - if kwargs: - raise TypeError(f"Twist got unexpected keyword arguments {sorted(kwargs)}") - - self.linear = Vector3() if linear is None else Vector3(linear) - if angular is None: - self.angular = Vector3() - elif isinstance(angular, Quaternion): - self.angular = angular.to_euler() - else: - self.angular = Vector3(angular) - - def __repr__(self) -> str: - return f"Twist(linear={self.linear!r}, angular={self.angular!r})" - - def __str__(self) -> str: - return f"Twist:\n Linear: {self.linear}\n Angular: {self.angular}" - - def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] - """Check if two twists are equal.""" - if not isinstance(other, Twist): - return False - return self.linear == other.linear and self.angular == other.angular - - @classmethod - def zero(cls) -> Twist: - """Create a zero twist (no motion).""" - return cls() - - def is_zero(self) -> bool: - """Check if this is a zero twist (no linear or angular velocity).""" - return self.linear.is_zero() and self.angular.is_zero() - - def __sub__(self, other: Twist) -> Twist: - """Component-wise subtraction: self - other.""" - if not isinstance(other, Twist): - return NotImplemented - return Twist( - linear=self.linear - other.linear, - angular=self.angular - other.angular, - ) - - def __add__(self, other: Twist) -> Twist: - """Component-wise addition: self + other.""" - if not isinstance(other, Twist): - return NotImplemented - return Twist( - linear=self.linear + other.linear, - angular=self.angular + other.angular, - ) - - def __bool__(self) -> bool: - """Boolean conversion for Twist. - - A Twist is considered False if it's a zero twist (no motion), - and True otherwise. - - Returns: - False if twist is zero, True otherwise - """ - return not self.is_zero() diff --git a/dimos/msgs/geometry_msgs/TwistStamped.py b/dimos/msgs/geometry_msgs/TwistStamped.py deleted file mode 100644 index 4377687e564..00000000000 --- a/dimos/msgs/geometry_msgs/TwistStamped.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import time -from typing import Any, BinaryIO, TypeAlias - -from dimos_lcm.geometry_msgs import TwistStamped as LCMTwistStamped - -from dimos.msgs.geometry_msgs.Twist import Twist -from dimos.msgs.geometry_msgs.Vector3 import VectorConvertable -from dimos.types.timestamped import Timestamped - -# Types that can be converted to/from TwistStamped -TwistConvertable: TypeAlias = ( - tuple[VectorConvertable, VectorConvertable] | LCMTwistStamped | dict[str, VectorConvertable] -) - - -def sec_nsec(ts): # type: ignore[no-untyped-def] - s = int(ts) - return [s, int((ts - s) * 1_000_000_000)] - - -class TwistStamped(Twist, Timestamped): - msg_name = "geometry_msgs.TwistStamped" - ts: float - frame_id: str - - def __init__(self, *args: Any, **kwargs: Any) -> None: - """Initialize a stamped twist. - - Takes ``(ts, frame_id)`` positionally, plus every Twist keyword. Any other - positional form belongs to Twist, so ``TwistStamped(linear, angular)`` - works as it does on the base class. - """ - ts: Any - # A leading number or string is a timestamp; anything else is a Twist argument. - if args and isinstance(args[0], int | float | str): - ts = args[0] - frame_id = args[1] if len(args) > 1 else kwargs.pop("frame_id", "") - twist_args: tuple[Any, ...] = () - else: - ts = kwargs.pop("ts", None) - frame_id = kwargs.pop("frame_id", "") - twist_args = args - - self.frame_id = frame_id - self.ts = time.time() if ts is None else ts - super().__init__(*twist_args, **kwargs) - - def lcm_encode(self) -> bytes: - lcm_msg = LCMTwistStamped() - lcm_msg.twist = self - [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] - lcm_msg.header.frame_id = self.frame_id - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes | BinaryIO) -> TwistStamped: - lcm_msg = LCMTwistStamped.lcm_decode(data) - return cls( - ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), - frame_id=lcm_msg.header.frame_id, - linear=[lcm_msg.twist.linear.x, lcm_msg.twist.linear.y, lcm_msg.twist.linear.z], - angular=[lcm_msg.twist.angular.x, lcm_msg.twist.angular.y, lcm_msg.twist.angular.z], - ) - - def __str__(self) -> str: - return ( - f"TwistStamped(linear=[{self.linear.x:.3f}, {self.linear.y:.3f}, {self.linear.z:.3f}], " - f"angular=[{self.angular.x:.3f}, {self.angular.y:.3f}, {self.angular.z:.3f}])" - ) diff --git a/dimos/msgs/geometry_msgs/TwistWithCovariance.py b/dimos/msgs/geometry_msgs/TwistWithCovariance.py deleted file mode 100644 index 3786a013f54..00000000000 --- a/dimos/msgs/geometry_msgs/TwistWithCovariance.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from typing import Any, TypeAlias - -from dimos_lcm.geometry_msgs import ( - TwistWithCovariance as LCMTwistWithCovariance, -) -import numpy as np - -from dimos.msgs.geometry_msgs.Twist import Twist -from dimos.msgs.geometry_msgs.Vector3 import Vector3, VectorConvertable - -# Types that can be converted to/from TwistWithCovariance -TwistWithCovarianceConvertable: TypeAlias = ( - tuple[Twist | tuple[VectorConvertable, VectorConvertable], list[float] | np.ndarray] - | LCMTwistWithCovariance - | dict[str, Twist | tuple[VectorConvertable, VectorConvertable] | list[float] | np.ndarray] -) - -COVARIANCE_SIZE = 36 - - -def _is_twist_covariance_pair(value: Any) -> bool: - """True for a 2-element (twist, covariance) pair, where covariance is 36 long.""" - if not isinstance(value, tuple | list) or len(value) != 2: - return False - covariance = value[1] - return isinstance(covariance, list | np.ndarray) and np.size(covariance) == COVARIANCE_SIZE - - -def _to_twist(value: Any) -> Twist: - """A Twist, or a (linear, angular) pair to build one from.""" - if isinstance(value, Twist): - return value - if value is None: - return Twist() - return Twist(value[0], value[1]) - - -class TwistWithCovariance(LCMTwistWithCovariance): # type: ignore[misc] - twist: Twist - covariance: np.ndarray[tuple[int], np.dtype[np.floating[Any]]] - msg_name = "geometry_msgs.TwistWithCovariance" - - def __init__( - self, - twist: Twist | TwistWithCovarianceConvertable | None = None, - covariance: list[float] | np.ndarray | None = None, - ) -> None: - """Initialize a twist with covariance. - - Supported forms: - TwistWithCovariance() # zero twist and covariance - TwistWithCovariance(twist) - TwistWithCovariance(twist, covariance) - TwistWithCovariance(twist=..., covariance=...) - TwistWithCovariance((linear, angular)) - TwistWithCovariance((twist, covariance)) # pair - TwistWithCovariance({"twist": ..., "covariance": ...}) - TwistWithCovariance(other) # copy constructor - TwistWithCovariance(lcm_twist_with_cov) # from LCM message - """ - source: Any = twist - cov: Any = covariance - - # TwistWithCovariance before LCMTwistWithCovariance (it is a subclass). - if isinstance(source, TwistWithCovariance): - if cov is None: - cov = np.array(source.covariance).copy() - source = Twist(source.twist) # copy constructor: don't alias the source twist - elif isinstance(source, LCMTwistWithCovariance): - if cov is None: - cov = np.array(source.covariance) - source = Twist(source.twist) - elif isinstance(source, dict) and "twist" in source: - cov = source.get("covariance", cov) - source = source["twist"] - elif _is_twist_covariance_pair(source): - source, cov = source - - self.twist = _to_twist(source) - self.covariance = ( - np.zeros(COVARIANCE_SIZE) - if cov is None - else np.array(cov, dtype=float).reshape(COVARIANCE_SIZE) - ) - - def __getattribute__(self, name: str): # type: ignore[no-untyped-def] - """Override to ensure covariance is always returned as numpy array.""" - if name == "covariance": - cov = object.__getattribute__(self, "covariance") - if not isinstance(cov, np.ndarray): - return np.array(cov, dtype=float) - return cov - return super().__getattribute__(name) - - def __setattr__(self, name: str, value) -> None: # type: ignore[no-untyped-def] - """Override to ensure covariance is stored as numpy array.""" - if name == "covariance": - if not isinstance(value, np.ndarray): - value = np.array(value, dtype=float).reshape(36) - super().__setattr__(name, value) - - @property - def linear(self) -> Vector3: - """Linear velocity vector.""" - return self.twist.linear - - @property - def angular(self) -> Vector3: - """Angular velocity vector.""" - return self.twist.angular - - @property - def covariance_matrix(self) -> np.ndarray: - """Get covariance as 6x6 matrix.""" - return self.covariance.reshape(6, 6) - - @covariance_matrix.setter - def covariance_matrix(self, value: np.ndarray) -> None: - """Set covariance from 6x6 matrix.""" - self.covariance = np.array(value).reshape(36) - - def __repr__(self) -> str: - return f"TwistWithCovariance(twist={self.twist!r}, covariance=<{self.covariance.shape[0] if isinstance(self.covariance, np.ndarray) else len(self.covariance)} elements>)" - - def __str__(self) -> str: - return ( - f"TwistWithCovariance(linear=[{self.linear.x:.3f}, {self.linear.y:.3f}, {self.linear.z:.3f}], " - f"angular=[{self.angular.x:.3f}, {self.angular.y:.3f}, {self.angular.z:.3f}], " - f"cov_trace={np.trace(self.covariance_matrix):.3f})" - ) - - def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] - """Check if two TwistWithCovariance are equal.""" - if not isinstance(other, TwistWithCovariance): - return False - return self.twist == other.twist and np.allclose(self.covariance, other.covariance) - - def is_zero(self) -> bool: - """Check if this is a zero twist (no linear or angular velocity).""" - return self.twist.is_zero() - - def __bool__(self) -> bool: - """Boolean conversion - False if zero twist, True otherwise.""" - return not self.is_zero() - - def lcm_encode(self) -> bytes: - """Encode to LCM binary format.""" - lcm_msg = LCMTwistWithCovariance() - lcm_msg.twist = self.twist - # LCM expects list, not numpy array - if isinstance(self.covariance, np.ndarray): - lcm_msg.covariance = self.covariance.tolist() - else: - lcm_msg.covariance = list(self.covariance) - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes) -> TwistWithCovariance: - """Decode from LCM binary format.""" - lcm_msg = LCMTwistWithCovariance.lcm_decode(data) - twist = Twist( - linear=[lcm_msg.twist.linear.x, lcm_msg.twist.linear.y, lcm_msg.twist.linear.z], - angular=[lcm_msg.twist.angular.x, lcm_msg.twist.angular.y, lcm_msg.twist.angular.z], - ) - return cls(twist, lcm_msg.covariance) diff --git a/dimos/msgs/geometry_msgs/TwistWithCovarianceStamped.py b/dimos/msgs/geometry_msgs/TwistWithCovarianceStamped.py deleted file mode 100644 index a828fdaa836..00000000000 --- a/dimos/msgs/geometry_msgs/TwistWithCovarianceStamped.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import time -from typing import TypeAlias - -from dimos_lcm.geometry_msgs import ( - TwistWithCovarianceStamped as LCMTwistWithCovarianceStamped, -) -import numpy as np - -from dimos.msgs.geometry_msgs.Twist import Twist -from dimos.msgs.geometry_msgs.TwistWithCovariance import TwistWithCovariance -from dimos.msgs.geometry_msgs.Vector3 import VectorConvertable -from dimos.types.timestamped import Timestamped - -# Types that can be converted to/from TwistWithCovarianceStamped -TwistWithCovarianceStampedConvertable: TypeAlias = ( - tuple[Twist | tuple[VectorConvertable, VectorConvertable], list[float] | np.ndarray] - | LCMTwistWithCovarianceStamped - | dict[ - str, - Twist - | tuple[VectorConvertable, VectorConvertable] - | list[float] - | np.ndarray - | float - | str, - ] -) - - -def sec_nsec(ts): # type: ignore[no-untyped-def] - s = int(ts) - return [s, int((ts - s) * 1_000_000_000)] - - -class TwistWithCovarianceStamped(TwistWithCovariance, Timestamped): - msg_name = "geometry_msgs.TwistWithCovarianceStamped" - ts: float - frame_id: str - - def __init__( - self, - ts: float | None = None, - frame_id: str = "", - twist: Twist | tuple[VectorConvertable, VectorConvertable] | None = None, - covariance: list[float] | np.ndarray | None = None, - ) -> None: - """Initialize with timestamp, frame_id, twist and covariance.""" - self.frame_id = frame_id - self.ts = time.time() if ts is None else ts - super().__init__(twist, covariance) - - def lcm_encode(self) -> bytes: - lcm_msg = LCMTwistWithCovarianceStamped() - lcm_msg.twist.twist = self.twist - # LCM expects list, not numpy array - if isinstance(self.covariance, np.ndarray): - lcm_msg.twist.covariance = self.covariance.tolist() - else: - lcm_msg.twist.covariance = list(self.covariance) - [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] - lcm_msg.header.frame_id = self.frame_id - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes) -> TwistWithCovarianceStamped: - lcm_msg = LCMTwistWithCovarianceStamped.lcm_decode(data) - return cls( - ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), - frame_id=lcm_msg.header.frame_id, - twist=Twist( - linear=[ - lcm_msg.twist.twist.linear.x, - lcm_msg.twist.twist.linear.y, - lcm_msg.twist.twist.linear.z, - ], - angular=[ - lcm_msg.twist.twist.angular.x, - lcm_msg.twist.twist.angular.y, - lcm_msg.twist.twist.angular.z, - ], - ), - covariance=lcm_msg.twist.covariance, - ) - - def __str__(self) -> str: - return ( - f"TwistWithCovarianceStamped(linear=[{self.linear.x:.3f}, {self.linear.y:.3f}, {self.linear.z:.3f}], " - f"angular=[{self.angular.x:.3f}, {self.angular.y:.3f}, {self.angular.z:.3f}], " - f"cov_trace={np.trace(self.covariance_matrix):.3f})" - ) diff --git a/dimos/msgs/geometry_msgs/Vector3.py b/dimos/msgs/geometry_msgs/Vector3.py deleted file mode 100644 index 99c98677182..00000000000 --- a/dimos/msgs/geometry_msgs/Vector3.py +++ /dev/null @@ -1,434 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from collections.abc import Sequence -from typing import Any, TypeAlias - -from dimos_lcm.geometry_msgs import Vector3 as LCMVector3 -import numpy as np - -# Types that can be converted to/from Vector -VectorConvertable: TypeAlias = Sequence[int | float] | LCMVector3 | np.ndarray - - -def _ensure_3d(data: np.ndarray) -> np.ndarray: - """Ensure the data array is exactly 3D by padding with zeros or raising an exception if too long.""" - if len(data) == 3: - return data - elif len(data) < 3: - padded = np.zeros(3, dtype=float) - padded[: len(data)] = data - return padded - else: - raise ValueError( - f"Vector3 cannot be initialized with more than 3 components. Got {len(data)} components." - ) - - -class Vector3(LCMVector3): # type: ignore[misc] - x: float = 0.0 - y: float = 0.0 - z: float = 0.0 - - def __init__(self, *args: Any, **kwargs: Any) -> None: - """Initialize a 3D vector. - - Supported forms: - Vector3() # zero vector - Vector3(x) # (x, 0, 0) - Vector3(x, y) # (x, y, 0) - Vector3(x, y, z) # (x, y, z) - Vector3(x=1, y=2, z=3) # keyword args - Vector3([x, y, z]) # sequence - Vector3(np.array([x, y, z])) # numpy array - Vector3(other_vector3) # copy constructor - Vector3(lcm_vector3) # from LCM message - """ - if kwargs and not args: - # Keyword arguments: Vector3(x=1, y=2, z=3) - self.x = float(kwargs.get("x", 0.0)) - self.y = float(kwargs.get("y", 0.0)) - self.z = float(kwargs.get("z", 0.0)) - elif not args: - # No arguments: zero vector - self.x = 0.0 - self.y = 0.0 - self.z = 0.0 - elif len(args) == 1: - arg = args[0] - if isinstance(arg, Vector3): - # Copy constructor - self.x = arg.x - self.y = arg.y - self.z = arg.z - elif isinstance(arg, LCMVector3): - # From LCM Vector3 - self.x = float(arg.x) - self.y = float(arg.y) - self.z = float(arg.z) - elif isinstance(arg, np.ndarray): - # From numpy array - data = _ensure_3d(np.array(arg, dtype=float)) - self.x = float(data[0]) - self.y = float(data[1]) - self.z = float(data[2]) - elif isinstance(arg, (list, tuple)): - # From sequence - data = _ensure_3d(np.array(arg, dtype=float)) - self.x = float(data[0]) - self.y = float(data[1]) - self.z = float(data[2]) - elif isinstance(arg, (int, float)): - # Single numeric value: (x, 0, 0) - self.x = float(arg) - self.y = 0.0 - self.z = 0.0 - else: - raise TypeError(f"Cannot initialize Vector3 from {type(arg)}") - elif len(args) == 2: - # Two numeric values: (x, y, 0) - self.x = float(args[0]) - self.y = float(args[1]) - self.z = 0.0 - elif len(args) == 3: - # Three numeric values: (x, y, z) - self.x = float(args[0]) - self.y = float(args[1]) - self.z = float(args[2]) - else: - raise TypeError(f"Vector3 takes at most 3 positional arguments ({len(args)} given)") - - @property - def as_tuple(self) -> tuple[float, float, float]: - return (self.x, self.y, self.z) - - @property - def yaw(self) -> float: - return self.z - - @property - def pitch(self) -> float: - return self.y - - @property - def roll(self) -> float: - return self.x - - @property - def data(self) -> np.ndarray: - """Get the underlying numpy array.""" - return np.array([self.x, self.y, self.z], dtype=float) - - def __getitem__(self, idx: int) -> float: - if idx == 0: - return self.x - elif idx == 1: - return self.y - elif idx == 2: - return self.z - else: - raise IndexError(f"Vector3 index {idx} out of range [0-2]") - - def __repr__(self) -> str: - return f"Vector({self.data})" - - def __str__(self) -> str: - def getArrow() -> str: - repr = ["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"] - - if self.x == 0 and self.y == 0: - return "·" - - # Calculate angle in radians and convert to directional index - angle = np.arctan2(self.y, self.x) - # Map angle to 0-7 index (8 directions) with proper orientation - dir_index = int(((angle + np.pi) * 4 / np.pi) % 8) - # Get directional arrow symbol - return repr[dir_index] - - return f"{getArrow()} Vector {self.__repr__()}" - - def agent_encode(self) -> dict[str, float]: - """Encode the vector for agent communication.""" - return {"x": self.x, "y": self.y, "z": self.z} - - def serialize(self) -> dict[str, Any]: - """Serialize the vector to a tuple.""" - return {"type": "vector", "c": (self.x, self.y, self.z)} - - def __eq__(self, other: object) -> bool: - """Check if two vectors are equal using numpy's allclose for floating point comparison.""" - if not isinstance(other, Vector3): - return False - return bool(np.allclose([self.x, self.y, self.z], [other.x, other.y, other.z])) - - def __add__(self, other: VectorConvertable | Vector3) -> Vector3: - other_vector: Vector3 = to_vector(other) - return self.__class__( - self.x + other_vector.x, self.y + other_vector.y, self.z + other_vector.z - ) - - def __sub__(self, other: VectorConvertable | Vector3) -> Vector3: - other_vector = to_vector(other) - return self.__class__( - self.x - other_vector.x, self.y - other_vector.y, self.z - other_vector.z - ) - - def __mul__(self, scalar: float) -> Vector3: - return self.__class__(self.x * scalar, self.y * scalar, self.z * scalar) - - def __rmul__(self, scalar: float) -> Vector3: - return self.__mul__(scalar) - - def __truediv__(self, scalar: float) -> Vector3: - return self.__class__(self.x / scalar, self.y / scalar, self.z / scalar) - - def __neg__(self) -> Vector3: - return self.__class__(-self.x, -self.y, -self.z) - - def dot(self, other: VectorConvertable | Vector3) -> float: - """Compute dot product.""" - other_vector = to_vector(other) - return float(self.x * other_vector.x + self.y * other_vector.y + self.z * other_vector.z) - - def cross(self, other: VectorConvertable | Vector3) -> Vector3: - """Compute cross product (3D vectors only).""" - other_vector = to_vector(other) - return self.__class__( - self.y * other_vector.z - self.z * other_vector.y, - self.z * other_vector.x - self.x * other_vector.z, - self.x * other_vector.y - self.y * other_vector.x, - ) - - def magnitude(self) -> float: - """Alias for length().""" - return self.length() - - def length(self) -> float: - """Compute the Euclidean length (magnitude) of the vector.""" - return float(np.sqrt(self.x * self.x + self.y * self.y + self.z * self.z)) - - def length_squared(self) -> float: - """Compute the squared length of the vector (faster than length()).""" - return float(self.x * self.x + self.y * self.y + self.z * self.z) - - def normalize(self) -> Vector3: - """Return a normalized unit vector in the same direction.""" - length = self.length() - if length < 1e-10: # Avoid division by near-zero - return self.__class__(0.0, 0.0, 0.0) - return self.__class__(self.x / length, self.y / length, self.z / length) - - def to_2d(self) -> Vector3: - """Convert a vector to a 2D vector by taking only the x and y components (z=0).""" - return self.__class__(self.x, self.y, 0.0) - - def distance(self, other: VectorConvertable | Vector3) -> float: - """Compute Euclidean distance to another vector.""" - other_vector = to_vector(other) - dx = self.x - other_vector.x - dy = self.y - other_vector.y - dz = self.z - other_vector.z - return float(np.sqrt(dx * dx + dy * dy + dz * dz)) - - def distance_squared(self, other: VectorConvertable | Vector3) -> float: - """Compute squared Euclidean distance to another vector (faster than distance()).""" - other_vector = to_vector(other) - dx = self.x - other_vector.x - dy = self.y - other_vector.y - dz = self.z - other_vector.z - return float(dx * dx + dy * dy + dz * dz) - - def angle(self, other: VectorConvertable | Vector3) -> float: - """Compute the angle (in radians) between this vector and another.""" - other_vector = to_vector(other) - this_length = self.length() - other_length = other_vector.length() - - if this_length < 1e-10 or other_length < 1e-10: - return 0.0 - - cos_angle = np.clip( - self.dot(other_vector) / (this_length * other_length), - -1.0, - 1.0, - ) - return float(np.arccos(cos_angle)) - - def project(self, onto: VectorConvertable | Vector3) -> Vector3: - """Project this vector onto another vector.""" - onto_vector = to_vector(onto) - onto_length_sq = ( - onto_vector.x * onto_vector.x - + onto_vector.y * onto_vector.y - + onto_vector.z * onto_vector.z - ) - if onto_length_sq < 1e-10: - return self.__class__(0.0, 0.0, 0.0) - - scalar_projection = self.dot(onto_vector) / onto_length_sq - return self.__class__( - scalar_projection * onto_vector.x, - scalar_projection * onto_vector.y, - scalar_projection * onto_vector.z, - ) - - @classmethod - def zeros(cls) -> Vector3: - """Create a zero 3D vector.""" - return cls() - - @classmethod - def ones(cls) -> Vector3: - """Create a 3D vector of ones.""" - return cls(1.0, 1.0, 1.0) - - @classmethod - def unit_x(cls) -> Vector3: - """Create a unit vector in the x direction.""" - return cls(1.0, 0.0, 0.0) - - @classmethod - def unit_y(cls) -> Vector3: - """Create a unit vector in the y direction.""" - return cls(0.0, 1.0, 0.0) - - @classmethod - def unit_z(cls) -> Vector3: - """Create a unit vector in the z direction.""" - return cls(0.0, 0.0, 1.0) - - def to_list(self) -> list[float]: - """Convert the vector to a list.""" - return [self.x, self.y, self.z] - - def to_tuple(self) -> tuple[float, float, float]: - """Convert the vector to a tuple.""" - return (self.x, self.y, self.z) - - def to_numpy(self) -> np.ndarray: - """Convert the vector to a numpy array.""" - return np.array([self.x, self.y, self.z], dtype=float) - - def is_zero(self) -> bool: - """Check if this is a zero vector (all components are zero). - - Returns: - True if all components are zero, False otherwise - """ - return bool(np.allclose([self.x, self.y, self.z], 0.0)) - - @property - def quaternion(self) -> Quaternion: # type: ignore[name-defined] - return self.to_quaternion() - - def to_quaternion(self) -> Quaternion: # type: ignore[name-defined] - """Convert Vector3 representing Euler angles (roll, pitch, yaw) to a Quaternion. - - Assumes this Vector3 contains Euler angles in radians: - - x component: roll (rotation around x-axis) - - y component: pitch (rotation around y-axis) - - z component: yaw (rotation around z-axis) - - Returns: - Quaternion: The equivalent quaternion representation - """ - # Import here to avoid circular imports - from dimos.msgs.geometry_msgs.Quaternion import Quaternion - - # Extract Euler angles - roll = self.x - pitch = self.y - yaw = self.z - - # Convert Euler angles to quaternion using ZYX convention - # Source: https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles - - # Compute half angles - cy = np.cos(yaw * 0.5) - sy = np.sin(yaw * 0.5) - cp = np.cos(pitch * 0.5) - sp = np.sin(pitch * 0.5) - cr = np.cos(roll * 0.5) - sr = np.sin(roll * 0.5) - - # Compute quaternion components - w = cr * cp * cy + sr * sp * sy - x = sr * cp * cy - cr * sp * sy - y = cr * sp * cy + sr * cp * sy - z = cr * cp * sy - sr * sp * cy - - return Quaternion(x, y, z, w) - - def __bool__(self) -> bool: - """Boolean conversion for Vector. - - A Vector is considered False if it's a zero vector (all components are zero), - and True otherwise. - - Returns: - False if vector is zero, True otherwise - """ - return not self.is_zero() - - -def to_numpy(value: Vector3 | np.ndarray | Sequence[int | float]) -> np.ndarray: - """Convert a value to a numpy array.""" - if isinstance(value, Vector3): - return value.to_numpy() - elif isinstance(value, np.ndarray): - return value - else: - return np.array(value, dtype=float) - - -def to_vector(value: VectorConvertable | Vector3) -> Vector3: - """Convert a vector-compatible value to a Vector3 object.""" - if isinstance(value, Vector3): - return value - return Vector3(value) - - -def to_tuple(value: Vector3 | np.ndarray | Sequence[int | float]) -> tuple[float, ...]: - """Convert a value to a tuple.""" - if isinstance(value, Vector3): - return value.to_tuple() - elif isinstance(value, np.ndarray): - return tuple(value.tolist()) - elif isinstance(value, tuple): - return value - else: - return tuple(value) - - -def to_list(value: Vector3 | np.ndarray | Sequence[int | float]) -> list[float]: - """Convert a value to a list.""" - if isinstance(value, Vector3): - return value.to_list() - elif isinstance(value, np.ndarray): - result: list[float] = value.tolist() - return result - elif isinstance(value, list): - return value - else: - return list(value) - - -VectorLike: TypeAlias = VectorConvertable | Vector3 - - -def make_vector3(x: float, y: float, z: float) -> Vector3: - return Vector3(x, y, z) diff --git a/dimos/msgs/geometry_msgs/Wrench.py b/dimos/msgs/geometry_msgs/Wrench.py deleted file mode 100644 index 7b3a4427758..00000000000 --- a/dimos/msgs/geometry_msgs/Wrench.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from collections.abc import Sequence -from typing import Any, overload - -from dimos_lcm.geometry_msgs import Wrench as LCMWrench -import numpy as np - -from dimos.msgs.geometry_msgs.Vector3 import Vector3, VectorLike - - -class Wrench(LCMWrench): # type: ignore[misc] - """Force (N) and torque (Nm) in 3D space.""" - - force: Vector3 - torque: Vector3 - msg_name = "geometry_msgs.Wrench" - - @overload - def __init__(self) -> None: ... - - @overload - def __init__( - self, - force: VectorLike | None = ..., - torque: VectorLike | None = ..., - ) -> None: ... - - @overload - def __init__(self, wrench: Wrench | LCMWrench, /) -> None: ... - - def __init__(self, *args: Any, **kwargs: Any) -> None: - """Initialize a wrench. - - Supported forms: - Wrench() # zero wrench - Wrench(force, torque) - Wrench(force=..., torque=...) # keyword args, either optional - Wrench(other_wrench) # copy constructor - Wrench(lcm_wrench) # from LCM message - """ - force: Any = None - torque: Any = None - - if len(args) == 2: - force, torque = args - elif len(args) == 1: - value = args[0] - # Wrench before LCMWrench (it is a subclass); anything else is a - # force, same as the `force=` keyword. - if isinstance(value, Wrench | LCMWrench): - force, torque = value.force, value.torque - else: - force = value - elif args: - raise TypeError(f"Wrench takes 1 or 2 positional arguments ({len(args)} given)") - - if kwargs: - force = kwargs.pop("force", force) - torque = kwargs.pop("torque", torque) - if kwargs: - raise TypeError(f"Wrench got unexpected keyword arguments {sorted(kwargs)}") - - self.force = Vector3() if force is None else Vector3(force) - self.torque = Vector3() if torque is None else Vector3(torque) - - @classmethod - def from_array(cls, ft: Sequence[float] | np.ndarray) -> Wrench: - """Build from a 6-element ``[fx, fy, fz, tx, ty, tz]`` sensor reading.""" - if len(ft) != 6: - raise ValueError(f"Expected 6 elements [fx, fy, fz, tx, ty, tz], got {len(ft)}") - return cls(force=ft[:3], torque=ft[3:]) - - def to_array(self) -> np.ndarray: - """``[fx, fy, fz, tx, ty, tz]``.""" - return np.concatenate([self.force.to_numpy(), self.torque.to_numpy()]) - - @classmethod - def zero(cls) -> Wrench: - return cls() - - def is_zero(self) -> bool: - return self.force.is_zero() and self.torque.is_zero() - - def __add__(self, other: Wrench) -> Wrench: - if not isinstance(other, Wrench): - return NotImplemented - return Wrench(force=self.force + other.force, torque=self.torque + other.torque) - - def __sub__(self, other: Wrench) -> Wrench: - if not isinstance(other, Wrench): - return NotImplemented - return Wrench(force=self.force - other.force, torque=self.torque - other.torque) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Wrench): - return False - return self.force == other.force and self.torque == other.torque - - def __bool__(self) -> bool: - return not self.is_zero() - - def __repr__(self) -> str: - return f"Wrench(force={self.force!r}, torque={self.torque!r})" - - def __str__(self) -> str: - return f"Wrench:\n Force: {self.force}\n Torque: {self.torque}" diff --git a/dimos/msgs/geometry_msgs/WrenchStamped.py b/dimos/msgs/geometry_msgs/WrenchStamped.py deleted file mode 100644 index 12e6e940072..00000000000 --- a/dimos/msgs/geometry_msgs/WrenchStamped.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from collections.abc import Sequence -import time -from typing import Any, BinaryIO - -from dimos_lcm.geometry_msgs import WrenchStamped as LCMWrenchStamped -import numpy as np - -from dimos.msgs.geometry_msgs.Wrench import Wrench -from dimos.types.timestamped import Timestamped - - -class WrenchStamped(Wrench, Timestamped): - """A force/torque measurement with a timestamp and frame_id.""" - - msg_name = "geometry_msgs.WrenchStamped" - ts: float - frame_id: str - - def __init__(self, *args: Any, **kwargs: Any) -> None: - """Initialize a stamped wrench. - - Takes ``(ts, frame_id)`` positionally, plus every Wrench keyword. Any other - positional form belongs to Wrench, so ``WrenchStamped(force, torque)`` works - as it does on the base class. - """ - ts: Any - # A leading number or string is a timestamp; anything else is a Wrench argument. - if args and isinstance(args[0], int | float | str): - ts = args[0] - frame_id = args[1] if len(args) > 1 else kwargs.pop("frame_id", "") - wrench_args: tuple[Any, ...] = () - else: - ts = kwargs.pop("ts", None) - frame_id = kwargs.pop("frame_id", "") - wrench_args = args - - self.frame_id = frame_id - self.ts = time.time() if ts is None else ts - super().__init__(*wrench_args, **kwargs) - - @classmethod - def from_array( # type: ignore[override] - cls, - ft: Sequence[float] | np.ndarray, - frame_id: str = "ft_sensor", - ts: float | None = None, - ) -> WrenchStamped: - """Build from a 6-element ``[fx, fy, fz, tx, ty, tz]`` sensor reading.""" - if len(ft) != 6: - raise ValueError(f"Expected 6 elements [fx, fy, fz, tx, ty, tz], got {len(ft)}") - return cls(ts=ts, frame_id=frame_id, force=ft[:3], torque=ft[3:]) - - def lcm_encode(self) -> bytes: - lcm_msg = LCMWrenchStamped() - lcm_msg.wrench = self - [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = self.ros_timestamp() - lcm_msg.header.frame_id = self.frame_id - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes | BinaryIO) -> WrenchStamped: - lcm_msg = LCMWrenchStamped.lcm_decode(data) - return cls( - ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), - frame_id=lcm_msg.header.frame_id, - force=[lcm_msg.wrench.force.x, lcm_msg.wrench.force.y, lcm_msg.wrench.force.z], - torque=[lcm_msg.wrench.torque.x, lcm_msg.wrench.torque.y, lcm_msg.wrench.torque.z], - ) - - def __repr__(self) -> str: - return ( - f"WrenchStamped(force={self.force!r}, torque={self.torque!r}, " - f"ts={self.ts}, frame_id={self.frame_id!r})" - ) - - def __str__(self) -> str: - return ( - f"WrenchStamped(force=[{self.force.x:.3f}, {self.force.y:.3f}, {self.force.z:.3f}], " - f"torque=[{self.torque.x:.3f}, {self.torque.y:.3f}, {self.torque.z:.3f}], " - f"frame_id={self.frame_id!r})" - ) diff --git a/dimos/msgs/manipulation_msgs/GraspCandidate.py b/dimos/msgs/manipulation_msgs/GraspCandidate.py deleted file mode 100644 index f83db6016f4..00000000000 --- a/dimos/msgs/manipulation_msgs/GraspCandidate.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import math -import pickle - -from dimos.msgs.geometry_msgs.Pose import Pose - - -class GraspCandidate: - """A robot TCP pose and its generator-local ranking score.""" - - msg_name = "manipulation_msgs.GraspCandidate" - - def __init__(self, pose: Pose | None = None, score: float = 0.0) -> None: - self.pose = pose if pose is not None else Pose(0.0, 0.0, 0.0) - self.score = float(score) - if not math.isfinite(self.score): - raise ValueError("GraspCandidate.score must be finite") - - def encode(self) -> bytes: - return pickle.dumps({"pose": self.pose, "score": self.score}) - - @classmethod - def decode(cls, data: bytes) -> GraspCandidate: - value = pickle.loads(data) - return cls(value["pose"], value["score"]) diff --git a/dimos/msgs/manipulation_msgs/GraspCandidateArray.py b/dimos/msgs/manipulation_msgs/GraspCandidateArray.py deleted file mode 100644 index 5144d0b5b91..00000000000 --- a/dimos/msgs/manipulation_msgs/GraspCandidateArray.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from collections.abc import Iterator -import pickle - -from dimos.msgs.manipulation_msgs.GraspCandidate import GraspCandidate -from dimos.msgs.std_msgs.Header import Header - - -class GraspCandidateArray: - """Ordered grasp proposals sharing one input-cloud header.""" - - msg_name = "manipulation_msgs.GraspCandidateArray" - - def __init__( - self, header: Header | None = None, candidates: list[GraspCandidate] | None = None - ) -> None: - self.header = header if header is not None else Header(0.0) - self.candidates = candidates if candidates is not None else [] - - def __len__(self) -> int: - return len(self.candidates) - - def __iter__(self) -> Iterator[GraspCandidate]: - return iter(self.candidates) - - def encode(self) -> bytes: - """Encode using the repository's pickle transport convention.""" - return pickle.dumps({"header": self.header, "candidates": self.candidates}) - - @classmethod - def decode(cls, data: bytes) -> GraspCandidateArray: - value = pickle.loads(data) - return cls(value["header"], value["candidates"]) diff --git a/dimos/msgs/nav_msgs/OccupancyGrid.py b/dimos/msgs/nav_msgs/OccupancyGrid.py deleted file mode 100644 index 7370cd6bf70..00000000000 --- a/dimos/msgs/nav_msgs/OccupancyGrid.py +++ /dev/null @@ -1,598 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from enum import IntEnum -from functools import lru_cache -import time -from typing import TYPE_CHECKING, BinaryIO - -from dimos_lcm.nav_msgs import ( - MapMetaData, - OccupancyGrid as LCMOccupancyGrid, -) -from dimos_lcm.std_msgs import Time as LCMTime -import numpy as np - -from dimos.msgs.geometry_msgs.Pose import Pose -from dimos.msgs.geometry_msgs.Vector3 import Vector3, VectorLike -from dimos.types.timestamped import Timestamped - - -@lru_cache(maxsize=16) -def _get_matplotlib_cmap(name: str): # type: ignore[no-untyped-def] - """Get a matplotlib colormap by name (cached for performance).""" - # Lazy import to save time. - import matplotlib.pyplot as plt - - return plt.get_cmap(name) - - -@lru_cache(maxsize=16) -def _build_occupancy_lut( - colormap: str | None, - opacity: float, - background: str | None, -) -> np.ndarray: - """Build a 102-entry RGBA LUT for grid values -1..100. One-time cost per config.""" - bg_rgb = np.array([0, 0, 0], dtype=np.float32) - if background is not None: - bg = background.lstrip("#") - bg_rgb = np.array([int(bg[i : i + 2], 16) for i in (0, 2, 4)], dtype=np.float32) - - # LUT: index 0 = grid value -1 (unknown), index 1 = grid value 0 (free), index 2..101 = grid values 1..100 - lut = np.zeros((102, 4), dtype=np.uint8) - - # Unknown (-1) → index 0: black - lut[0] = [0, 0, 0, 255] - - if colormap is not None: - cmap = _get_matplotlib_cmap(colormap) - # Free (0) → index 1 - fg = np.array(cmap(0.0)[:3]) * 255 - blended = fg * opacity + bg_rgb * (1 - opacity) - lut[1, :3] = blended.astype(np.uint8) - lut[1, 3] = 255 - - # Occupied (1..100) → index 2..101 - for cost in range(1, 101): - cost_norm = 0.5 + (cost / 100) * 0.5 - fg = np.array(cmap(cost_norm)[:3]) * 255 - blended = fg * opacity + bg_rgb * (1 - opacity) - lut[cost + 1, :3] = blended.astype(np.uint8) - lut[cost + 1, 3] = 255 - else: - # Foxglove-style: free = #484981, occupied = gradient to black - fg_free = np.array([72, 73, 129], dtype=np.float32) - blended_free = fg_free * opacity + bg_rgb * (1 - opacity) - lut[1, :3] = blended_free.astype(np.uint8) - lut[1, 3] = 255 - - for cost in range(1, 101): - factor = 1 - cost / 100 - fg = np.array([72 * factor, 73 * factor, 129 * factor], dtype=np.float32) - blended = fg * opacity + bg_rgb * (1 - opacity) - lut[cost + 1, :3] = blended.astype(np.uint8) - lut[cost + 1, 3] = 255 - - return lut - - -if TYPE_CHECKING: - from pathlib import Path - - from numpy.typing import NDArray - from rerun._baseclasses import Archetype - - -def block_max_reduce(cells: NDArray[np.int8], factor: int) -> NDArray[np.int8]: - """Coarsen an occupancy grid by taking the max of factor x factor blocks. - - Block maximum (not mean) so coarsening never erases an obstacle; a block - is unknown (-1) only when every cell in it is unknown. Trailing remainder - rows/cols are trimmed, keeping row 0/col 0 - the origin corner - so the - grid origin stays valid. Grids thinner than `factor` pass through. - """ - h, w = cells.shape[:2] - new_h, new_w = h // factor, w // factor - if new_h == 0 or new_w == 0: - return cells - trimmed = cells[: new_h * factor, : new_w * factor] - blocks = trimmed.reshape(new_h, factor, new_w, factor) - # Sink unknown below every known value for the max, then map it back. - as_int = blocks.astype(np.int16) - known = np.where(as_int < 0, -1000, as_int) - reduced = known.max(axis=(1, 3)) - reduced[reduced == -1000] = -1 - result: NDArray[np.int8] = reduced.astype(np.int8) - return result - - -class CostValues(IntEnum): - """Standard cost values for occupancy grid cells. - - These values follow the ROS nav_msgs/OccupancyGrid convention: - - 0: Free space - - 1-99: Occupied space with varying cost levels - - 100: Lethal obstacle (definitely occupied) - - -1: Unknown space - """ - - UNKNOWN = -1 # Unknown space - FREE = 0 # Free space - OCCUPIED = 100 # Occupied/lethal space - - -class OccupancyGrid(Timestamped): - """ - Convenience wrapper for nav_msgs/OccupancyGrid with numpy array support. - """ - - msg_name = "nav_msgs.OccupancyGrid" - - # Attributes - ts: float - frame_id: str - info: MapMetaData - grid: NDArray[np.int8] - - def __init__( - self, - grid: NDArray[np.int8] | None = None, - width: int | None = None, - height: int | None = None, - resolution: float = 0.05, - origin: Pose | None = None, - frame_id: str = "world", - ts: float | None = None, - ) -> None: - """Initialize OccupancyGrid. - - Args: - grid: 2D numpy array of int8 values (height x width) - width: Width in cells (used if grid is None) - height: Height in cells (used if grid is None) - resolution: Grid resolution in meters/cell - origin: Origin pose of the grid - frame_id: Reference frame - ts: Timestamp (defaults to current time if 0) - """ - - self.frame_id = frame_id - self.ts = time.time() if ts is None else ts - - if grid is not None: - # Initialize from numpy array - if grid.ndim != 2: - raise ValueError("Grid must be a 2D array") - height, width = grid.shape - self.info = MapMetaData( - map_load_time=self._to_lcm_time(), # type: ignore[no-untyped-call] - resolution=resolution, - width=width, - height=height, - origin=origin or Pose(), - ) - self.grid = grid.astype(np.int8) - elif width is not None and height is not None: - # Initialize with dimensions - self.info = MapMetaData( - map_load_time=self._to_lcm_time(), # type: ignore[no-untyped-call] - resolution=resolution, - width=width, - height=height, - origin=origin or Pose(), - ) - self.grid = np.full((height, width), -1, dtype=np.int8) - else: - # Initialize empty - self.info = MapMetaData(map_load_time=self._to_lcm_time()) # type: ignore[no-untyped-call] - self.grid = np.array([], dtype=np.int8) - - def _to_lcm_time(self): # type: ignore[no-untyped-def] - """Convert timestamp to LCM Time.""" - - s = int(self.ts) - return LCMTime(sec=s, nsec=int((self.ts - s) * 1_000_000_000)) - - @property - def width(self) -> int: - """Width of the grid in cells.""" - return self.info.width # type: ignore[no-any-return] - - @property - def height(self) -> int: - """Height of the grid in cells.""" - return self.info.height # type: ignore[no-any-return] - - @property - def resolution(self) -> float: - """Grid resolution in meters/cell.""" - return self.info.resolution # type: ignore[no-any-return] - - @property - def origin(self) -> Pose: - """Origin pose of the grid.""" - return self.info.origin # type: ignore[no-any-return] - - @property - def total_cells(self) -> int: - """Total number of cells in the grid.""" - return self.width * self.height - - @property - def occupied_cells(self) -> int: - """Number of occupied cells (value >= 1).""" - return int(np.sum(self.grid >= 1)) - - @property - def free_cells(self) -> int: - """Number of free cells (value == 0).""" - return int(np.sum(self.grid == 0)) - - @property - def unknown_cells(self) -> int: - """Number of unknown cells (value == -1).""" - return int(np.sum(self.grid == -1)) - - @property - def occupied_percent(self) -> float: - """Percentage of cells that are occupied.""" - return (self.occupied_cells / self.total_cells * 100) if self.total_cells > 0 else 0.0 - - @property - def free_percent(self) -> float: - """Percentage of cells that are free.""" - return (self.free_cells / self.total_cells * 100) if self.total_cells > 0 else 0.0 - - @property - def unknown_percent(self) -> float: - """Percentage of cells that are unknown.""" - return (self.unknown_cells / self.total_cells * 100) if self.total_cells > 0 else 0.0 - - @classmethod - def from_path(cls, path: Path) -> OccupancyGrid: - match path.suffix.lower(): - case ".npy": - return cls(grid=np.load(path)) - case ".png": - # Lazy import: Pillow serves only this file loader; message - # transport must not depend on it. - from PIL import Image - - img = Image.open(path).convert("L") - return cls(grid=np.array(img).astype(np.int8)) - case _: - raise NotImplementedError(f"Unsupported file format: {path.suffix}") - - def world_to_grid(self, point: VectorLike) -> Vector3: - """Convert world coordinates to grid coordinates. - - Args: - point: A vector-like object containing X,Y coordinates - - Returns: - Vector3 with grid coordinates - """ - positionVector = Vector3(point) - # Get origin position - ox = self.origin.position.x - oy = self.origin.position.y - - # Convert to grid coordinates (simplified, assuming no rotation) - grid_x = (positionVector.x - ox) / self.resolution - grid_y = (positionVector.y - oy) / self.resolution - - return Vector3(grid_x, grid_y, 0.0) - - def grid_to_world(self, grid_point: VectorLike) -> Vector3: - """Convert grid coordinates to world coordinates. - - Args: - grid_point: Vector-like object containing grid coordinates - - Returns: - World position as Vector3 - """ - gridVector = Vector3(grid_point) - # Get origin position - ox = self.origin.position.x - oy = self.origin.position.y - - # Convert to world (simplified, no rotation) - x = ox + gridVector.x * self.resolution - y = oy + gridVector.y * self.resolution - - return Vector3(x, y, 0.0) - - def __str__(self) -> str: - """Create a concise string representation.""" - origin_pos = self.origin.position - - parts = [ - f"▦ OccupancyGrid[{self.frame_id}]", - f"{self.width}x{self.height}", - f"({self.width * self.resolution:.1f}x{self.height * self.resolution:.1f}m @", - f"{1 / self.resolution:.0f}cm res)", - f"Origin: ({origin_pos.x:.2f}, {origin_pos.y:.2f})", - f"▣ {self.occupied_percent:.1f}%", - f"□ {self.free_percent:.1f}%", - f"◌ {self.unknown_percent:.1f}%", - ] - - return " ".join(parts) - - def __repr__(self) -> str: - """Create a detailed representation.""" - return ( - f"OccupancyGrid(width={self.width}, height={self.height}, " - f"resolution={self.resolution}, frame_id='{self.frame_id}', " - f"occupied={self.occupied_cells}, free={self.free_cells}, " - f"unknown={self.unknown_cells})" - ) - - def lcm_encode(self) -> bytes: - """Encode OccupancyGrid to LCM bytes.""" - # Create LCM message - lcm_msg = LCMOccupancyGrid() - - # Build header on demand - s = int(self.ts) - lcm_msg.header.stamp.sec = s - lcm_msg.header.stamp.nsec = int((self.ts - s) * 1_000_000_000) - lcm_msg.header.frame_id = self.frame_id - - # Copy map metadata - lcm_msg.info = self.info - - # Convert numpy array to flat data list - if self.grid.size > 0: - flat_data = self.grid.flatten() - lcm_msg.data_length = len(flat_data) - lcm_msg.data = flat_data.tolist() - else: - lcm_msg.data_length = 0 - lcm_msg.data = [] - - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes | BinaryIO) -> OccupancyGrid: - """Decode LCM bytes to OccupancyGrid.""" - lcm_msg = LCMOccupancyGrid.lcm_decode(data) - - # Extract timestamp and frame_id from header - ts = lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000) - frame_id = lcm_msg.header.frame_id - - # Extract grid data; empty stays 2-D so the constructor accepts it. - if lcm_msg.data and lcm_msg.info.width > 0 and lcm_msg.info.height > 0: - grid = np.array(lcm_msg.data, dtype=np.int8).reshape( - (lcm_msg.info.height, lcm_msg.info.width) - ) - else: - grid = np.zeros((0, 0), dtype=np.int8) - - # The wire origin decodes as a plain generated pose without the dimos - # Pose surface (.yaw etc.); rebuild it field by field so the origin - # property honors its declared type. - o = lcm_msg.info.origin - lcm_msg.info.origin = Pose( - position=[o.position.x, o.position.y, o.position.z], - orientation=[o.orientation.x, o.orientation.y, o.orientation.z, o.orientation.w], - ) - - # Create new instance - instance = cls( - grid=grid, - resolution=lcm_msg.info.resolution, - origin=lcm_msg.info.origin, - frame_id=frame_id, - ts=ts, - ) - instance.info = lcm_msg.info - return instance - - def filter_above(self, threshold: int) -> OccupancyGrid: - """Create a new OccupancyGrid with only values above threshold. - - Args: - threshold: Keep cells with values > threshold - - Returns: - New OccupancyGrid where: - - Cells > threshold: kept as-is - - Cells <= threshold: set to -1 (unknown) - - Unknown cells (-1): preserved - """ - new_grid = self.grid.copy() - - # Create mask for cells to filter (not unknown and <= threshold) - filter_mask = (new_grid != -1) & (new_grid <= threshold) - - # Set filtered cells to unknown - new_grid[filter_mask] = -1 - - # Create new OccupancyGrid - filtered = OccupancyGrid( - new_grid, - resolution=self.resolution, - origin=self.origin, - frame_id=self.frame_id, - ts=self.ts, - ) - - return filtered - - def filter_below(self, threshold: int) -> OccupancyGrid: - """Create a new OccupancyGrid with only values below threshold. - - Args: - threshold: Keep cells with values < threshold - - Returns: - New OccupancyGrid where: - - Cells < threshold: kept as-is - - Cells >= threshold: set to -1 (unknown) - - Unknown cells (-1): preserved - """ - new_grid = self.grid.copy() - - # Create mask for cells to filter (not unknown and >= threshold) - filter_mask = (new_grid != -1) & (new_grid >= threshold) - - # Set filtered cells to unknown - new_grid[filter_mask] = -1 - - # Create new OccupancyGrid - filtered = OccupancyGrid( - new_grid, - resolution=self.resolution, - origin=self.origin, - frame_id=self.frame_id, - ts=self.ts, - ) - - return filtered - - def max(self) -> OccupancyGrid: - """Create a new OccupancyGrid with all non-unknown cells set to maximum value. - - Returns: - New OccupancyGrid where: - - All non-unknown cells: set to CostValues.OCCUPIED (100) - - Unknown cells: preserved as CostValues.UNKNOWN (-1) - """ - new_grid = self.grid.copy() - - # Set all non-unknown cells to max - new_grid[new_grid != CostValues.UNKNOWN] = CostValues.OCCUPIED - - # Create new OccupancyGrid - maxed = OccupancyGrid( - new_grid, - resolution=self.resolution, - origin=self.origin, - frame_id=self.frame_id, - ts=self.ts, - ) - - return maxed - - def copy(self) -> OccupancyGrid: - """Create a deep copy of the OccupancyGrid. - - Returns: - A new OccupancyGrid instance with copied data. - """ - return OccupancyGrid( - grid=self.grid.copy(), - resolution=self.resolution, - origin=self.origin, - frame_id=self.frame_id, - ts=self.ts, - ) - - def cell_value(self, world_position: Vector3) -> int: - grid_position = self.world_to_grid(world_position) - x = int(grid_position.x) - y = int(grid_position.y) - - if not (0 <= x < self.width and 0 <= y < self.height): - return CostValues.UNKNOWN - - return int(self.grid[y, x]) - - def to_rerun( - self, - colormap: str | None = None, - z_offset: float = 0, - opacity: float = 1.0, - cost_range: tuple[int, int] | None = None, - background: str | None = None, - color_lookup_table: np.ndarray | None = None, - ) -> Archetype: - """Convert to 3D textured mesh overlay on floor plane. - - Uses a single quad with the occupancy grid as a texture. - Much more efficient than per-cell quads (4 vertices vs n_cells*4). - """ - import rerun as rr - - if self.grid.size == 0: - return rr.Mesh3D(vertex_positions=[]) - - # Downsample grid before LUT to avoid allocating huge RGBA array - max_tex = 256 - grid = self.grid[::-1] # flip for world coords (view, no copy) - if grid.shape[0] > max_tex or grid.shape[1] > max_tex: - step_h = max(1, grid.shape[0] // max_tex) - step_w = max(1, grid.shape[1] // max_tex) - grid = grid[::step_h, ::step_w] - - if color_lookup_table is None: - color_lookup_table = _build_occupancy_lut(colormap, opacity, background) - rgba = np.ascontiguousarray(color_lookup_table[np.clip(grid + 1, 0, 101)]) - - # Apply cost_range filter on downsampled grid - if cost_range is not None: - out_of_range = ((grid < cost_range[0]) | (grid > cost_range[1])) & (grid != -1) - if np.any(out_of_range): - bg_rgb = [0, 0, 0] - if background is not None: - bg = background.lstrip("#") - bg_rgb = [int(bg[i : i + 2], 16) for i in (0, 2, 4)] - rgba[out_of_range, :3] = bg_rgb - rgba[out_of_range, 3] = 255 - - # Single quad covering entire grid - ox = self.origin.position.x - oy = self.origin.position.y - w = self.width * self.resolution - h = self.height * self.resolution - - vertices = np.array( - [ - [ox, oy, z_offset], # 0: bottom-left (world) - [ox + w, oy, z_offset], # 1: bottom-right - [ox + w, oy + h, z_offset], # 2: top-right - [ox, oy + h, z_offset], # 3: top-left - ], - dtype=np.float32, - ) - - indices = np.array([[0, 1, 2], [0, 2, 3]], dtype=np.uint32) - - # UV coords: Rerun uses top-left origin for textures - # Grid row 0 is at world y=oy (bottom), row H-1 at y=oy+h (top) - # Texture row 0 = grid row 0, so: - # world bottom (v0,v1) -> texture v=1 (bottom of texture) - # world top (v2,v3) -> texture v=0 (top of texture) - texcoords = np.array( - [ - [0.0, 1.0], # v0: bottom-left world -> bottom-left tex - [1.0, 1.0], # v1: bottom-right world -> bottom-right tex - [1.0, 0.0], # v2: top-right world -> top-right tex - [0.0, 0.0], # v3: top-left world -> top-left tex - ], - dtype=np.float32, - ) - - return rr.Mesh3D( - vertex_positions=vertices, - triangle_indices=indices, - vertex_texcoords=texcoords, - albedo_texture=rgba, - ) diff --git a/dimos/msgs/nav_msgs/Odometry.py b/dimos/msgs/nav_msgs/Odometry.py deleted file mode 100644 index 5e986672ea9..00000000000 --- a/dimos/msgs/nav_msgs/Odometry.py +++ /dev/null @@ -1,249 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import time -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from rerun._baseclasses import Archetype - -from dimos_lcm.nav_msgs import Odometry as LCMOdometry -import numpy as np - -from dimos.msgs.geometry_msgs.Pose import Pose -from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped -from dimos.msgs.geometry_msgs.PoseWithCovariance import PoseWithCovariance -from dimos.msgs.geometry_msgs.Twist import Twist -from dimos.msgs.geometry_msgs.TwistWithCovariance import TwistWithCovariance -from dimos.types.timestamped import Timestamped - -if TYPE_CHECKING: - from dimos.msgs.geometry_msgs.Quaternion import Quaternion - from dimos.msgs.geometry_msgs.Vector3 import Vector3 - - -class Odometry(Timestamped): - """Odometry message with pose, twist, and frame information.""" - - msg_name = "nav_msgs.Odometry" - - def __init__( - self, - ts: float | None = None, - frame_id: str = "", - child_frame_id: str = "", - pose: PoseWithCovariance | Pose | None = None, - twist: TwistWithCovariance | Twist | None = None, - ) -> None: - self.ts = time.time() if ts is None else ts - self.frame_id = frame_id - self.child_frame_id = child_frame_id - - if pose is None: - self.pose = PoseWithCovariance() - elif isinstance(pose, Pose): - self.pose = PoseWithCovariance(pose) - else: - self.pose = pose - - if twist is None: - self.twist = TwistWithCovariance() - elif isinstance(twist, Twist): - self.twist = TwistWithCovariance(twist) - else: - self.twist = twist - - # -- Convenience properties -- - - @property - def position(self) -> Vector3: - return self.pose.position - - @property - def orientation(self) -> Quaternion: - return self.pose.orientation - - @property - def linear_velocity(self) -> Vector3: - return self.twist.linear - - @property - def angular_velocity(self) -> Vector3: - return self.twist.angular - - @property - def x(self) -> float: - return self.pose.x - - @property - def y(self) -> float: - return self.pose.y - - @property - def z(self) -> float: - return self.pose.z - - @property - def vx(self) -> float: - return self.twist.linear.x - - @property - def vy(self) -> float: - return self.twist.linear.y - - @property - def vz(self) -> float: - return self.twist.linear.z - - @property - def wx(self) -> float: - return self.twist.angular.x - - @property - def wy(self) -> float: - return self.twist.angular.y - - @property - def wz(self) -> float: - return self.twist.angular.z - - @property - def roll(self) -> float: - return self.pose.roll - - @property - def pitch(self) -> float: - return self.pose.pitch - - @property - def yaw(self) -> float: - return self.pose.yaw - - def to_pose_stamped(self) -> PoseStamped: - return PoseStamped( - ts=self.ts, - frame_id=self.frame_id, - position=[self.position.x, self.position.y, self.position.z], - orientation=[ - self.orientation.x, - self.orientation.y, - self.orientation.z, - self.orientation.w, - ], - ) - - # -- Serialization -- - - def lcm_encode(self) -> bytes: - lcm_msg = LCMOdometry() - - lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec = self.ros_timestamp() - lcm_msg.header.frame_id = self.frame_id - lcm_msg.child_frame_id = self.child_frame_id - - lcm_msg.pose.pose = self.pose.pose - lcm_msg.pose.covariance = list(np.asarray(self.pose.covariance)) - - lcm_msg.twist.twist = self.twist.twist - lcm_msg.twist.covariance = list(np.asarray(self.twist.covariance)) - - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes) -> Odometry: - lcm_msg = LCMOdometry.lcm_decode(data) - - ts = lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000) - - pose = Pose( - position=[ - lcm_msg.pose.pose.position.x, - lcm_msg.pose.pose.position.y, - lcm_msg.pose.pose.position.z, - ], - orientation=[ - lcm_msg.pose.pose.orientation.x, - lcm_msg.pose.pose.orientation.y, - lcm_msg.pose.pose.orientation.z, - lcm_msg.pose.pose.orientation.w, - ], - ) - twist = Twist( - linear=[ - lcm_msg.twist.twist.linear.x, - lcm_msg.twist.twist.linear.y, - lcm_msg.twist.twist.linear.z, - ], - angular=[ - lcm_msg.twist.twist.angular.x, - lcm_msg.twist.twist.angular.y, - lcm_msg.twist.twist.angular.z, - ], - ) - - return cls( - ts=ts, - frame_id=lcm_msg.header.frame_id, - child_frame_id=lcm_msg.child_frame_id, - pose=PoseWithCovariance(pose, lcm_msg.pose.covariance), - twist=TwistWithCovariance(twist, lcm_msg.twist.covariance), - ) - - # -- Comparison / display -- - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Odometry): - return False - return ( - abs(self.ts - other.ts) < 1e-6 - and self.frame_id == other.frame_id - and self.child_frame_id == other.child_frame_id - and self.pose == other.pose - and self.twist == other.twist - ) - - def __repr__(self) -> str: - return ( - f"Odometry(ts={self.ts:.6f}, frame_id='{self.frame_id}', " - f"child_frame_id='{self.child_frame_id}', pose={self.pose!r}, twist={self.twist!r})" - ) - - def __str__(self) -> str: - return ( - f"Odometry:\n" - f" Timestamp: {self.ts:.6f}\n" - f" Frame: {self.frame_id} -> {self.child_frame_id}\n" - f" Position: [{self.x:.3f}, {self.y:.3f}, {self.z:.3f}]\n" - f" Orientation: [roll={self.roll:.3f}, pitch={self.pitch:.3f}, yaw={self.yaw:.3f}]\n" - f" Linear Velocity: [{self.vx:.3f}, {self.vy:.3f}, {self.vz:.3f}]\n" - f" Angular Velocity: [{self.wx:.3f}, {self.wy:.3f}, {self.wz:.3f}]" - ) - - def to_rerun(self) -> Archetype: - """Convert to rerun Transform3D for visualizing the pose.""" - import rerun as rr - - return rr.Transform3D( - translation=[self.x, self.y, self.z], - rotation=rr.Quaternion( - xyzw=[ - self.orientation.x, - self.orientation.y, - self.orientation.z, - self.orientation.w, - ] - ), - ) diff --git a/dimos/msgs/nav_msgs/Path.py b/dimos/msgs/nav_msgs/Path.py deleted file mode 100644 index cd901f2a06f..00000000000 --- a/dimos/msgs/nav_msgs/Path.py +++ /dev/null @@ -1,214 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import time -from typing import TYPE_CHECKING, BinaryIO - -from dimos_lcm.geometry_msgs import ( - Point as LCMPoint, - Pose as LCMPose, - PoseStamped as LCMPoseStamped, - Quaternion as LCMQuaternion, -) -from dimos_lcm.nav_msgs import Path as LCMPath -from dimos_lcm.std_msgs import Header as LCMHeader, Time as LCMTime - -from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped -from dimos.types.timestamped import Timestamped - -if TYPE_CHECKING: - from collections.abc import Iterator - - from rerun._baseclasses import Archetype - - -def sec_nsec(ts): # type: ignore[no-untyped-def] - s = int(ts) - return [s, int((ts - s) * 1_000_000_000)] - - -class Path(Timestamped): - msg_name = "nav_msgs.Path" - ts: float - frame_id: str - poses: list[PoseStamped] - - def __init__( # type: ignore[no-untyped-def] - self, - ts: float | None = None, - frame_id: str = "world", - poses: list[PoseStamped] | None = None, - **kwargs, - ) -> None: - self.frame_id = frame_id - self.ts = time.time() if ts is None else ts - self.poses = poses if poses is not None else [] - - def __len__(self) -> int: - """Return the number of poses in the path.""" - return len(self.poses) - - def __bool__(self) -> bool: - """Return True if path has poses.""" - return len(self.poses) > 0 - - def head(self) -> PoseStamped | None: - """Return the first pose in the path, or None if empty.""" - return self.poses[0] if self.poses else None - - def last(self) -> PoseStamped | None: - """Return the last pose in the path, or None if empty.""" - return self.poses[-1] if self.poses else None - - def tail(self) -> Path: - """Return a new Path with all poses except the first.""" - return Path(ts=self.ts, frame_id=self.frame_id, poses=self.poses[1:] if self.poses else []) - - def push(self, pose: PoseStamped) -> Path: - """Return a new Path with the pose appended (immutable).""" - return Path(ts=self.ts, frame_id=self.frame_id, poses=[*self.poses, pose]) - - def push_mut(self, pose: PoseStamped) -> None: - """Append a pose to this path (mutable).""" - self.poses.append(pose) - - def lcm_encode(self) -> bytes: - """Encode Path to LCM bytes.""" - lcm_msg = LCMPath() - - # Set poses - lcm_msg.poses_length = len(self.poses) - lcm_poses = [] # Build list separately to avoid LCM library reuse issues - for pose in self.poses: - lcm_pose = LCMPoseStamped() - # Create new pose objects to avoid LCM library reuse bug - lcm_pose.pose = LCMPose() - lcm_pose.pose.position = LCMPoint() - lcm_pose.pose.orientation = LCMQuaternion() - - # Set the pose geometry data - lcm_pose.pose.position.x = pose.x - lcm_pose.pose.position.y = pose.y - lcm_pose.pose.position.z = pose.z - lcm_pose.pose.orientation.x = pose.orientation.x - lcm_pose.pose.orientation.y = pose.orientation.y - lcm_pose.pose.orientation.z = pose.orientation.z - lcm_pose.pose.orientation.w = pose.orientation.w - - # Create new header to avoid reuse - lcm_pose.header = LCMHeader() - lcm_pose.header.stamp = LCMTime() - - # Set the header with pose timestamp but path's frame_id - [lcm_pose.header.stamp.sec, lcm_pose.header.stamp.nsec] = sec_nsec(pose.ts) # type: ignore[no-untyped-call] - lcm_pose.header.frame_id = self.frame_id # All poses use path's frame_id - lcm_poses.append(lcm_pose) - lcm_msg.poses = lcm_poses - - # Set header with path's own timestamp - [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] - lcm_msg.header.frame_id = self.frame_id - - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes | BinaryIO) -> Path: - """Decode LCM bytes to Path.""" - lcm_msg = LCMPath.lcm_decode(data) - - # Decode header - header_ts = lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000) - frame_id = lcm_msg.header.frame_id - - # Decode poses - all use the path's frame_id - poses = [] - for lcm_pose in lcm_msg.poses: - pose = PoseStamped( - ts=lcm_pose.header.stamp.sec + (lcm_pose.header.stamp.nsec / 1_000_000_000), - frame_id=frame_id, # Use path's frame_id for all poses - position=[ - lcm_pose.pose.position.x, - lcm_pose.pose.position.y, - lcm_pose.pose.position.z, - ], - orientation=[ - lcm_pose.pose.orientation.x, - lcm_pose.pose.orientation.y, - lcm_pose.pose.orientation.z, - lcm_pose.pose.orientation.w, - ], - ) - poses.append(pose) - - # Use header timestamp for the path - return cls(ts=header_ts, frame_id=frame_id, poses=poses) - - def __str__(self) -> str: - """String representation of Path.""" - return f"Path(frame_id='{self.frame_id}', poses={len(self.poses)})" - - def __getitem__(self, index: int | slice) -> PoseStamped | list[PoseStamped]: - """Allow indexing and slicing of poses.""" - return self.poses[index] - - def __iter__(self) -> Iterator: # type: ignore[type-arg] - """Allow iteration over poses.""" - return iter(self.poses) - - def slice(self, start: int, end: int | None = None) -> Path: - """Return a new Path with a slice of poses.""" - return Path(ts=self.ts, frame_id=self.frame_id, poses=self.poses[start:end]) - - def extend(self, other: Path) -> Path: - """Return a new Path with poses from both paths (immutable).""" - return Path(ts=self.ts, frame_id=self.frame_id, poses=self.poses + other.poses) - - def extend_mut(self, other: Path) -> None: - """Extend this path with poses from another path (mutable).""" - self.poses.extend(other.poses) - - def reverse(self) -> Path: - """Return a new Path with poses in reverse order.""" - return Path(ts=self.ts, frame_id=self.frame_id, poses=list(reversed(self.poses))) - - def clear(self) -> None: - """Clear all poses from this path (mutable).""" - self.poses.clear() - - def to_rerun( - self, - color: tuple[int, int, int] = (0, 255, 128), - z_offset: float = 0.5, - radii: float = 0.05, - ) -> Archetype: - """Convert to rerun LineStrips3D format. - - Args: - color: RGB color tuple for the path line - z_offset: Height above floor to render path (default 0.2m to avoid costmap occlusion) - radii: Thickness of the path line (default 0.05m = 5cm) - - Returns: - rr.LineStrips3D archetype for logging to rerun - """ - import rerun as rr - - if not self.poses: - return rr.LineStrips3D([]) - - # Lift path above floor so it's visible over costmap - points = [[p.x, p.y, p.z + z_offset] for p in self.poses] - return rr.LineStrips3D([points], colors=[color], radii=radii) diff --git a/dimos/msgs/sensor_msgs/CompressedImage.py b/dimos/msgs/sensor_msgs/CompressedImage.py deleted file mode 100644 index f1853986fc5..00000000000 --- a/dimos/msgs/sensor_msgs/CompressedImage.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from dataclasses import dataclass, field -import time -from typing import TYPE_CHECKING, Any, Literal - -from dimos_lcm.sensor_msgs.CompressedImage import CompressedImage as LCMCompressedImage -from dimos_lcm.std_msgs.Header import Header - -from dimos.types.timestamped import Timestamped, to_human_readable - -# cv2/turbojpeg/Image are imported lazily so this module stays cheap for -# byte-level consumers that never encode or decode pixels. -if TYPE_CHECKING: - from dimos.msgs.sensor_msgs.Image import Image - -CompressionFormat = Literal["jpeg", "png", "jxl"] - - -@dataclass -class CompressedImage(Timestamped): - """Compressed image bytes (JPEG/PNG/JPEG-XL) — ROS sensor_msgs/CompressedImage.""" - - msg_name = "sensor_msgs.CompressedImage" - - data: bytes = b"" - format: str = "jpeg" - frame_id: str = "" - ts: float = field(default_factory=time.time) - - def __str__(self) -> str: - return ( - f"CompressedImage(format={self.format}, bytes={len(self.data)}, " - f"ts={to_human_readable(self.ts)})" - ) - - @classmethod - def from_image( - cls, - image: Image, - format: CompressionFormat = "jpeg", - quality: int = 75, - max_width: int | None = None, - effort: int | None = None, - ) -> CompressedImage: - """Encode a raw Image. - - JPEG rejects 16-bit/depth formats; PNG rejects float depth. JXL takes - everything: lossless for 16-bit/float data (depth must survive the wire - exactly), `quality` for uint8. `effort` (jxl only, 1-9) trades encode - cpu for size; defaults are pinned for camera-rate streaming. - """ - from dimos.msgs.sensor_msgs.Image import Image, ImageFormat - - if not isinstance(image, Image): - raise TypeError(f"from_image expects Image, got {type(image).__name__}") - if max_width is not None: - image, _ = image.resize_to_fit(max_width, max_width) - if format == "jpeg": - if image.format in (ImageFormat.GRAY16, ImageFormat.DEPTH, ImageFormat.DEPTH16): - raise ValueError(f"JPEG cannot encode {image.format.value}; use format='png'") - data = image.to_jpeg_bytes(quality=quality) - elif format == "png": - import cv2 - - if image.format in (ImageFormat.DEPTH, ImageFormat.DEPTH16): - raise ValueError(f"PNG cannot encode {image.format.value}") - arr = image.data if image.channels == 1 else image.to_bgr().data - ok, buf = cv2.imencode(".png", arr) - if not ok: - raise ValueError("PNG encoding failed") - data = buf.tobytes() - elif format == "jxl": - import imagecodecs - import numpy as np - - # zero-copy passthrough unless channel order actually needs fixing - if image.channels == 1 or image.format is ImageFormat.RGB: - arr = image.data - else: - arr = image.to_rgb().data - if arr.dtype not in (np.uint8, np.uint16, np.float32): - raise ValueError(f"JXL cannot encode dtype {arr.dtype}") - arr = np.ascontiguousarray(arr) - # libjxl's default effort=7 costs 83-300ms per 720p frame; these - # pins keep camera-rate (13ms lossy / 3ms lossless) for ~5% size - if arr.dtype == np.uint8: - data = bytes(imagecodecs.jpegxl_encode(arr, level=quality, effort=effort or 3)) - else: - data = bytes(imagecodecs.jpegxl_encode(arr, lossless=True, effort=effort or 1)) - else: - raise ValueError(f"unsupported format {format!r}") - return cls(data=data, format=format, frame_id=image.frame_id, ts=image.ts) - - def decode(self) -> Image: - """Decompress to a raw Image; ts/frame_id preserved.""" - from dimos.msgs.sensor_msgs.Image import Image, ImageFormat - - if self.format.startswith("jpeg"): - from turbojpeg import TJPF_RGB, TurboJPEG - - arr = TurboJPEG().decode(self.data, pixel_format=TJPF_RGB) - fmt = ImageFormat.RGB - elif self.format.startswith("png"): - import cv2 - import numpy as np - - arr = cv2.imdecode(np.frombuffer(self.data, dtype=np.uint8), cv2.IMREAD_UNCHANGED) - if arr is None: - raise ValueError("PNG decoding failed") - if arr.ndim == 2: - fmt = ImageFormat.GRAY16 if arr.dtype == np.uint16 else ImageFormat.GRAY - elif arr.shape[2] == 4: - fmt = ImageFormat.BGRA - else: - fmt = ImageFormat.BGR - elif self.format.startswith("jxl"): - import imagecodecs - import numpy as np - - arr = imagecodecs.jpegxl_decode(self.data) - if arr.ndim == 2: - fmt = {np.float32: ImageFormat.DEPTH, np.uint16: ImageFormat.GRAY16}.get( - arr.dtype.type, ImageFormat.GRAY - ) - else: - fmt = ImageFormat.RGBA if arr.shape[2] == 4 else ImageFormat.RGB - else: - raise ValueError(f"unsupported format {self.format!r}") - return Image(data=arr, format=fmt, frame_id=self.frame_id, ts=self.ts) - - def lcm_encode(self, frame_id: str | None = None) -> bytes: - msg = LCMCompressedImage() - msg.header = Header() - msg.header.seq = 0 - msg.header.frame_id = frame_id or self.frame_id - msg.header.stamp.sec = int(self.ts) - msg.header.stamp.nsec = int((self.ts - int(self.ts)) * 1e9) - msg.format = self.format - msg.data = self.data - msg.data_length = len(self.data) - return msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes, **kwargs: Any) -> CompressedImage: - msg = LCMCompressedImage.lcm_decode(data) - return cls( - data=bytes(msg.data), - format=msg.format, - frame_id=msg.header.frame_id, - ts=msg.header.stamp.sec + msg.header.stamp.nsec / 1e9, - ) - - def to_rerun(self) -> Any: - import rerun as rr - - if self.format.startswith(("jpeg", "png")): - media_type = "image/jpeg" if self.format.startswith("jpeg") else "image/png" - return rr.EncodedImage(contents=self.data, media_type=media_type) - # formats rerun's EncodedImage can't decode: send pixels instead - return self.decode().to_rerun() diff --git a/dimos/msgs/sensor_msgs/Image.py b/dimos/msgs/sensor_msgs/Image.py deleted file mode 100644 index 05b05225757..00000000000 --- a/dimos/msgs/sensor_msgs/Image.py +++ /dev/null @@ -1,700 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import base64 -from dataclasses import dataclass, field -from enum import Enum -import time -from typing import TYPE_CHECKING, Any, Literal, TypedDict -import warnings - -from dimos_lcm.sensor_msgs.Image import Image as LCMImage -from dimos_lcm.std_msgs.Header import Header -import numpy as np -import reactivex as rx -from reactivex import operators as ops -from turbojpeg import TJPF_RGB - -from dimos.types.timestamped import Timestamped, TimestampedBufferCollection, to_human_readable -from dimos.utils.reactive import quality_barrier -from dimos.utils.turbojpeg import get_turbojpeg - -if TYPE_CHECKING: - from collections.abc import Callable - import os - - from reactivex.abc import SchedulerBase - from reactivex.observable import Observable - - -class ImageFormat(Enum): - BGR = "BGR" - RGB = "RGB" - RGBA = "RGBA" - BGRA = "BGRA" - GRAY = "GRAY" - GRAY16 = "GRAY16" - DEPTH = "DEPTH" - DEPTH16 = "DEPTH16" - - -class AgentImageMessage(TypedDict): - """Type definition for agent-compatible image representation.""" - - type: Literal["image"] - source_type: Literal["base64"] - mime_type: Literal["image/jpeg", "image/png"] - data: str # Base64 encoded image data - - -@dataclass -class Image(Timestamped): - """Simple NumPy-based image container.""" - - msg_name = "sensor_msgs.Image" - - data: np.ndarray[Any, np.dtype[Any]] = field( - default_factory=lambda: np.zeros((1, 1, 3), dtype=np.uint8) - ) - format: ImageFormat = field(default=ImageFormat.BGR) - frame_id: str = field(default="") - ts: float = field(default_factory=time.time) - - def __post_init__(self) -> None: - if not isinstance(self.data, np.ndarray): - self.data = np.asarray(self.data) - if self.data.ndim < 2: - raise ValueError("Image requires a 2D/3D NumPy array") - - def __str__(self) -> str: - return ( - f"Image(shape={self.shape}, format={self.format.value}, dtype={self.dtype}, " - f"ts={to_human_readable(self.ts)})" - ) - - def __repr__(self) -> str: - return f"Image(shape={self.shape}, format={self.format.value}, dtype={self.dtype}, frame_id='{self.frame_id}', ts={self.ts})" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Image): - return False - return ( - np.array_equal(self.data, other.data) - and self.format == other.format - and self.frame_id == other.frame_id - and abs(self.ts - other.ts) < 1e-6 - ) - - def __len__(self) -> int: - return int(self.height * self.width) - - def __getstate__(self) -> dict[str, Any]: - return {"data": self.data, "format": self.format, "frame_id": self.frame_id, "ts": self.ts} - - def __setstate__(self, state: dict[str, Any]) -> None: - self.data = state.get("data", np.zeros((1, 1, 3), dtype=np.uint8)) - self.format = state.get("format", ImageFormat.BGR) - self.frame_id = state.get("frame_id", "") - self.ts = state.get("ts", time.time()) - - @property - def height(self) -> int: - return int(self.data.shape[0]) - - @property - def width(self) -> int: - return int(self.data.shape[1]) - - @property - def channels(self) -> int: - if self.data.ndim == 2: - return 1 - if self.data.ndim == 3: - return int(self.data.shape[2]) - raise ValueError("Invalid image dimensions") - - @property - def shape(self) -> tuple[int, ...]: - return tuple(self.data.shape) - - @property - def dtype(self) -> np.dtype[Any]: - return self.data.dtype - - def copy(self) -> Image: - return Image(data=self.data.copy(), format=self.format, frame_id=self.frame_id, ts=self.ts) - - @classmethod - def from_numpy( - cls, - np_image: np.ndarray, - format: ImageFormat = ImageFormat.BGR, - frame_id: str = "", - ts: float | None = None, - ) -> Image: - return cls( - data=np.asarray(np_image), - format=format, - frame_id=frame_id, - ts=ts if ts is not None else time.time(), - ) - - @classmethod - def from_file( - cls, - filepath: str | os.PathLike[str], - format: ImageFormat = ImageFormat.RGB, - ) -> Image: - import cv2 - - arr = cv2.imread(str(filepath), cv2.IMREAD_UNCHANGED) - if arr is None: - raise ValueError(f"Could not load image from {filepath}") - if arr.ndim == 2: - detected = ImageFormat.GRAY16 if arr.dtype == np.uint16 else ImageFormat.GRAY - elif arr.shape[2] == 3: - detected = ImageFormat.BGR # OpenCV default - elif arr.shape[2] == 4: - detected = ImageFormat.BGRA # OpenCV default - else: - detected = format - return cls(data=arr, format=detected) - - @classmethod - def from_opencv( - cls, - cv_image: np.ndarray, - format: ImageFormat = ImageFormat.BGR, - frame_id: str = "", - ts: float | None = None, - ) -> Image: - """Construct from an OpenCV image (NumPy array).""" - return cls( - data=cv_image, - format=format, - frame_id=frame_id, - ts=ts if ts is not None else time.time(), - ) - - def to_opencv(self) -> np.ndarray: - """Convert to OpenCV BGR format.""" - import cv2 - - arr = self.data - if self.format == ImageFormat.BGR: - return arr - if self.format == ImageFormat.RGB: - return cv2.cvtColor(arr, cv2.COLOR_RGB2BGR) - if self.format == ImageFormat.RGBA: - return cv2.cvtColor(arr, cv2.COLOR_RGBA2BGR) - if self.format == ImageFormat.BGRA: - return cv2.cvtColor(arr, cv2.COLOR_BGRA2BGR) - if self.format in ( - ImageFormat.GRAY, - ImageFormat.GRAY16, - ImageFormat.DEPTH, - ImageFormat.DEPTH16, - ): - return arr - raise ValueError(f"Unsupported format: {self.format}") - - def as_numpy(self) -> np.ndarray: - """Get image data as numpy array.""" - return self.data - - def to_rgb(self) -> Image: - import cv2 - - if self.format == ImageFormat.RGB: - return self.copy() - arr = self.data - if self.format == ImageFormat.BGR: - return Image( - data=cv2.cvtColor(arr, cv2.COLOR_BGR2RGB), - format=ImageFormat.RGB, - frame_id=self.frame_id, - ts=self.ts, - ) - if self.format == ImageFormat.RGBA: - warnings.warn("to_rgb() drops alpha channel from RGBA image", stacklevel=2) - return Image( - data=cv2.cvtColor(arr, cv2.COLOR_RGBA2RGB), - format=ImageFormat.RGB, - frame_id=self.frame_id, - ts=self.ts, - ) - if self.format == ImageFormat.BGRA: - warnings.warn("to_rgb() drops alpha channel from BGRA image", stacklevel=2) - return Image( - data=cv2.cvtColor(arr, cv2.COLOR_BGRA2RGB), - format=ImageFormat.RGB, - frame_id=self.frame_id, - ts=self.ts, - ) - if self.format in (ImageFormat.GRAY, ImageFormat.GRAY16, ImageFormat.DEPTH16): - gray8 = (arr / 256).astype(np.uint8) if self.format != ImageFormat.GRAY else arr - rgb = cv2.cvtColor(gray8, cv2.COLOR_GRAY2RGB) - return Image(data=rgb, format=ImageFormat.RGB, frame_id=self.frame_id, ts=self.ts) - return self.copy() - - def to_bgr(self) -> Image: - import cv2 - - if self.format == ImageFormat.BGR: - return self.copy() - arr = self.data - if self.format == ImageFormat.RGB: - return Image( - data=cv2.cvtColor(arr, cv2.COLOR_RGB2BGR), - format=ImageFormat.BGR, - frame_id=self.frame_id, - ts=self.ts, - ) - if self.format == ImageFormat.RGBA: - warnings.warn("to_bgr() drops alpha channel from RGBA image", stacklevel=2) - return Image( - data=cv2.cvtColor(arr, cv2.COLOR_RGBA2BGR), - format=ImageFormat.BGR, - frame_id=self.frame_id, - ts=self.ts, - ) - if self.format == ImageFormat.BGRA: - warnings.warn("to_bgr() drops alpha channel from BGRA image", stacklevel=2) - return Image( - data=cv2.cvtColor(arr, cv2.COLOR_BGRA2BGR), - format=ImageFormat.BGR, - frame_id=self.frame_id, - ts=self.ts, - ) - if self.format in (ImageFormat.GRAY, ImageFormat.GRAY16, ImageFormat.DEPTH16): - gray8 = (arr / 256).astype(np.uint8) if self.format != ImageFormat.GRAY else arr - return Image( - data=cv2.cvtColor(gray8, cv2.COLOR_GRAY2BGR), - format=ImageFormat.BGR, - frame_id=self.frame_id, - ts=self.ts, - ) - return self.copy() - - def to_grayscale(self) -> Image: - import cv2 - - if self.format in (ImageFormat.GRAY, ImageFormat.GRAY16, ImageFormat.DEPTH): - return self.copy() - if self.format == ImageFormat.BGR: - return Image( - data=cv2.cvtColor(self.data, cv2.COLOR_BGR2GRAY), - format=ImageFormat.GRAY, - frame_id=self.frame_id, - ts=self.ts, - ) - if self.format == ImageFormat.RGB: - return Image( - data=cv2.cvtColor(self.data, cv2.COLOR_RGB2GRAY), - format=ImageFormat.GRAY, - frame_id=self.frame_id, - ts=self.ts, - ) - if self.format in (ImageFormat.RGBA, ImageFormat.BGRA): - code = cv2.COLOR_RGBA2GRAY if self.format == ImageFormat.RGBA else cv2.COLOR_BGRA2GRAY - return Image( - data=cv2.cvtColor(self.data, code), - format=ImageFormat.GRAY, - frame_id=self.frame_id, - ts=self.ts, - ) - raise ValueError(f"Unsupported format: {self.format}") - - def to_rerun(self) -> Any: - """Convert to a Rerun archetype: JPEG-encoded for color images, raw for depth.""" - import rerun as rr - - match self.format: - case ImageFormat.DEPTH | ImageFormat.DEPTH16: - return rr.DepthImage(self.data) - case ImageFormat.GRAY16: - return rr.Image(self.data, color_model="L") - case _: - return rr.EncodedImage(contents=self.to_jpeg_bytes(), media_type="image/jpeg") - - def resize(self, width: int, height: int, interpolation: int | None = None) -> Image: - import cv2 - - if interpolation is None: - interpolation = cv2.INTER_LINEAR - return Image( - data=cv2.resize(self.data, (width, height), interpolation=interpolation), - format=self.format, - frame_id=self.frame_id, - ts=self.ts, - ) - - def resize_to_fit( - self, max_width: int, max_height: int, interpolation: int | None = None - ) -> tuple[Image, float]: - """Resize image to fit within max dimensions while preserving aspect ratio. - - Only scales down if image exceeds max dimensions. Returns self if already fits. - - Returns: - Tuple of (resized_image, scale_factor). Scale factor is 1.0 if no resize needed. - """ - if self.width <= max_width and self.height <= max_height: - return self, 1.0 - - scale = min(max_width / self.width, max_height / self.height) - new_width = int(self.width * scale) - new_height = int(self.height * scale) - return self.resize(new_width, new_height, interpolation), scale - - def crop(self, x: int, y: int, width: int, height: int) -> Image: - """Crop the image to the specified region. - - Args: - x: Starting x coordinate (left edge) - y: Starting y coordinate (top edge) - width: Width of the cropped region - height: Height of the cropped region - - Returns: - A new Image containing the cropped region - """ - img_height, img_width = self.data.shape[:2] - - # Clamp the crop region to image bounds - x = max(0, min(x, img_width)) - y = max(0, min(y, img_height)) - x_end = min(x + width, img_width) - y_end = min(y + height, img_height) - - # Perform the crop using array slicing - if self.data.ndim == 2: - cropped_data = self.data[y:y_end, x:x_end] - else: - cropped_data = self.data[y:y_end, x:x_end, :] - - return Image(data=cropped_data, format=self.format, frame_id=self.frame_id, ts=self.ts) - - @property - def brightness(self) -> float: - """Return mean brightness in [0, 1]. - - Strides to ~256px on the long edge first — ~O(N/step²) cheaper than - reading every pixel, and the mean converges quickly (CLT). - """ - max_val = 65535.0 if self.format in (ImageFormat.GRAY16, ImageFormat.DEPTH16) else 255.0 - step = max(1, max(self.data.shape[:2]) // 256) - return float(self.data[::step, ::step].mean() / max_val) - - @property - def sharpness(self) -> float: - """Return sharpness score. - - Downsamples to ~160px wide before computing Laplacian variance - for fast evaluation (~10-20x cheaper than full-res Sobel). - """ - import cv2 - - gray = self.to_grayscale().data - # Downsample to ~160px wide for cheap evaluation - h, w = gray.shape[:2] - if w > 160: - scale = 160.0 / w - gray = cv2.resize(gray, (160, int(h * scale)), interpolation=cv2.INTER_AREA) - lap_var = cv2.Laplacian(gray, cv2.CV_32F).var() - if lap_var <= 0: - return 0.0 - return float(np.clip((np.log10(lap_var + 1) - 1.0) / 3.0, 0.0, 1.0)) - - def save(self, filepath: str) -> bool: - import cv2 - - arr = self.to_opencv() - return cv2.imwrite(filepath, arr) - - def to_base64( - self, - quality: int = 80, - *, - max_width: int | None = None, - max_height: int | None = None, - ) -> str: - """Encode the image as a base64 JPEG string. - - Args: - quality: JPEG quality (0-100). - max_width: Optional maximum width to constrain the encoded image. - max_height: Optional maximum height to constrain the encoded image. - - Returns: - Base64-encoded JPEG representation of the image. - """ - import cv2 - - bgr_image = self.to_bgr().to_opencv() - height, width = bgr_image.shape[:2] - - scale = 1.0 - if max_width is not None and width > max_width: - scale = min(scale, max_width / width) - if max_height is not None and height > max_height: - scale = min(scale, max_height / height) - - if scale < 1.0: - new_width = max(1, round(width * scale)) - new_height = max(1, round(height * scale)) - bgr_image = cv2.resize(bgr_image, (new_width, new_height), interpolation=cv2.INTER_AREA) - - encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), int(np.clip(quality, 0, 100))] - success, buffer = cv2.imencode(".jpg", bgr_image, encode_param) - if not success: - raise ValueError("Failed to encode image as JPEG") - - return base64.b64encode(buffer.tobytes()).decode("utf-8") - - def agent_encode(self) -> AgentImageMessage: - return [ # type: ignore[return-value] - { - "type": "image_url", - "image_url": {"url": f"data:image/jpeg;base64,{self.to_base64()}"}, - } - ] - - # LCM encode/decode - def lcm_encode(self, frame_id: str | None = None) -> bytes: - """Convert to LCM Image message.""" - msg = LCMImage() - - # Header - msg.header = Header() - msg.header.seq = 0 - msg.header.frame_id = frame_id or self.frame_id - - # Set timestamp - if self.ts is not None: - msg.header.stamp.sec = int(self.ts) - msg.header.stamp.nsec = int((self.ts - int(self.ts)) * 1e9) - else: - now = time.time() - msg.header.stamp.sec = int(now) - msg.header.stamp.nsec = int((now - int(now)) * 1e9) - - # Image properties - msg.height = self.height - msg.width = self.width - msg.encoding = _get_lcm_encoding(self.format, self.dtype) - msg.is_bigendian = False - - # Calculate step (bytes per row) - channels = 1 if self.data.ndim == 2 else self.data.shape[2] - msg.step = self.width * self.dtype.itemsize * channels - - view = memoryview(np.ascontiguousarray(self.data)).cast("B") # type: ignore[arg-type] - msg.data_length = len(view) - msg.data = view - - return msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes, **kwargs: Any) -> Image: - msg = LCMImage.lcm_decode(data) - - # JPEG-compressed images use a different decode path. - if msg.encoding == "jpeg": - return cls.lcm_jpeg_decode(data, **kwargs) - - fmt, dtype, channels = _parse_lcm_encoding(msg.encoding) - arr: np.ndarray[Any, Any] = np.frombuffer(msg.data, dtype=dtype) - if channels == 1: - arr = arr.reshape((msg.height, msg.width)) - else: - arr = arr.reshape((msg.height, msg.width, channels)) - return cls( - data=arr, - format=fmt, - frame_id=msg.header.frame_id if hasattr(msg, "header") else "", - ts=( - msg.header.stamp.sec + msg.header.stamp.nsec / 1e9 - if hasattr(msg, "header") - and hasattr(msg.header, "stamp") - and msg.header.stamp.sec > 0 - else time.time() - ), - ) - - def to_jpeg_bytes(self, quality: int = 75) -> bytes: - """Encode this image as JPEG bytes using TurboJPEG. - - Args: - quality: JPEG compression quality (0-100, default 75). - - Returns: - Raw JPEG bytes. - """ - # Canonicalize to RGB so JPEG bytes are deterministic regardless of input format. - rgb_array = self.to_rgb().data - return get_turbojpeg().encode(rgb_array, quality=quality, pixel_format=TJPF_RGB) # type: ignore[no-any-return] - - def lcm_jpeg_encode(self, quality: int = 75, frame_id: str | None = None) -> bytes: - """Convert to LCM Image message with JPEG-compressed data. - - Args: - quality: JPEG compression quality (0-100, default 75) - frame_id: Optional frame ID override - - Returns: - LCM-encoded bytes with JPEG-compressed image data - """ - msg = LCMImage() - - # Header - msg.header = Header() - msg.header.seq = 0 - msg.header.frame_id = frame_id or self.frame_id - - # Set timestamp - if self.ts is not None: - msg.header.stamp.sec = int(self.ts) - msg.header.stamp.nsec = int((self.ts - int(self.ts)) * 1e9) - else: - now = time.time() - msg.header.stamp.sec = int(now) - msg.header.stamp.nsec = int((now - int(now)) * 1e9) - - jpeg_data = self.to_jpeg_bytes(quality=quality) - - # Store JPEG data and metadata - msg.height = self.height - msg.width = self.width - msg.encoding = "jpeg" - msg.is_bigendian = False - msg.step = 0 # Not applicable for compressed format - - msg.data_length = len(jpeg_data) - msg.data = jpeg_data - - return msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_jpeg_decode(cls, data: bytes, **kwargs: Any) -> Image: - """Decode an LCM Image message with JPEG-compressed data. - - Args: - data: LCM-encoded bytes containing JPEG-compressed image - - Returns: - Image instance - """ - msg = LCMImage.lcm_decode(data) - - if msg.encoding != "jpeg": - raise ValueError(f"Expected JPEG encoding, got {msg.encoding}") - - rgb_array = get_turbojpeg().decode(msg.data, pixel_format=TJPF_RGB) - - return cls( - data=rgb_array, - format=ImageFormat.RGB, - frame_id=msg.header.frame_id if hasattr(msg, "header") else "", - ts=( - msg.header.stamp.sec + msg.header.stamp.nsec / 1e9 - if hasattr(msg, "header") - and hasattr(msg.header, "stamp") - and msg.header.stamp.sec > 0 - else time.time() - ), - ) - - -def sharpness_window(target_frequency: float, source: Observable[Image]) -> Observable[Image]: - """Emit the sharpest Image seen within each sliding time window.""" - from reactivex.scheduler import ThreadPoolScheduler - - if target_frequency <= 0: - raise ValueError("target_frequency must be positive") - - window = TimestampedBufferCollection(1.0 / target_frequency) # type: ignore[var-annotated] - source.subscribe(window.add) - - thread_scheduler = ThreadPoolScheduler(max_workers=1) - - def find_best(*_args: Any) -> Image | None: - if len(window) == 0: - return None - return max(window, key=lambda img: img.sharpness) # type: ignore[no-any-return] - - return rx.interval(1.0 / target_frequency).pipe( # type: ignore[misc] - ops.observe_on(thread_scheduler), - ops.map(find_best), - ops.filter(lambda img: img is not None), - ) - - -def sharpness_barrier( - target_frequency: float, scheduler: SchedulerBase | None = None -) -> Callable[[Observable[Image]], Observable[Image]]: - """Select the sharpest Image within each time window.""" - if target_frequency <= 0: - raise ValueError("target_frequency must be positive") - return quality_barrier(lambda image: image.sharpness, target_frequency, scheduler) - - -def _get_lcm_encoding(fmt: ImageFormat, dtype: np.dtype) -> str: - if fmt == ImageFormat.GRAY: - if dtype == np.uint8: - return "mono8" - if dtype == np.uint16: - return "mono16" - if fmt == ImageFormat.GRAY16: - return "mono16" - if fmt == ImageFormat.RGB: - return "rgb8" - if fmt == ImageFormat.RGBA: - return "rgba8" - if fmt == ImageFormat.BGR: - return "bgr8" - if fmt == ImageFormat.BGRA: - return "bgra8" - if fmt == ImageFormat.DEPTH: - if dtype == np.float32: - return "32FC1" - if dtype == np.float64: - return "64FC1" - if fmt == ImageFormat.DEPTH16: - if dtype == np.uint16: - return "16UC1" - if dtype == np.int16: - return "16SC1" - raise ValueError(f"Unsupported LCM encoding for fmt={fmt}, dtype={dtype}") - - -def _parse_lcm_encoding(enc: str) -> tuple[ImageFormat, type, int]: - m = { - "mono8": (ImageFormat.GRAY, np.uint8, 1), - "mono16": (ImageFormat.GRAY16, np.uint16, 1), - "rgb8": (ImageFormat.RGB, np.uint8, 3), - "rgba8": (ImageFormat.RGBA, np.uint8, 4), - "bgr8": (ImageFormat.BGR, np.uint8, 3), - "bgra8": (ImageFormat.BGRA, np.uint8, 4), - "32FC1": (ImageFormat.DEPTH, np.float32, 1), - "32FC3": (ImageFormat.RGB, np.float32, 3), - "64FC1": (ImageFormat.DEPTH, np.float64, 1), - "16UC1": (ImageFormat.DEPTH16, np.uint16, 1), - "16SC1": (ImageFormat.DEPTH16, np.int16, 1), - } - if enc not in m: - raise ValueError(f"Unsupported encoding: {enc}") - return m[enc] diff --git a/dimos/msgs/sensor_msgs/Imu.py b/dimos/msgs/sensor_msgs/Imu.py deleted file mode 100644 index e1cd1f6b621..00000000000 --- a/dimos/msgs/sensor_msgs/Imu.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import time - -from dimos_lcm.sensor_msgs.Imu import Imu as LCMImu - -from dimos.msgs.geometry_msgs.Quaternion import Quaternion -from dimos.msgs.geometry_msgs.Vector3 import Vector3 -from dimos.types.timestamped import Timestamped - - -class Imu(Timestamped): - """IMU sensor message mirroring ROS sensor_msgs/Imu. - - Contains orientation, angular velocity, and linear acceleration - with optional covariance matrices (3x3 row-major as flat 9-element lists). - """ - - msg_name = "sensor_msgs.Imu" - - def __init__( - self, - angular_velocity: Vector3 | None = None, - linear_acceleration: Vector3 | None = None, - orientation: Quaternion | None = None, - orientation_covariance: list[float] | None = None, - angular_velocity_covariance: list[float] | None = None, - linear_acceleration_covariance: list[float] | None = None, - frame_id: str = "imu_link", - ts: float | None = None, - ) -> None: - self.ts = ts if ts is not None else time.time() - self.frame_id = frame_id - self.angular_velocity = angular_velocity or Vector3(0.0, 0.0, 0.0) - self.linear_acceleration = linear_acceleration or Vector3(0.0, 0.0, 0.0) - self.orientation = orientation or Quaternion(0.0, 0.0, 0.0, 1.0) - self.orientation_covariance = orientation_covariance or [0.0] * 9 - self.angular_velocity_covariance = angular_velocity_covariance or [0.0] * 9 - self.linear_acceleration_covariance = linear_acceleration_covariance or [0.0] * 9 - - def lcm_encode(self) -> bytes: - msg = LCMImu() - [msg.header.stamp.sec, msg.header.stamp.nsec] = self.ros_timestamp() - msg.header.frame_id = self.frame_id - - msg.orientation.x = self.orientation.x - msg.orientation.y = self.orientation.y - msg.orientation.z = self.orientation.z - msg.orientation.w = self.orientation.w - msg.orientation_covariance = self.orientation_covariance - - msg.angular_velocity.x = self.angular_velocity.x - msg.angular_velocity.y = self.angular_velocity.y - msg.angular_velocity.z = self.angular_velocity.z - msg.angular_velocity_covariance = self.angular_velocity_covariance - - msg.linear_acceleration.x = self.linear_acceleration.x - msg.linear_acceleration.y = self.linear_acceleration.y - msg.linear_acceleration.z = self.linear_acceleration.z - msg.linear_acceleration_covariance = self.linear_acceleration_covariance - - return msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes) -> Imu: - msg = LCMImu.lcm_decode(data) - ts = msg.header.stamp.sec + (msg.header.stamp.nsec / 1_000_000_000) - return cls( - angular_velocity=Vector3( - msg.angular_velocity.x, - msg.angular_velocity.y, - msg.angular_velocity.z, - ), - linear_acceleration=Vector3( - msg.linear_acceleration.x, - msg.linear_acceleration.y, - msg.linear_acceleration.z, - ), - orientation=Quaternion( - msg.orientation.x, - msg.orientation.y, - msg.orientation.z, - msg.orientation.w, - ), - orientation_covariance=list(msg.orientation_covariance), - angular_velocity_covariance=list(msg.angular_velocity_covariance), - linear_acceleration_covariance=list(msg.linear_acceleration_covariance), - frame_id=msg.header.frame_id, - ts=ts, - ) - - def __str__(self) -> str: - return ( - f"Imu(frame_id='{self.frame_id}', " - f"gyro=({self.angular_velocity.x:.3f}, {self.angular_velocity.y:.3f}, {self.angular_velocity.z:.3f}), " - f"accel=({self.linear_acceleration.x:.3f}, {self.linear_acceleration.y:.3f}, {self.linear_acceleration.z:.3f}))" - ) - - def __repr__(self) -> str: - return ( - f"Imu(ts={self.ts}, frame_id='{self.frame_id}', " - f"angular_velocity={self.angular_velocity}, " - f"linear_acceleration={self.linear_acceleration}, " - f"orientation={self.orientation})" - ) - - def to_rerun(self, axis_length: float = 0.2): # type: ignore[no-untyped-def] - """Orientation axes for rerun.""" - import rerun as rr - - return rr.TransformAxes3D(axis_length=axis_length) diff --git a/dimos/msgs/sensor_msgs/ImuInfo.py b/dimos/msgs/sensor_msgs/ImuInfo.py deleted file mode 100644 index 216d7e42a58..00000000000 --- a/dimos/msgs/sensor_msgs/ImuInfo.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright 2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""IMU noise-model information, the inertial sibling of ``CameraInfo``. - -Where the IMU sits comes from tf (``header.frame_id`` names the frame), just as -camera extrinsics do; this message carries what tf cannot: the continuous-time -noise model consumers such as VIO preintegration need. The values are -Allan-variance constants, measured once per model (or per unit); IMUs do not -report them at runtime, so a driver publishes them from its config the same way -``camera_info`` is published alongside images. - -LCM schema (fingerprint-compatible bindings must be generated from this):: - - package sensor_msgs; - - struct ImuInfo { - std_msgs.Header header; - double gyro_noise_density; - double gyro_random_walk; - double accel_noise_density; - double accel_random_walk; - double frequency; - } -""" - -from __future__ import annotations - -from io import BytesIO -import struct - -from dimos_lcm.std_msgs.Header import Header - -from dimos.types.timestamped import Timestamped - -# lcm-gen's base hash for the struct above; the wire fingerprint mixes in -# Header's recursively, matching the generated C++ in dimSLAM. -_BASE_HASH = 0x437A196CBD6B4E49 - - -def _packed_fingerprint() -> bytes: - tmphash = (_BASE_HASH + Header._get_hash_recursive([ImuInfo])) & 0xFFFFFFFFFFFFFFFF - tmphash = (((tmphash << 1) & 0xFFFFFFFFFFFFFFFF) + (tmphash >> 63)) & 0xFFFFFFFFFFFFFFFF - return struct.pack(">Q", tmphash) - - -class ImuInfo(Timestamped): - """IMU noise model: Allan-variance constants plus the delivered sample rate.""" - - msg_name = "sensor_msgs.ImuInfo" - - def __init__( - self, - gyro_noise_density: float = 0.0, - gyro_random_walk: float = 0.0, - accel_noise_density: float = 0.0, - accel_random_walk: float = 0.0, - frequency: float = 0.0, - frame_id: str = "", - ts: float | None = None, - ) -> None: - """Initialize ImuInfo. - - Args: - gyro_noise_density: Gyroscope white noise, rad/s/sqrt(Hz) - gyro_random_walk: Gyroscope bias random walk, rad/s^2/sqrt(Hz) - accel_noise_density: Accelerometer white noise, m/s^2/sqrt(Hz) - accel_random_walk: Accelerometer bias random walk, m/s^3/sqrt(Hz) - frequency: Rate the samples are actually delivered at, Hz - frame_id: The IMU frame; tf places it against the rest of the rig - ts: Timestamp (defaults to now) - """ - import time - - super().__init__(ts if ts is not None else time.time()) - self.gyro_noise_density = gyro_noise_density - self.gyro_random_walk = gyro_random_walk - self.accel_noise_density = accel_noise_density - self.accel_random_walk = accel_random_walk - self.frequency = frequency - self.frame_id = frame_id - - def with_ts(self, ts: float) -> ImuInfo: - """Return a copy of this ImuInfo with the given timestamp.""" - return ImuInfo( - gyro_noise_density=self.gyro_noise_density, - gyro_random_walk=self.gyro_random_walk, - accel_noise_density=self.accel_noise_density, - accel_random_walk=self.accel_random_walk, - frequency=self.frequency, - frame_id=self.frame_id, - ts=ts, - ) - - def with_frame_id(self, frame_id: str) -> ImuInfo: - """Return a copy of this ImuInfo stamped with the given frame.""" - copy = self.with_ts(self.ts) - copy.frame_id = frame_id - return copy - - def lcm_encode(self) -> bytes: - header = Header() - header.seq = 0 - header.frame_id = self.frame_id - header.stamp.sec = int(self.ts) - header.stamp.nsec = int((self.ts - int(self.ts)) * 1e9) - - buf = BytesIO() - buf.write(_packed_fingerprint()) - header._encode_one(buf) - buf.write( - struct.pack( - ">ddddd", - self.gyro_noise_density, - self.gyro_random_walk, - self.accel_noise_density, - self.accel_random_walk, - self.frequency, - ) - ) - return buf.getvalue() - - @classmethod - def lcm_decode(cls, data: bytes) -> ImuInfo: - buf = BytesIO(data) - if buf.read(8) != _packed_fingerprint(): - raise ValueError("Decode error") - header = Header._decode_one(buf) - values = struct.unpack(">ddddd", buf.read(40)) - return cls( - gyro_noise_density=values[0], - gyro_random_walk=values[1], - accel_noise_density=values[2], - accel_random_walk=values[3], - frequency=values[4], - frame_id=header.frame_id, - ts=header.stamp.sec + header.stamp.nsec / 1e9, - ) - - def __repr__(self) -> str: - return ( - f"ImuInfo(gyro_noise_density={self.gyro_noise_density}, " - f"gyro_random_walk={self.gyro_random_walk}, " - f"accel_noise_density={self.accel_noise_density}, " - f"accel_random_walk={self.accel_random_walk}, " - f"frequency={self.frequency}, frame_id='{self.frame_id}')" - ) diff --git a/dimos/msgs/sensor_msgs/JointCommand.py b/dimos/msgs/sensor_msgs/JointCommand.py deleted file mode 100644 index 78c541c50ec..00000000000 --- a/dimos/msgs/sensor_msgs/JointCommand.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""LCM type definitions -This file automatically generated by lcm. -DO NOT MODIFY BY HAND!!!! -""" - -from io import BytesIO -import struct -import time - - -class JointCommand: - """ - Joint command message for robotic manipulators. - - Supports variable number of joints (DOF) with float64 values. - Can be used for position commands or velocity commands. - Includes timestamp for synchronization. - """ - - msg_name = "sensor_msgs.JointCommand" - - __slots__ = ["num_joints", "positions", "timestamp"] - - __typenames__ = ["double", "int32_t", "double"] - - __dimensions__ = [None, None, ["num_joints"]] - - def __init__( - self, positions: list[float] | None = None, timestamp: float | None = None - ) -> None: - """ - Initialize JointCommand. - - Args: - positions: List of joint values (positions or velocities) - timestamp: Unix timestamp (seconds since epoch). If None, uses current time. - """ - if positions is None: - positions = [] - - if timestamp is None: - timestamp = time.time() - - # LCM Type: double (timestamp) - self.timestamp = timestamp - # LCM Type: int32_t - self.num_joints = len(positions) - # LCM Type: double[num_joints] - self.positions = list(positions) - - def lcm_encode(self): # type: ignore[no-untyped-def] - """Encode for LCM transport (dimos uses lcm_encode method name).""" - return self.encode() # type: ignore[no-untyped-call] - - def encode(self): # type: ignore[no-untyped-def] - buf = BytesIO() - buf.write(JointCommand._get_packed_fingerprint()) # type: ignore[no-untyped-call] - self._encode_one(buf) - return buf.getvalue() - - def _encode_one(self, buf) -> None: # type: ignore[no-untyped-def] - # Encode timestamp - buf.write(struct.pack(">d", self.timestamp)) - - # Encode num_joints - buf.write(struct.pack(">i", self.num_joints)) - - # Encode positions array - for i in range(self.num_joints): - buf.write(struct.pack(">d", self.positions[i])) - - @classmethod - def lcm_decode(cls, data: bytes): # type: ignore[no-untyped-def] - """Decode from LCM transport (dimos uses lcm_decode method name).""" - return cls.decode(data) - - @classmethod - def decode(cls, data: bytes): # type: ignore[no-untyped-def] - if hasattr(data, "read"): - buf = data - else: - buf = BytesIO(data) # type: ignore[assignment] - if buf.read(8) != cls._get_packed_fingerprint(): # type: ignore[no-untyped-call] - raise ValueError("Decode error") - return cls._decode_one(buf) # type: ignore[no-untyped-call] - - @classmethod - def _decode_one(cls, buf): # type: ignore[no-untyped-def] - self = JointCommand.__new__(JointCommand) - - # Decode timestamp - self.timestamp = struct.unpack(">d", buf.read(8))[0] - - # Decode num_joints - self.num_joints = struct.unpack(">i", buf.read(4))[0] - - # Decode positions array - self.positions = [] - for _i in range(self.num_joints): - self.positions.append(struct.unpack(">d", buf.read(8))[0]) - - return self - - @classmethod - def _get_hash_recursive(cls, parents): # type: ignore[no-untyped-def] - if cls in parents: - return 0 - # Hash for variable-length double array message - tmphash = (0x8A3D2E1C5F4B6A9D) & 0xFFFFFFFFFFFFFFFF - tmphash = (((tmphash << 1) & 0xFFFFFFFFFFFFFFFF) + (tmphash >> 63)) & 0xFFFFFFFFFFFFFFFF - return tmphash - - _packed_fingerprint = None - - @classmethod - def _get_packed_fingerprint(cls): # type: ignore[no-untyped-def] - if cls._packed_fingerprint is None: - cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) # type: ignore[no-untyped-call] - return cls._packed_fingerprint - - def get_hash(self): # type: ignore[no-untyped-def] - """Get the LCM hash of the struct""" - return struct.unpack(">Q", JointCommand._get_packed_fingerprint())[0] # type: ignore[no-untyped-call] - - def __str__(self) -> str: - return f"JointCommand(timestamp={self.timestamp:.6f}, num_joints={self.num_joints}, positions={self.positions})" - - def __repr__(self) -> str: - return f"JointCommand(positions={self.positions}, timestamp={self.timestamp})" diff --git a/dimos/msgs/sensor_msgs/JointState.py b/dimos/msgs/sensor_msgs/JointState.py deleted file mode 100644 index 3cbb74e0338..00000000000 --- a/dimos/msgs/sensor_msgs/JointState.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import time -from typing import Any, TypeAlias - -from dimos_lcm.sensor_msgs import JointState as LCMJointState - -from dimos.types.timestamped import Timestamped - -# Types that can be converted to/from JointState -JointStateConvertable: TypeAlias = dict[str, list[str] | list[float]] | LCMJointState - -_FIELDS = ("ts", "frame_id", "name", "position", "velocity", "effort") - - -def sec_nsec(ts): # type: ignore[no-untyped-def] - s = int(ts) - return [s, int((ts - s) * 1_000_000_000)] - - -def _fields_of(source: Any) -> tuple[Any, ...]: - """Pull the six JointState fields out of a dict, a JointState or an LCM message.""" - if isinstance(source, dict): - return ( - source.get("ts"), - source.get("frame_id", ""), - source.get("name"), - source.get("position"), - source.get("velocity"), - source.get("effort"), - ) - if isinstance(source, JointState): - return (source.ts, source.frame_id, *(list(getattr(source, f)) for f in _FIELDS[2:])) - return ( - source.header.stamp.sec + (source.header.stamp.nsec / 1_000_000_000), - source.header.frame_id, - *(list(getattr(source, f) or []) for f in _FIELDS[2:]), - ) - - -class JointState(Timestamped): - msg_name = "sensor_msgs.JointState" - ts: float - frame_id: str - name: list[str] - position: list[float] - velocity: list[float] - effort: list[float] - - def __init__( - self, - ts: float | JointStateConvertable | JointState | None = None, - frame_id: str = "", - name: list[str] | None = None, - position: list[float] | None = None, - velocity: list[float] | None = None, - effort: list[float] | None = None, - ) -> None: - """Initialize a JointState message. - - The first argument doubles as the source for the copy/dict/LCM forms: - ``JointState(other)``, ``JointState({...})``, ``JointState(lcm_msg)``. - - Args: - ts: Timestamp in seconds - frame_id: Frame ID for the message - name: List of joint names - position: List of joint positions (rad or m); gripper joints use - the unit their adapter declares - velocity: List of joint velocities (rad/s or m/s) - effort: List of joint efforts (Nm or N) - """ - stamp: Any = ts - if isinstance(stamp, dict | JointState | LCMJointState): - stamp, frame_id, name, position, velocity, effort = _fields_of(stamp) - - self.ts = time.time() if stamp is None else stamp - self.frame_id = frame_id - self.name = name if name is not None else [] - self.position = position if position is not None else [] - self.velocity = velocity if velocity is not None else [] - self.effort = effort if effort is not None else [] - - def lcm_encode(self) -> bytes: - lcm_msg = LCMJointState() - [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] - lcm_msg.header.frame_id = self.frame_id - lcm_msg.name_length = len(self.name) - lcm_msg.name = self.name - lcm_msg.position_length = len(self.position) - lcm_msg.position = self.position - lcm_msg.velocity_length = len(self.velocity) - lcm_msg.velocity = self.velocity - lcm_msg.effort_length = len(self.effort) - lcm_msg.effort = self.effort - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes) -> JointState: - lcm_msg = LCMJointState.lcm_decode(data) - return cls( - ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), - frame_id=lcm_msg.header.frame_id, - name=list(lcm_msg.name) if lcm_msg.name else [], - position=list(lcm_msg.position) if lcm_msg.position else [], - velocity=list(lcm_msg.velocity) if lcm_msg.velocity else [], - effort=list(lcm_msg.effort) if lcm_msg.effort else [], - ) - - def __str__(self) -> str: - return f"JointState({len(self.name)} joints, frame_id='{self.frame_id}')" - - def __repr__(self) -> str: - return ( - f"JointState(ts={self.ts}, frame_id='{self.frame_id}', " - f"name={self.name}, position={self.position}, " - f"velocity={self.velocity}, effort={self.effort})" - ) - - def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] - """Check if two JointState messages are equal.""" - if not isinstance(other, JointState): - return False - return ( - self.name == other.name - and self.position == other.position - and self.velocity == other.velocity - and self.effort == other.effort - and self.frame_id == other.frame_id - ) diff --git a/dimos/msgs/sensor_msgs/Joy.py b/dimos/msgs/sensor_msgs/Joy.py deleted file mode 100644 index 9443770b67e..00000000000 --- a/dimos/msgs/sensor_msgs/Joy.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -import time -from typing import Any, TypeAlias - -from dimos_lcm.sensor_msgs import Joy as LCMJoy - -from dimos.types.timestamped import Timestamped - -# Types that can be converted to/from Joy -JoyConvertable: TypeAlias = ( - tuple[list[float], list[int]] | dict[str, list[float] | list[int]] | LCMJoy -) - - -def sec_nsec(ts): # type: ignore[no-untyped-def] - s = int(ts) - return [s, int((ts - s) * 1_000_000_000)] - - -def _fields_of(source: Any) -> tuple[Any, ...]: - """Pull the four Joy fields out of a dict, an (axes, buttons) pair, a Joy or an LCM message.""" - if isinstance(source, dict): - return ( - source.get("ts"), - source.get("frame_id", ""), - source.get("axes"), - source.get("buttons"), - ) - if isinstance(source, tuple | list): - return (None, "", list(source[0]), list(source[1])) - if isinstance(source, Joy): - return (source.ts, source.frame_id, list(source.axes), list(source.buttons)) - return ( - source.header.stamp.sec + (source.header.stamp.nsec / 1_000_000_000), - source.header.frame_id, - list(source.axes), - list(source.buttons), - ) - - -class Joy(Timestamped): - msg_name = "sensor_msgs.Joy" - ts: float - frame_id: str - axes: list[float] - buttons: list[int] - - def __init__( - self, - ts: float | JoyConvertable | Joy | None = None, - frame_id: str = "", - axes: list[float] | None = None, - buttons: list[int] | None = None, - ) -> None: - """Initialize a Joy message. - - The first argument doubles as the source for the copy/dict/pair/LCM forms: - ``Joy(other)``, ``Joy({...})``, ``Joy((axes, buttons))``, ``Joy(lcm_msg)``. - - Args: - ts: Timestamp in seconds - frame_id: Frame ID for the message - axes: List of axis values (typically -1.0 to 1.0) - buttons: List of button states (0 or 1) - """ - stamp: Any = ts - if isinstance(stamp, dict | tuple | list | Joy | LCMJoy): - stamp, frame_id, axes, buttons = _fields_of(stamp) - - self.ts = time.time() if stamp is None else stamp - self.frame_id = frame_id - self.axes = axes if axes is not None else [] - self.buttons = buttons if buttons is not None else [] - - def lcm_encode(self) -> bytes: - lcm_msg = LCMJoy() - [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] - lcm_msg.header.frame_id = self.frame_id - lcm_msg.axes_length = len(self.axes) - lcm_msg.axes = self.axes - lcm_msg.buttons_length = len(self.buttons) - lcm_msg.buttons = self.buttons - return lcm_msg.lcm_encode() # type: ignore[no-any-return] - - @classmethod - def lcm_decode(cls, data: bytes) -> Joy: - lcm_msg = LCMJoy.lcm_decode(data) - return cls( - ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), - frame_id=lcm_msg.header.frame_id, - axes=list(lcm_msg.axes) if lcm_msg.axes else [], - buttons=list(lcm_msg.buttons) if lcm_msg.buttons else [], - ) - - def __str__(self) -> str: - return ( - f"Joy(axes={len(self.axes)} values, buttons={len(self.buttons)} values, " - f"frame_id='{self.frame_id}')" - ) - - def __repr__(self) -> str: - return ( - f"Joy(ts={self.ts}, frame_id='{self.frame_id}', " - f"axes={self.axes}, buttons={self.buttons})" - ) - - def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] - """Check if two Joy messages are equal.""" - if not isinstance(other, Joy): - return False - return ( - self.axes == other.axes - and self.buttons == other.buttons - and self.frame_id == other.frame_id - ) diff --git a/dimos/msgs/sensor_msgs/MotorCommandArray.py b/dimos/msgs/sensor_msgs/MotorCommandArray.py deleted file mode 100644 index 577b03c7655..00000000000 --- a/dimos/msgs/sensor_msgs/MotorCommandArray.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""LCM type for low-level motor commands: q, dq, kp, kd, tau per motor.""" - -from io import BytesIO -import struct -import time - - -class MotorCommandArray: - """Per-motor q/dq/kp/kd/tau. Joint order is implicit (caller-defined).""" - - msg_name = "sensor_msgs.MotorCommandArray" - - __slots__ = ["dq", "kd", "kp", "num_joints", "q", "tau", "timestamp"] - - def __init__( - self, - q: list[float] | None = None, - dq: list[float] | None = None, - kp: list[float] | None = None, - kd: list[float] | None = None, - tau: list[float] | None = None, - timestamp: float | None = None, - ) -> None: - if q is None: - q = [] - if timestamp is None: - timestamp = time.time() - - n = len(q) - if dq is None: - dq = [0.0] * n - if kp is None: - kp = [0.0] * n - if kd is None: - kd = [0.0] * n - if tau is None: - tau = [0.0] * n - - if not (len(dq) == len(kp) == len(kd) == len(tau) == n): - raise ValueError( - f"All arrays must have length {n}; got " - f"dq={len(dq)} kp={len(kp)} kd={len(kd)} tau={len(tau)}" - ) - - self.timestamp = timestamp - self.num_joints = n - self.q = list(q) - self.dq = list(dq) - self.kp = list(kp) - self.kd = list(kd) - self.tau = list(tau) - - def lcm_encode(self) -> bytes: - return self.encode() - - def encode(self) -> bytes: - buf = BytesIO() - buf.write(MotorCommandArray._get_packed_fingerprint()) - self._encode_one(buf) - return buf.getvalue() - - def _encode_one(self, buf: BytesIO) -> None: - buf.write(struct.pack(">d", self.timestamp)) - buf.write(struct.pack(">i", self.num_joints)) - for arr in (self.q, self.dq, self.kp, self.kd, self.tau): - for v in arr: - buf.write(struct.pack(">d", v)) - - @classmethod - def lcm_decode(cls, data: bytes) -> "MotorCommandArray": - return cls.decode(data) - - @classmethod - def decode(cls, data: bytes | BytesIO) -> "MotorCommandArray": - buf: BytesIO = data if isinstance(data, BytesIO) else BytesIO(data) - if buf.read(8) != cls._get_packed_fingerprint(): - raise ValueError("Decode error") - return cls._decode_one(buf) - - @classmethod - def _decode_one(cls, buf: BytesIO) -> "MotorCommandArray": - self = MotorCommandArray.__new__(MotorCommandArray) - self.timestamp = struct.unpack(">d", buf.read(8))[0] - self.num_joints = struct.unpack(">i", buf.read(4))[0] - n = self.num_joints - arrays = [] - for _ in range(5): - arrays.append([struct.unpack(">d", buf.read(8))[0] for _ in range(n)]) - self.q, self.dq, self.kp, self.kd, self.tau = arrays - return self - - @classmethod - def _get_hash_recursive(cls, parents: list[type]) -> int: - if cls in parents: - return 0 - # Distinct fingerprint from JointCommand (0x8A3D2E1C5F4B6A9D) - tmphash = (0x9B4E3F2D6A5C7B8E) & 0xFFFFFFFFFFFFFFFF - tmphash = (((tmphash << 1) & 0xFFFFFFFFFFFFFFFF) + (tmphash >> 63)) & 0xFFFFFFFFFFFFFFFF - return tmphash - - _packed_fingerprint: bytes | None = None - - @classmethod - def _get_packed_fingerprint(cls) -> bytes: - if cls._packed_fingerprint is None: - cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) - return cls._packed_fingerprint - - def get_hash(self) -> int: - return int(struct.unpack(">Q", MotorCommandArray._get_packed_fingerprint())[0]) - - def __str__(self) -> str: - return f"MotorCommandArray(timestamp={self.timestamp:.6f}, num_joints={self.num_joints})" - - def __repr__(self) -> str: - return ( - f"MotorCommandArray(q={self.q}, dq={self.dq}, kp={self.kp}, " - f"kd={self.kd}, tau={self.tau}, timestamp={self.timestamp})" - ) diff --git a/dimos/msgs/sensor_msgs/RobotState.py b/dimos/msgs/sensor_msgs/RobotState.py deleted file mode 100644 index 20e41e7d248..00000000000 --- a/dimos/msgs/sensor_msgs/RobotState.py +++ /dev/null @@ -1,188 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""LCM type definitions -This file automatically generated by lcm. -DO NOT MODIFY BY HAND!!!! -""" - -from io import BytesIO -import struct - - -class RobotState: - msg_name = "sensor_msgs.RobotState" - - __slots__ = [ - "cmdnum", - "error_code", - "joints", - "mode", - "mt_able", - "mt_brake", - "state", - "tcp_offset", - "tcp_pose", - "warn_code", - ] - - __typenames__ = [ - "int32_t", - "int32_t", - "int32_t", - "int32_t", - "int32_t", - "int32_t", - "int32_t", - "float", - "float", - "float", - ] - - __dimensions__ = [None, None, None, None, None, None, None, None, None, None] - - def __init__( # type: ignore[no-untyped-def] - self, - state: int = 0, - mode: int = 0, - error_code: int = 0, - warn_code: int = 0, - cmdnum: int = 0, - mt_brake: int = 0, - mt_able: int = 0, - tcp_pose=None, - tcp_offset=None, - joints=None, - ) -> None: - # LCM Type: int32_t - self.state = state - # LCM Type: int32_t - self.mode = mode - # LCM Type: int32_t - self.error_code = error_code - # LCM Type: int32_t - self.warn_code = warn_code - # LCM Type: int32_t - self.cmdnum = cmdnum - # LCM Type: int32_t - self.mt_brake = mt_brake - # LCM Type: int32_t - self.mt_able = mt_able - # LCM Type: float[] - TCP pose [x, y, z, roll, pitch, yaw] - self.tcp_pose = tcp_pose if tcp_pose is not None else [] - # LCM Type: float[] - TCP offset [x, y, z, roll, pitch, yaw] - self.tcp_offset = tcp_offset if tcp_offset is not None else [] - # LCM Type: float[] - Joint positions (variable length based on robot DOF) - self.joints = joints if joints is not None else [] - - def lcm_encode(self): # type: ignore[no-untyped-def] - """Encode for LCM transport (dimos uses lcm_encode method name).""" - return self.encode() # type: ignore[no-untyped-call] - - def encode(self): # type: ignore[no-untyped-def] - buf = BytesIO() - buf.write(RobotState._get_packed_fingerprint()) # type: ignore[no-untyped-call] - self._encode_one(buf) - return buf.getvalue() - - def _encode_one(self, buf) -> None: # type: ignore[no-untyped-def] - buf.write( - struct.pack( - ">iiiiiii", - self.state, - self.mode, - self.error_code, - self.warn_code, - self.cmdnum, - self.mt_brake, - self.mt_able, - ) - ) - # Encode tcp_pose array - buf.write(struct.pack(">i", len(self.tcp_pose))) - for val in self.tcp_pose: - buf.write(struct.pack(">f", val)) - # Encode tcp_offset array - buf.write(struct.pack(">i", len(self.tcp_offset))) - for val in self.tcp_offset: - buf.write(struct.pack(">f", val)) - # Encode joints array - buf.write(struct.pack(">i", len(self.joints))) - for val in self.joints: - buf.write(struct.pack(">f", val)) - - @classmethod - def lcm_decode(cls, data: bytes): # type: ignore[no-untyped-def] - """Decode from LCM transport (dimos uses lcm_decode method name).""" - return cls.decode(data) - - @classmethod - def decode(cls, data: bytes): # type: ignore[no-untyped-def] - if hasattr(data, "read"): - buf = data - else: - buf = BytesIO(data) # type: ignore[assignment] - if buf.read(8) != cls._get_packed_fingerprint(): # type: ignore[no-untyped-call] - raise ValueError("Decode error") - return cls._decode_one(buf) # type: ignore[no-untyped-call] - - @classmethod - def _decode_one(cls, buf): # type: ignore[no-untyped-def] - self = RobotState() - ( - self.state, - self.mode, - self.error_code, - self.warn_code, - self.cmdnum, - self.mt_brake, - self.mt_able, - ) = struct.unpack(">iiiiiii", buf.read(28)) - # Decode tcp_pose array - tcp_pose_len = struct.unpack(">i", buf.read(4))[0] - self.tcp_pose = [] - for _ in range(tcp_pose_len): - self.tcp_pose.append(struct.unpack(">f", buf.read(4))[0]) - # Decode tcp_offset array - tcp_offset_len = struct.unpack(">i", buf.read(4))[0] - self.tcp_offset = [] - for _ in range(tcp_offset_len): - self.tcp_offset.append(struct.unpack(">f", buf.read(4))[0]) - # Decode joints array - joints_len = struct.unpack(">i", buf.read(4))[0] - self.joints = [] - for _ in range(joints_len): - self.joints.append(struct.unpack(">f", buf.read(4))[0]) - return self - - @classmethod - def _get_hash_recursive(cls, parents): # type: ignore[no-untyped-def] - if cls in parents: - return 0 - # Updated hash to reflect new fields: tcp_pose, tcp_offset, joints - tmphash = (0x8C3B9A1FE7D24E6A) & 0xFFFFFFFFFFFFFFFF - tmphash = (((tmphash << 1) & 0xFFFFFFFFFFFFFFFF) + (tmphash >> 63)) & 0xFFFFFFFFFFFFFFFF - return tmphash - - _packed_fingerprint = None - - @classmethod - def _get_packed_fingerprint(cls): # type: ignore[no-untyped-def] - if cls._packed_fingerprint is None: - cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) # type: ignore[no-untyped-call] - return cls._packed_fingerprint - - def get_hash(self): # type: ignore[no-untyped-def] - """Get the LCM hash of the struct""" - return struct.unpack(">Q", RobotState._get_packed_fingerprint())[0] # type: ignore[no-untyped-call] diff --git a/dimos/msgs/sensor_msgs/image_impls/AbstractImage.py b/dimos/msgs/sensor_msgs/image_impls/AbstractImage.py deleted file mode 100644 index 3b901b874b8..00000000000 --- a/dimos/msgs/sensor_msgs/image_impls/AbstractImage.py +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Backwards compatibility stub for unpickling old data. -# AbstractImage and ImageFormat were moved to Image. -from dimos.msgs.sensor_msgs.Image import Image as AbstractImage, ImageFormat # noqa: F401 diff --git a/dimos/msgs/std_msgs/Bool.py b/dimos/msgs/std_msgs/Bool.py deleted file mode 100644 index 4421447edfc..00000000000 --- a/dimos/msgs/std_msgs/Bool.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Bool message type.""" - -from dimos_lcm.std_msgs import Bool as LCMBool - - -class Bool(LCMBool): # type: ignore[misc] - """Bool message.""" - - msg_name = "std_msgs.Bool" - - def __init__(self, data: bool = False) -> None: - """Initialize Bool with data value.""" - self.data = data diff --git a/dimos/msgs/std_msgs/Float32.py b/dimos/msgs/std_msgs/Float32.py deleted file mode 100644 index f5a508d21c0..00000000000 --- a/dimos/msgs/std_msgs/Float32.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Float32 message type.""" - -from typing import ClassVar - -from dimos_lcm.std_msgs import Float32 as LCMFloat32 - - -class Float32(LCMFloat32): # type: ignore[misc] - """Float32 message.""" - - msg_name: ClassVar[str] = "std_msgs.Float32" - - def __init__(self, data: float = 0.0) -> None: - """Initialize Float32 with data value.""" - self.data = data diff --git a/dimos/msgs/std_msgs/Header.py b/dimos/msgs/std_msgs/Header.py deleted file mode 100644 index 5c542004972..00000000000 --- a/dimos/msgs/std_msgs/Header.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations - -from datetime import datetime -import time - -from dimos_lcm.std_msgs import Header as LCMHeader, Time as LCMTime -from plum import dispatch - -# Import the actual LCM header type that's returned from decoding -try: - from lcm_msgs.std_msgs.Header import ( # type: ignore[import-not-found] - Header as DecodedLCMHeader, - ) -except ImportError: - DecodedLCMHeader = None - - -class Header(LCMHeader): # type: ignore[misc] - msg_name = "std_msgs.Header" - ts: float - - @dispatch - def __init__(self) -> None: - """Initialize a Header with current time and empty frame_id.""" - self.ts = time.time() - sec = int(self.ts) - nsec = int((self.ts - sec) * 1_000_000_000) - super().__init__(seq=0, stamp=LCMTime(sec=sec, nsec=nsec), frame_id="") - - @dispatch # type: ignore[no-redef] - def __init__(self, frame_id: str) -> None: - """Initialize a Header with current time and specified frame_id.""" - self.ts = time.time() - sec = int(self.ts) - nsec = int((self.ts - sec) * 1_000_000_000) - super().__init__(seq=1, stamp=LCMTime(sec=sec, nsec=nsec), frame_id=frame_id) - - @dispatch # type: ignore[no-redef] - def __init__(self, timestamp: float, frame_id: str = "", seq: int = 1) -> None: - """Initialize a Header with Unix timestamp, frame_id, and optional seq.""" - sec = int(timestamp) - nsec = int((timestamp - sec) * 1_000_000_000) - super().__init__(seq=seq, stamp=LCMTime(sec=sec, nsec=nsec), frame_id=frame_id) - - @dispatch # type: ignore[no-redef] - def __init__(self, timestamp: datetime, frame_id: str = "") -> None: - """Initialize a Header with datetime object and frame_id.""" - self.ts = timestamp.timestamp() - sec = int(self.ts) - nsec = int((self.ts - sec) * 1_000_000_000) - super().__init__(seq=1, stamp=LCMTime(sec=sec, nsec=nsec), frame_id=frame_id) - - @dispatch # type: ignore[no-redef] - def __init__(self, seq: int, stamp: LCMTime, frame_id: str) -> None: - """Initialize with explicit seq, stamp, and frame_id (LCM compatibility).""" - super().__init__(seq=seq, stamp=stamp, frame_id=frame_id) - - @dispatch # type: ignore[no-redef] - def __init__(self, header: LCMHeader) -> None: - """Initialize from another Header (copy constructor).""" - super().__init__(seq=header.seq, stamp=header.stamp, frame_id=header.frame_id) - - @dispatch # type: ignore[no-redef] - def __init__(self, header: object) -> None: - """Initialize from a decoded LCM header object.""" - # Handle the case where we get an lcm_msgs.std_msgs.Header.Header object - if hasattr(header, "seq") and hasattr(header, "stamp") and hasattr(header, "frame_id"): - super().__init__(seq=header.seq, stamp=header.stamp, frame_id=header.frame_id) - else: - raise ValueError(f"Cannot create Header from {type(header)}") - - @classmethod - def now(cls, frame_id: str = "", seq: int = 1) -> Header: - """Create a Header with current timestamp.""" - ts = time.time() - return cls(ts, frame_id, seq) - - @property - def timestamp(self) -> float: - """Get timestamp as Unix time (float).""" - return self.stamp.sec + (self.stamp.nsec / 1_000_000_000) # type: ignore[no-any-return] - - @property - def datetime(self) -> datetime: - """Get timestamp as datetime object.""" - return datetime.fromtimestamp(self.timestamp) - - def __str__(self) -> str: - return f"Header(seq={self.seq}, time={self.timestamp:.6f}, frame_id='{self.frame_id}')" - - def __repr__(self) -> str: - return f"Header(seq={self.seq}, stamp=Time(sec={self.stamp.sec}, nsec={self.stamp.nsec}), frame_id='{self.frame_id}')" diff --git a/dimos/msgs/std_msgs/Int32.py b/dimos/msgs/std_msgs/Int32.py deleted file mode 100644 index ba4906f485d..00000000000 --- a/dimos/msgs/std_msgs/Int32.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Copyright 2025-2026 Dimensional Inc. - -"""Int32 message type.""" - -from typing import ClassVar - -from dimos_lcm.std_msgs import Int32 as LCMInt32 - - -class Int32(LCMInt32): # type: ignore[misc] - """ROS-compatible Int32 message.""" - - msg_name: ClassVar[str] = "std_msgs.Int32" - - def __init__(self, data: int = 0) -> None: - """Initialize Int32 with data value.""" - self.data = data diff --git a/dimos/msgs/std_msgs/Int8.py b/dimos/msgs/std_msgs/Int8.py deleted file mode 100644 index ca871403534..00000000000 --- a/dimos/msgs/std_msgs/Int8.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Copyright 2025-2026 Dimensional Inc. - -"""Int32 message type.""" - -from typing import ClassVar - -from dimos_lcm.std_msgs import Int8 as LCMInt8 - - -class Int8(LCMInt8): # type: ignore[misc] - """Int8 message.""" - - msg_name: ClassVar[str] = "std_msgs.Int8" - - def __init__(self, data: int = 0) -> None: - """Initialize Int8 with data value.""" - self.data = data diff --git a/dimos/msgs/std_msgs/String.py b/dimos/msgs/std_msgs/String.py deleted file mode 100644 index ef48233dfd3..00000000000 --- a/dimos/msgs/std_msgs/String.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""String message type.""" - -from typing import ClassVar - -from dimos_lcm.std_msgs import String as LCMString - - -class String(LCMString): # type: ignore[misc] - """ROS-compatible String message.""" - - msg_name: ClassVar[str] = "std_msgs.String" - - def __init__(self, data: str = "") -> None: - """Initialize String with data value.""" - self.data = data diff --git a/dimos/msgs/std_msgs/UInt32.py b/dimos/msgs/std_msgs/UInt32.py deleted file mode 100644 index e617c782fed..00000000000 --- a/dimos/msgs/std_msgs/UInt32.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""UInt32 message type.""" - -from typing import ClassVar - -from dimos_lcm.std_msgs import UInt32 as LCMUInt32 - - -class UInt32(LCMUInt32): # type: ignore[misc] - """ROS-compatible UInt32 message.""" - - msg_name: ClassVar[str] = "std_msgs.UInt32" - - def __init__(self, data: int = 0) -> None: - """Initialize UInt32 with data value.""" - self.data = data diff --git a/dimos/msgs/trajectory_msgs/JointTrajectory.py b/dimos/msgs/trajectory_msgs/JointTrajectory.py deleted file mode 100644 index ae2ad55fd1b..00000000000 --- a/dimos/msgs/trajectory_msgs/JointTrajectory.py +++ /dev/null @@ -1,211 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -JointTrajectory message type. - -A sequence of joint trajectory points representing a full trajectory. -Similar to ROS trajectory_msgs/JointTrajectory. -""" - -from io import BytesIO -import struct -import time - -from dimos.msgs.trajectory_msgs.TrajectoryPoint import TrajectoryPoint - - -class JointTrajectory: - """ - A joint-space trajectory consisting of timestamped waypoints. - - Attributes: - timestamp: When trajectory was created (seconds since epoch) - joint_names: Names of joints (optional) - points: Sequence of TrajectoryPoints - duration: Total trajectory duration (seconds) - """ - - msg_name = "trajectory_msgs.JointTrajectory" - - __slots__ = ["duration", "joint_names", "num_joints", "num_points", "points", "timestamp"] - - def __init__( - self, - points: list[TrajectoryPoint] | None = None, - joint_names: list[str] | None = None, - timestamp: float | None = None, - ) -> None: - """ - Initialize JointTrajectory. - - Args: - points: List of TrajectoryPoints - joint_names: Names of joints (optional) - timestamp: Creation timestamp (defaults to now) - """ - self.timestamp = timestamp if timestamp is not None else time.time() - self.points = list(points) if points else [] - self.num_points = len(self.points) - self.joint_names = list(joint_names) if joint_names else [] - self.num_joints = ( - len(self.joint_names) - if self.joint_names - else (self.points[0].num_joints if self.points else 0) - ) - - # Compute duration from last point - if self.points: - self.duration = max(p.time_from_start for p in self.points) - else: - self.duration = 0.0 - - def sample(self, t: float) -> tuple[list[float], list[float]]: - """ - Sample the trajectory at time t using linear interpolation. - - Args: - t: Time from trajectory start (seconds) - - Returns: - Tuple of (positions, velocities) at time t - """ - if not self.points: - return [], [] - - # Clamp t to valid range - t = max(0.0, min(t, self.duration)) - - # Find bracketing points - if t <= self.points[0].time_from_start: - return list(self.points[0].positions), list(self.points[0].velocities) - - if t >= self.points[-1].time_from_start: - return list(self.points[-1].positions), list(self.points[-1].velocities) - - # Find interval - for i in range(len(self.points) - 1): - t0 = self.points[i].time_from_start - t1 = self.points[i + 1].time_from_start - - if t0 <= t <= t1: - # Linear interpolation - alpha = (t - t0) / (t1 - t0) if t1 > t0 else 0.0 - p0 = self.points[i] - p1 = self.points[i + 1] - - positions = [ - p0.positions[j] + alpha * (p1.positions[j] - p0.positions[j]) - for j in range(len(p0.positions)) - ] - velocities = [ - p0.velocities[j] + alpha * (p1.velocities[j] - p0.velocities[j]) - for j in range(len(p0.velocities)) - ] - return positions, velocities - - # Fallback - return list(self.points[-1].positions), list(self.points[-1].velocities) - - def lcm_encode(self) -> bytes: - """Encode for LCM transport.""" - return self.encode() - - def encode(self) -> bytes: - buf = BytesIO() - buf.write(JointTrajectory._get_packed_fingerprint()) - self._encode_one(buf) - return buf.getvalue() - - def _encode_one(self, buf: BytesIO) -> None: - # timestamp (double) - buf.write(struct.pack(">d", self.timestamp)) - # duration (double) - buf.write(struct.pack(">d", self.duration)) - # num_joint_names (int32) - actual count of joint names - buf.write(struct.pack(">i", len(self.joint_names))) - # joint_names (string[num_joint_names]) - for name in self.joint_names: - name_bytes = name.encode("utf-8") - buf.write(struct.pack(">i", len(name_bytes))) - buf.write(name_bytes) - # num_points (int32) - buf.write(struct.pack(">i", self.num_points)) - # points (TrajectoryPoint[num_points]) - for point in self.points: - point._encode_one(buf) - - @classmethod - def lcm_decode(cls, data: bytes) -> "JointTrajectory": - """Decode from LCM transport.""" - return cls.decode(data) - - @classmethod - def decode(cls, data: bytes) -> "JointTrajectory": - buf = BytesIO(data) if not hasattr(data, "read") else data - if buf.read(8) != cls._get_packed_fingerprint(): - raise ValueError("Decode error: fingerprint mismatch") - return cls._decode_one(buf) # type: ignore[arg-type] - - @classmethod - def _decode_one(cls, buf: BytesIO) -> "JointTrajectory": - self = cls.__new__(cls) - self.timestamp = struct.unpack(">d", buf.read(8))[0] - self.duration = struct.unpack(">d", buf.read(8))[0] - - # Read joint names - num_joint_names = struct.unpack(">i", buf.read(4))[0] - self.joint_names = [] - for _ in range(num_joint_names): - name_len = struct.unpack(">i", buf.read(4))[0] - self.joint_names.append(buf.read(name_len).decode("utf-8")) - - # Read points - self.num_points = struct.unpack(">i", buf.read(4))[0] - self.points = [TrajectoryPoint._decode_one(buf) for _ in range(self.num_points)] - - # Set num_joints from joint_names or points - self.num_joints = ( - len(self.joint_names) - if self.joint_names - else (self.points[0].num_joints if self.points else 0) - ) - - return self - - _packed_fingerprint = None - - @classmethod - def _get_hash_recursive(cls, parents): # type: ignore[no-untyped-def] - if cls in parents: - return 0 - return 0x2B3C4D5E6F708192 & 0xFFFFFFFFFFFFFFFF - - @classmethod - def _get_packed_fingerprint(cls) -> bytes: - if cls._packed_fingerprint is None: - cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) # type: ignore[no-untyped-call] - return cls._packed_fingerprint - - def __str__(self) -> str: - return f"JointTrajectory({self.num_points} points, duration={self.duration:.3f}s)" - - def __repr__(self) -> str: - return ( - f"JointTrajectory(points={self.points}, joint_names={self.joint_names}, " - f"timestamp={self.timestamp})" - ) - - def __len__(self) -> int: - return self.num_points diff --git a/dimos/msgs/trajectory_msgs/TrajectoryPoint.py b/dimos/msgs/trajectory_msgs/TrajectoryPoint.py deleted file mode 100644 index b2b9ab8406c..00000000000 --- a/dimos/msgs/trajectory_msgs/TrajectoryPoint.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -TrajectoryPoint message type. - -A single point in a joint trajectory with positions, velocities, and time. -Similar to ROS trajectory_msgs/JointTrajectoryPoint. -""" - -from io import BytesIO -import struct - - -class TrajectoryPoint: - """ - A single point in a joint trajectory. - - Attributes: - time_from_start: Time from trajectory start (seconds) - positions: Joint positions (radians) - velocities: Joint velocities (rad/s) - """ - - msg_name = "trajectory_msgs.TrajectoryPoint" - - __slots__ = ["num_joints", "positions", "time_from_start", "velocities"] - - def __init__( - self, - time_from_start: float = 0.0, - positions: list[float] | None = None, - velocities: list[float] | None = None, - ) -> None: - """ - Initialize TrajectoryPoint. - - Args: - time_from_start: Time from trajectory start (seconds) - positions: Joint positions (radians) - velocities: Joint velocities (rad/s), defaults to zeros if None - """ - self.time_from_start = time_from_start - self.positions = list(positions) if positions else [] - self.num_joints = len(self.positions) - - if velocities is not None: - self.velocities = list(velocities) - else: - self.velocities = [0.0] * self.num_joints - - def lcm_encode(self) -> bytes: - """Encode for LCM transport.""" - return self.encode() - - def encode(self) -> bytes: - buf = BytesIO() - buf.write(TrajectoryPoint._get_packed_fingerprint()) - self._encode_one(buf) - return buf.getvalue() - - def _encode_one(self, buf: BytesIO) -> None: - # time_from_start (double) - buf.write(struct.pack(">d", self.time_from_start)) - # num_joints (int32) - buf.write(struct.pack(">i", self.num_joints)) - # positions (double[num_joints]) - for p in self.positions: - buf.write(struct.pack(">d", p)) - # velocities (double[num_joints]) - for v in self.velocities: - buf.write(struct.pack(">d", v)) - - @classmethod - def lcm_decode(cls, data: bytes) -> "TrajectoryPoint": - """Decode from LCM transport.""" - return cls.decode(data) - - @classmethod - def decode(cls, data: bytes) -> "TrajectoryPoint": - buf = BytesIO(data) if not hasattr(data, "read") else data - if buf.read(8) != cls._get_packed_fingerprint(): - raise ValueError("Decode error: fingerprint mismatch") - return cls._decode_one(buf) # type: ignore[arg-type] - - @classmethod - def _decode_one(cls, buf: BytesIO) -> "TrajectoryPoint": - self = cls.__new__(cls) - self.time_from_start = struct.unpack(">d", buf.read(8))[0] - self.num_joints = struct.unpack(">i", buf.read(4))[0] - self.positions = [struct.unpack(">d", buf.read(8))[0] for _ in range(self.num_joints)] - self.velocities = [struct.unpack(">d", buf.read(8))[0] for _ in range(self.num_joints)] - return self - - _packed_fingerprint = None - - @classmethod - def _get_hash_recursive(cls, parents): # type: ignore[no-untyped-def] - if cls in parents: - return 0 - return 0x1A2B3C4D5E6F7081 & 0xFFFFFFFFFFFFFFFF - - @classmethod - def _get_packed_fingerprint(cls) -> bytes: - if cls._packed_fingerprint is None: - cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) # type: ignore[no-untyped-call] - return cls._packed_fingerprint - - def __str__(self) -> str: - return f"TrajectoryPoint(t={self.time_from_start:.3f}s, {self.num_joints} joints)" - - def __repr__(self) -> str: - return ( - f"TrajectoryPoint(time_from_start={self.time_from_start}, " - f"positions={self.positions}, velocities={self.velocities})" - ) - - def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] - if not isinstance(other, TrajectoryPoint): - return False - return ( - self.time_from_start == other.time_from_start - and self.positions == other.positions - and self.velocities == other.velocities - ) diff --git a/dimos/msgs/trajectory_msgs/TrajectoryStatus.py b/dimos/msgs/trajectory_msgs/TrajectoryStatus.py deleted file mode 100644 index 0a3c117e685..00000000000 --- a/dimos/msgs/trajectory_msgs/TrajectoryStatus.py +++ /dev/null @@ -1,170 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -TrajectoryStatus message type. - -Status feedback for trajectory execution. -""" - -from enum import IntEnum -from io import BytesIO -import struct -import time - - -class TrajectoryState(IntEnum): - """States for trajectory execution.""" - - IDLE = 0 # No trajectory, ready to accept - EXECUTING = 1 # Currently executing trajectory - COMPLETED = 2 # Trajectory finished successfully - ABORTED = 3 # Trajectory was cancelled - FAULT = 4 # Error occurred, requires reset() - - -class TrajectoryStatus: - """ - Status of trajectory execution. - - Attributes: - timestamp: When status was generated - state: Current TrajectoryState - progress: Progress 0.0 to 1.0 - time_elapsed: Seconds since trajectory start - time_remaining: Estimated seconds remaining - error: Error message if FAULT state (empty string otherwise) - """ - - msg_name = "trajectory_msgs.TrajectoryStatus" - - __slots__ = ["error", "progress", "state", "time_elapsed", "time_remaining", "timestamp"] - - def __init__( - self, - state: TrajectoryState = TrajectoryState.IDLE, - progress: float = 0.0, - time_elapsed: float = 0.0, - time_remaining: float = 0.0, - error: str = "", - timestamp: float | None = None, - ) -> None: - """ - Initialize TrajectoryStatus. - - Args: - state: Current execution state - progress: Progress through trajectory (0.0 to 1.0) - time_elapsed: Time since trajectory start (seconds) - time_remaining: Estimated time remaining (seconds) - error: Error message if in FAULT state - timestamp: When status was generated (defaults to now) - """ - self.timestamp = timestamp if timestamp is not None else time.time() - self.state = state - self.progress = progress - self.time_elapsed = time_elapsed - self.time_remaining = time_remaining - self.error = error - - @property - def state_name(self) -> str: - """Get human-readable state name.""" - return self.state.name - - def is_done(self) -> bool: - """Check if trajectory execution is finished (completed, aborted, or fault).""" - return self.state in ( - TrajectoryState.COMPLETED, - TrajectoryState.ABORTED, - TrajectoryState.FAULT, - ) - - def is_active(self) -> bool: - """Check if trajectory is currently executing.""" - return self.state == TrajectoryState.EXECUTING - - def lcm_encode(self) -> bytes: - """Encode for LCM transport.""" - return self.encode() - - def encode(self) -> bytes: - buf = BytesIO() - buf.write(TrajectoryStatus._get_packed_fingerprint()) - self._encode_one(buf) - return buf.getvalue() - - def _encode_one(self, buf: BytesIO) -> None: - # timestamp (double) - buf.write(struct.pack(">d", self.timestamp)) - # state (int32) - buf.write(struct.pack(">i", int(self.state))) - # progress (double) - buf.write(struct.pack(">d", self.progress)) - # time_elapsed (double) - buf.write(struct.pack(">d", self.time_elapsed)) - # time_remaining (double) - buf.write(struct.pack(">d", self.time_remaining)) - # error (string) - error_bytes = self.error.encode("utf-8") - buf.write(struct.pack(">i", len(error_bytes))) - buf.write(error_bytes) - - @classmethod - def lcm_decode(cls, data: bytes) -> "TrajectoryStatus": - """Decode from LCM transport.""" - return cls.decode(data) - - @classmethod - def decode(cls, data: bytes) -> "TrajectoryStatus": - buf = BytesIO(data) if not hasattr(data, "read") else data - if buf.read(8) != cls._get_packed_fingerprint(): - raise ValueError("Decode error: fingerprint mismatch") - return cls._decode_one(buf) # type: ignore[arg-type] - - @classmethod - def _decode_one(cls, buf: BytesIO) -> "TrajectoryStatus": - self = cls.__new__(cls) - self.timestamp = struct.unpack(">d", buf.read(8))[0] - self.state = TrajectoryState(struct.unpack(">i", buf.read(4))[0]) - self.progress = struct.unpack(">d", buf.read(8))[0] - self.time_elapsed = struct.unpack(">d", buf.read(8))[0] - self.time_remaining = struct.unpack(">d", buf.read(8))[0] - error_len = struct.unpack(">i", buf.read(4))[0] - self.error = buf.read(error_len).decode("utf-8") - return self - - _packed_fingerprint = None - - @classmethod - def _get_hash_recursive(cls, parents): # type: ignore[no-untyped-def] - if cls in parents: - return 0 - return 0x3C4D5E6F708192A3 & 0xFFFFFFFFFFFFFFFF - - @classmethod - def _get_packed_fingerprint(cls) -> bytes: - if cls._packed_fingerprint is None: - cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) # type: ignore[no-untyped-call] - return cls._packed_fingerprint - - def __str__(self) -> str: - return f"TrajectoryStatus({self.state_name}, progress={self.progress:.1%})" - - def __repr__(self) -> str: - return ( - f"TrajectoryStatus(state={self.state_name}, progress={self.progress}, " - f"time_elapsed={self.time_elapsed}, time_remaining={self.time_remaining}, " - f"error='{self.error}')" - ) diff --git a/dimos/msgs/vision_msgs/BoundingBox2DArray.py b/dimos/msgs/vision_msgs/BoundingBox2DArray.py deleted file mode 100644 index f376de6372a..00000000000 --- a/dimos/msgs/vision_msgs/BoundingBox2DArray.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from dimos_lcm.vision_msgs.BoundingBox2DArray import ( - BoundingBox2DArray as LCMBoundingBox2DArray, -) - - -class BoundingBox2DArray(LCMBoundingBox2DArray): # type: ignore[misc] - msg_name = "vision_msgs.BoundingBox2DArray" diff --git a/dimos/msgs/vision_msgs/BoundingBox3DArray.py b/dimos/msgs/vision_msgs/BoundingBox3DArray.py deleted file mode 100644 index d8d7775f919..00000000000 --- a/dimos/msgs/vision_msgs/BoundingBox3DArray.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from dimos_lcm.vision_msgs.BoundingBox3DArray import ( - BoundingBox3DArray as LCMBoundingBox3DArray, -) - - -class BoundingBox3DArray(LCMBoundingBox3DArray): # type: ignore[misc] - msg_name = "vision_msgs.BoundingBox3DArray" diff --git a/dimos/msgs/vision_msgs/Detection2D.py b/dimos/msgs/vision_msgs/Detection2D.py deleted file mode 100644 index aa957f80614..00000000000 --- a/dimos/msgs/vision_msgs/Detection2D.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from dimos_lcm.vision_msgs.Detection2D import Detection2D as LCMDetection2D - -from dimos.types.timestamped import to_timestamp - - -class Detection2D(LCMDetection2D): # type: ignore[misc] - msg_name = "vision_msgs.Detection2D" - - # for _get_field_type() to work when decoding in _decode_one() - __annotations__ = LCMDetection2D.__annotations__ - - @property - def ts(self) -> float: - return to_timestamp(self.header.stamp) diff --git a/dimos/msgs/vision_msgs/Detection3D.py b/dimos/msgs/vision_msgs/Detection3D.py deleted file mode 100644 index 76a838041a4..00000000000 --- a/dimos/msgs/vision_msgs/Detection3D.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2025-2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -from dimos_lcm.vision_msgs.Detection3D import Detection3D as LCMDetection3D - -from dimos.types.timestamped import to_timestamp - - -class Detection3D(LCMDetection3D): # type: ignore[misc] - msg_name = "vision_msgs.Detection3D" - - # for _get_field_type() to work when decoding in _decode_one() - __annotations__ = LCMDetection3D.__annotations__ - - @property - def ts(self) -> float: - return to_timestamp(self.header.stamp) - - @property - def frame_id(self) -> str: - return str(self.header.frame_id) diff --git a/dimos/msgs/visualization_msgs/EntityMarkers.py b/dimos/msgs/visualization_msgs/EntityMarkers.py deleted file mode 100644 index 86ba74d72e9..00000000000 --- a/dimos/msgs/visualization_msgs/EntityMarkers.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Labeled 3D entity markers for Rerun visualization. - -Published by modules that track entities in world coordinates. -The Rerun bridge picks these up via ``to_rerun()`` and renders them -as labeled colored points overlaid on the 3D scene. -""" - -from __future__ import annotations - -from dataclasses import dataclass -from io import BytesIO -import json -import struct -import time -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from rerun._baseclasses import Archetype - -from dimos.types.timestamped import Timestamped - -# Entity type → RGBA color -TYPE_COLORS: dict[str, tuple[int, int, int, int]] = { - "person": (255, 100, 100, 255), - "object": (100, 255, 100, 255), - "location": (100, 100, 255, 255), -} -DEFAULT_COLOR = (200, 200, 200, 255) - - -@dataclass -class Marker: - """A single entity marker in world coordinates.""" - - entity_id: str - label: str - entity_type: str # person | object | location - x: float - y: float - z: float - - -class EntityMarkers(Timestamped): - """A batch of labeled 3D entity markers. - - Wire format: JSON-encoded list of markers over LCM string channel. - Rerun: ``rr.Points3D`` with per-point labels and colors. - """ - - msg_name = "visualization_msgs.EntityMarkers" - - def __init__( - self, - markers: list[Marker] | None = None, - ts: float | None = None, - ) -> None: - self.markers: list[Marker] = markers or [] - self.ts: float = ts or time.time() - - # -- LCM serialization (JSON payload) -- - - def _encode_one(self, buf: BytesIO) -> None: - payload = json.dumps( - [ - { - "id": m.entity_id, - "label": m.label, - "type": m.entity_type, - "x": m.x, - "y": m.y, - "z": m.z, - } - for m in self.markers - ] - ).encode() - buf.write(struct.pack(">I", len(payload))) - buf.write(payload) - - def encode(self) -> bytes: - buf = BytesIO() - self._encode_one(buf) - return buf.getvalue() - - @classmethod - def _decode_one(cls, buf: BytesIO) -> EntityMarkers: - (length,) = struct.unpack(">I", buf.read(4)) - payload = json.loads(buf.read(length).decode()) - markers = [ - Marker( - entity_id=m["id"], - label=m["label"], - entity_type=m["type"], - x=m["x"], - y=m["y"], - z=m["z"], - ) - for m in payload - ] - return cls(markers=markers) - - @classmethod - def decode(cls, data: bytes) -> EntityMarkers: - return cls._decode_one(BytesIO(data)) - - # -- Rerun conversion -- - - def to_rerun(self) -> Archetype: - import rerun as rr - - if not self.markers: - return rr.Points3D([]) - - positions = [[m.x, m.y, m.z] for m in self.markers] - labels = [f"{m.entity_id}: {m.label[:40]}" for m in self.markers] - colors = [TYPE_COLORS.get(m.entity_type, DEFAULT_COLOR) for m in self.markers] - - return rr.Points3D( - positions=positions, - labels=labels, - colors=colors, - radii=[0.15] * len(self.markers), - ) - - # -- LCM compat (so autoconnect assigns LCMTransport, not pLCM) -- - - def lcm_encode(self) -> bytes: - return self.encode() - - @classmethod - def lcm_decode(cls, data: bytes, **kwargs: object) -> EntityMarkers: - return cls.decode(data) diff --git a/examples/language-interop/lua/.gitignore b/examples/language-interop/lua/.gitignore deleted file mode 100644 index f87dd2d1251..00000000000 --- a/examples/language-interop/lua/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -lcm/ -dimos-lcm/ -msgs/ diff --git a/examples/language-interop/lua/main.lua b/examples/language-interop/lua/main.lua deleted file mode 100644 index f6d2dccca17..00000000000 --- a/examples/language-interop/lua/main.lua +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env lua - --- Lua robot control example --- Subscribes to robot pose and publishes twist commands - --- Add local msgs folder to path -local script_dir = arg[0]:match("(.*/)") or "./" -package.path = script_dir .. "msgs/?.lua;" .. package.path -package.path = script_dir .. "msgs/?/init.lua;" .. package.path - -local lcm = require("lcm") -local PoseStamped = require("geometry_msgs.PoseStamped") -local Twist = require("geometry_msgs.Twist") -local Vector3 = require("geometry_msgs.Vector3") - -local lc = lcm.lcm.new() - -print("Robot control started") -print("Subscribing to /odom, publishing to /cmd_vel") -print("Press Ctrl+C to stop.\n") - --- Subscribe to pose -lc:subscribe("/odom#geometry_msgs.PoseStamped", function(channel, msg) - msg = PoseStamped.decode(msg) - local pos = msg.pose.position - local ori = msg.pose.orientation - print(string.format("[pose] x=%.2f y=%.2f z=%.2f | qw=%.2f", - pos.x, pos.y, pos.z, ori.w)) -end) - --- Publisher loop -local t = 0 -local socket = require("socket") -local last_pub = socket.gettime() - -while true do - -- Handle incoming messages - lc:handle() - - -- Publish at ~10 Hz - local now = socket.gettime() - if now - last_pub >= 0.1 then - local twist = Twist:new() - twist.linear = Vector3:new() - twist.linear.x = 0.5 - twist.linear.y = 0 - twist.linear.z = 0 - twist.angular = Vector3:new() - twist.angular.x = 0 - twist.angular.y = 0 - twist.angular.z = math.sin(t) * 0.3 - - lc:publish("/cmd_vel#geometry_msgs.Twist", twist:encode()) - print(string.format("[twist] linear=%.2f angular=%.2f", twist.linear.x, twist.angular.z)) - - t = t + 0.1 - last_pub = now - end -end diff --git a/examples/language-interop/lua/setup.sh b/examples/language-interop/lua/setup.sh deleted file mode 100755 index 682d676183e..00000000000 --- a/examples/language-interop/lua/setup.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/bash -# Setup script for LCM Lua bindings -# Clones official LCM repo and builds Lua bindings -# -# Tested on: Arch Linux, Ubuntu, macOS (with Homebrew) - -set -e - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -LCM_DIR="$SCRIPT_DIR/lcm" - -echo "=== LCM Lua Setup ===" - -# Detect Lua version -if command -v lua &>/dev/null; then - LUA_VERSION=$(lua -v 2>&1 | grep -oE '[0-9]+\.[0-9]+' | head -1) - echo "Detected Lua version: $LUA_VERSION" -else - echo "Error: lua not found in PATH" - exit 1 -fi - -# Detect Lua paths using pkg-config if available -if command -v pkg-config &>/dev/null && pkg-config --exists "lua$LUA_VERSION" 2>/dev/null; then - LUA_INCLUDE_DIR=$(pkg-config --variable=includedir "lua$LUA_VERSION") - LUA_LIBRARY=$(pkg-config --libs "lua$LUA_VERSION" | grep -oE '/[^ ]+\.so' | head -1 || echo "") -elif command -v pkg-config &>/dev/null && pkg-config --exists lua 2>/dev/null; then - LUA_INCLUDE_DIR=$(pkg-config --variable=includedir lua) - LUA_LIBRARY=$(pkg-config --libs lua | grep -oE '/[^ ]+\.so' | head -1 || echo "") -fi - -# Platform-specific defaults -if [[ "$OSTYPE" == "darwin"* ]]; then - # macOS with Homebrew - LUA_INCLUDE_DIR="${LUA_INCLUDE_DIR:-$(brew --prefix lua 2>/dev/null)/include/lua}" - LUA_LIBRARY="${LUA_LIBRARY:-$(brew --prefix lua 2>/dev/null)/lib/liblua.dylib}" - LUA_CPATH_BASE="${LUA_CPATH_BASE:-/usr/local/lib/lua}" -else - # Linux defaults - LUA_INCLUDE_DIR="${LUA_INCLUDE_DIR:-/usr/include}" - LUA_LIBRARY="${LUA_LIBRARY:-/usr/lib/liblua.so}" - LUA_CPATH_BASE="${LUA_CPATH_BASE:-/usr/local/lib/lua}" -fi - -echo "Lua include: $LUA_INCLUDE_DIR" -echo "Lua library: $LUA_LIBRARY" - -# Clone LCM if not present -if [ ! -d "$LCM_DIR" ]; then - echo "Cloning LCM..." - git clone --depth 1 https://github.com/lcm-proj/lcm.git "$LCM_DIR" -else - echo "LCM already cloned" -fi - -# Build Lua bindings using cmake -echo "Building LCM Lua bindings..." -cd "$LCM_DIR" -mkdir -p build && cd build - -# Configure with Lua support -cmake .. \ - -DLCM_ENABLE_LUA=ON \ - -DLCM_ENABLE_PYTHON=OFF \ - -DLCM_ENABLE_JAVA=OFF \ - -DLCM_ENABLE_TESTS=OFF \ - -DLCM_ENABLE_EXAMPLES=OFF \ - -DLUA_INCLUDE_DIR="$LUA_INCLUDE_DIR" \ - -DLUA_LIBRARY="$LUA_LIBRARY" - -# Build just the lua target -make lcm-lua -j$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4) - -# Install the lua module -LUA_CPATH_DIR="$LUA_CPATH_BASE/$LUA_VERSION" -echo "Installing lcm.so to $LUA_CPATH_DIR" -sudo mkdir -p "$LUA_CPATH_DIR" -sudo cp lcm-lua/lcm.so "$LUA_CPATH_DIR/" - -# Get dimos-lcm message definitions -DIMOS_LCM_DIR="$SCRIPT_DIR/dimos-lcm" -MSGS_DST="$SCRIPT_DIR/msgs" - -echo "Getting message definitions..." -if [ -d "$DIMOS_LCM_DIR" ]; then - echo "Updating dimos-lcm..." - cd "$DIMOS_LCM_DIR" && git pull -else - echo "Cloning dimos-lcm..." - git clone --depth 1 https://github.com/dimensionalOS/dimos-lcm.git "$DIMOS_LCM_DIR" -fi - -# Link/copy messages -rm -rf "$MSGS_DST" -cp -r "$DIMOS_LCM_DIR/generated/lua_lcm_msgs" "$MSGS_DST" -echo "Messages installed to $MSGS_DST" - -echo "" -echo "=== Setup complete ===" -echo "Run: lua main.lua" diff --git a/examples/language-interop/ts/deno.json b/examples/language-interop/ts/deno.json deleted file mode 100644 index b64363a64a7..00000000000 --- a/examples/language-interop/ts/deno.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "imports": { - "@dimos/lcm": "jsr:@dimos/lcm", - "@dimos/msgs": "jsr:@dimos/msgs" - }, - "tasks": { - "start": "deno run --allow-net --unstable-net main.ts" - } -} diff --git a/examples/language-interop/ts/deno.lock b/examples/language-interop/ts/deno.lock deleted file mode 100644 index 9529ebdb342..00000000000 --- a/examples/language-interop/ts/deno.lock +++ /dev/null @@ -1,21 +0,0 @@ -{ - "version": "5", - "specifiers": { - "jsr:@dimos/lcm@*": "0.2.0", - "jsr:@dimos/msgs@*": "0.1.4" - }, - "jsr": { - "@dimos/lcm@0.2.0": { - "integrity": "03399f5e4800f28a0c294981e0210d784232fc65a57707de19052ad805bd5fea" - }, - "@dimos/msgs@0.1.4": { - "integrity": "564bc30b4bc41a562c296c257a15055283ca0cbd66d0627991ede5295832d0c4" - } - }, - "workspace": { - "dependencies": [ - "jsr:@dimos/lcm@*", - "jsr:@dimos/msgs@*" - ] - } -} diff --git a/examples/language-interop/ts/main.ts b/examples/language-interop/ts/main.ts deleted file mode 100644 index 9026304f2c6..00000000000 --- a/examples/language-interop/ts/main.ts +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env -S deno run --allow-net --unstable-net - -// TypeScript robot control example -// Subscribes to robot odometry and publishes twist commands - -import { LCM } from "@dimos/lcm"; -import { geometry_msgs } from "@dimos/msgs"; - -const lcm = new LCM(); -await lcm.start(); - -console.log("Robot control started"); -console.log("Subscribing to /odom, publishing to /cmd_vel"); -console.log("Press Ctrl+C to stop.\n"); - -// Subscribe to pose - prints robot position -lcm.subscribe("/odom", geometry_msgs.PoseStamped, (msg) => { - const pos = msg.data.pose.position; - const ori = msg.data.pose.orientation; - console.log( - `[pose] x=${pos.x.toFixed(2)} y=${pos.y.toFixed(2)} z=${pos.z.toFixed(2)} | qw=${ori.w.toFixed(2)}` - ); -}); - -// Publish twist commands at 10 Hz - simple forward motion -let t = 0; -const interval = setInterval(async () => { - if (!lcm.isRunning()) { - clearInterval(interval); - return; - } - - const twist = new geometry_msgs.Twist({ - linear: new geometry_msgs.Vector3({ x: 0.5, y: 0, z: 0 }), - angular: new geometry_msgs.Vector3({ x: 0, y: 0, z: Math.sin(t) * 0.3 }), - }); - - await lcm.publish("/cmd_vel", twist); - console.log(`[twist] linear=${twist.linear.x.toFixed(2)} angular=${twist.angular.z.toFixed(2)}`); - t += 0.1; -}, 100); - -await lcm.run(); diff --git a/examples/language-interop/ts/web/index.html b/examples/language-interop/ts/web/index.html deleted file mode 100644 index 1ce89604b6b..00000000000 --- a/examples/language-interop/ts/web/index.html +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - Robot Control - - - -

Robot Control

-
Connecting...
- -
-
-

Pose

-
X--
-
Y--
-
Z--
-
Qw--
-
- -
-

Controls

-
-
- -
- - - -
- -
-
-
- -
-

Log

-
-
- - - - diff --git a/examples/language-interop/ts/web/server.ts b/examples/language-interop/ts/web/server.ts deleted file mode 100644 index 5b8ec035bef..00000000000 --- a/examples/language-interop/ts/web/server.ts +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env -S deno run --allow-net --allow-read --unstable-net - -// LCM to WebSocket Bridge for Robot Control -// Forwards robot pose to browser, receives twist commands from browser - -import { LCM } from "jsr:@dimos/lcm"; -import { decodePacket, geometry_msgs } from "jsr:@dimos/msgs"; - -const PORT = 8080; -const clients = new Set(); - -Deno.serve({ port: PORT }, async (req) => { - const url = new URL(req.url); - - if (req.headers.get("upgrade") === "websocket") { - const { socket, response } = Deno.upgradeWebSocket(req); - socket.onopen = () => { console.log("Client connected"); clients.add(socket); }; - socket.onclose = () => { console.log("Client disconnected"); clients.delete(socket); }; - socket.onerror = () => clients.delete(socket); - - // Forward binary LCM packets from browser directly to UDP - socket.binaryType = "arraybuffer"; - socket.onmessage = async (event) => { - if (event.data instanceof ArrayBuffer) { - const packet = new Uint8Array(event.data); - try { - // we don't need to decode, just showing we can - const { channel, data } = decodePacket(packet); - console.log(`[ws->lcm] ${channel}`, data); - await lcm.publishPacket(packet); - } catch (e) { - console.error("Forward error:", e); - } - } - }; - - return response; - } - - if (url.pathname === "/" || url.pathname === "/index.html") { - const html = await Deno.readTextFile(new URL("./index.html", import.meta.url)); - return new Response(html, { headers: { "content-type": "text/html" } }); - } - - return new Response("Not found", { status: 404 }); -}); - -console.log(`Server: http://localhost:${PORT}`); - -const lcm = new LCM(); -await lcm.start(); - -// Subscribe to pose and just log to show how server can decode messages for itself -lcm.subscribe("/odom", geometry_msgs.PoseStamped, (msg) => { - const pos = msg.data.pose.position; - const ori = msg.data.pose.orientation; - console.log(`[pose] x=${pos.x.toFixed(2)} y=${pos.y.toFixed(2)} z=${pos.z.toFixed(2)}`); -}); - -// Forward all raw packets to browser (we are decoding LCM directly in the browser) -lcm.subscribePacket((packet) => { - for (const client of clients) { - if (client.readyState === WebSocket.OPEN) { - client.send(packet); - } - } -}); - -await lcm.run(); From 9b115a477c399fa29a22940863c909bd63abfc19 Mon Sep 17 00:00:00 2001 From: cc Date: Mon, 5 Oct 2026 23:41:04 -0700 Subject: [PATCH 02/11] fix: retain original legacy message interfaces for migration --- dimos/msgs/foxglove_msgs/CompressedVideo.py | 107 +++ dimos/msgs/geometry_msgs/Point.py | 33 + dimos/msgs/geometry_msgs/PointStamped.py | 102 +++ dimos/msgs/geometry_msgs/Pose.py | 265 +++++++ .../msgs/geometry_msgs/PoseWithCovariance.py | 201 +++++ .../PoseWithCovarianceStamped.py | 98 +++ dimos/msgs/geometry_msgs/Quaternion.py | 325 ++++++++ dimos/msgs/geometry_msgs/Transform.py | 329 ++++++++ dimos/msgs/geometry_msgs/Twist.py | 132 ++++ dimos/msgs/geometry_msgs/TwistStamped.py | 85 +++ .../msgs/geometry_msgs/TwistWithCovariance.py | 181 +++++ .../TwistWithCovarianceStamped.py | 106 +++ dimos/msgs/geometry_msgs/Vector3.py | 434 +++++++++++ dimos/msgs/geometry_msgs/Wrench.py | 121 +++ dimos/msgs/geometry_msgs/WrenchStamped.py | 97 +++ .../msgs/manipulation_msgs/GraspCandidate.py | 40 + .../manipulation_msgs/GraspCandidateArray.py | 48 ++ dimos/msgs/nav_msgs/OccupancyGrid.py | 598 +++++++++++++++ dimos/msgs/nav_msgs/Odometry.py | 249 +++++++ dimos/msgs/nav_msgs/Path.py | 214 ++++++ dimos/msgs/sensor_msgs/CompressedImage.py | 175 +++++ dimos/msgs/sensor_msgs/Image.py | 700 ++++++++++++++++++ dimos/msgs/sensor_msgs/Imu.py | 125 ++++ dimos/msgs/sensor_msgs/ImuInfo.py | 158 ++++ dimos/msgs/sensor_msgs/JointCommand.py | 143 ++++ dimos/msgs/sensor_msgs/JointState.py | 144 ++++ dimos/msgs/sensor_msgs/Joy.py | 130 ++++ dimos/msgs/sensor_msgs/MotorCommandArray.py | 133 ++++ dimos/msgs/sensor_msgs/RobotState.py | 188 +++++ .../sensor_msgs/image_impls/AbstractImage.py | 17 + dimos/msgs/std_msgs/Bool.py | 28 + dimos/msgs/std_msgs/Float32.py | 30 + dimos/msgs/std_msgs/Header.py | 106 +++ dimos/msgs/std_msgs/Int32.py | 32 + dimos/msgs/std_msgs/Int8.py | 32 + dimos/msgs/std_msgs/String.py | 30 + dimos/msgs/std_msgs/UInt32.py | 30 + dimos/msgs/trajectory_msgs/JointTrajectory.py | 211 ++++++ dimos/msgs/trajectory_msgs/TrajectoryPoint.py | 136 ++++ .../msgs/trajectory_msgs/TrajectoryStatus.py | 170 +++++ dimos/msgs/vision_msgs/BoundingBox2DArray.py | 21 + dimos/msgs/vision_msgs/BoundingBox3DArray.py | 21 + dimos/msgs/vision_msgs/Detection2D.py | 27 + dimos/msgs/vision_msgs/Detection3D.py | 31 + .../msgs/visualization_msgs/EntityMarkers.py | 145 ++++ 45 files changed, 6728 insertions(+) create mode 100644 dimos/msgs/foxglove_msgs/CompressedVideo.py create mode 100644 dimos/msgs/geometry_msgs/Point.py create mode 100644 dimos/msgs/geometry_msgs/PointStamped.py create mode 100644 dimos/msgs/geometry_msgs/Pose.py create mode 100644 dimos/msgs/geometry_msgs/PoseWithCovariance.py create mode 100644 dimos/msgs/geometry_msgs/PoseWithCovarianceStamped.py create mode 100644 dimos/msgs/geometry_msgs/Quaternion.py create mode 100644 dimos/msgs/geometry_msgs/Transform.py create mode 100644 dimos/msgs/geometry_msgs/Twist.py create mode 100644 dimos/msgs/geometry_msgs/TwistStamped.py create mode 100644 dimos/msgs/geometry_msgs/TwistWithCovariance.py create mode 100644 dimos/msgs/geometry_msgs/TwistWithCovarianceStamped.py create mode 100644 dimos/msgs/geometry_msgs/Vector3.py create mode 100644 dimos/msgs/geometry_msgs/Wrench.py create mode 100644 dimos/msgs/geometry_msgs/WrenchStamped.py create mode 100644 dimos/msgs/manipulation_msgs/GraspCandidate.py create mode 100644 dimos/msgs/manipulation_msgs/GraspCandidateArray.py create mode 100644 dimos/msgs/nav_msgs/OccupancyGrid.py create mode 100644 dimos/msgs/nav_msgs/Odometry.py create mode 100644 dimos/msgs/nav_msgs/Path.py create mode 100644 dimos/msgs/sensor_msgs/CompressedImage.py create mode 100644 dimos/msgs/sensor_msgs/Image.py create mode 100644 dimos/msgs/sensor_msgs/Imu.py create mode 100644 dimos/msgs/sensor_msgs/ImuInfo.py create mode 100644 dimos/msgs/sensor_msgs/JointCommand.py create mode 100644 dimos/msgs/sensor_msgs/JointState.py create mode 100644 dimos/msgs/sensor_msgs/Joy.py create mode 100644 dimos/msgs/sensor_msgs/MotorCommandArray.py create mode 100644 dimos/msgs/sensor_msgs/RobotState.py create mode 100644 dimos/msgs/sensor_msgs/image_impls/AbstractImage.py create mode 100644 dimos/msgs/std_msgs/Bool.py create mode 100644 dimos/msgs/std_msgs/Float32.py create mode 100644 dimos/msgs/std_msgs/Header.py create mode 100644 dimos/msgs/std_msgs/Int32.py create mode 100644 dimos/msgs/std_msgs/Int8.py create mode 100644 dimos/msgs/std_msgs/String.py create mode 100644 dimos/msgs/std_msgs/UInt32.py create mode 100644 dimos/msgs/trajectory_msgs/JointTrajectory.py create mode 100644 dimos/msgs/trajectory_msgs/TrajectoryPoint.py create mode 100644 dimos/msgs/trajectory_msgs/TrajectoryStatus.py create mode 100644 dimos/msgs/vision_msgs/BoundingBox2DArray.py create mode 100644 dimos/msgs/vision_msgs/BoundingBox3DArray.py create mode 100644 dimos/msgs/vision_msgs/Detection2D.py create mode 100644 dimos/msgs/vision_msgs/Detection3D.py create mode 100644 dimos/msgs/visualization_msgs/EntityMarkers.py diff --git a/dimos/msgs/foxglove_msgs/CompressedVideo.py b/dimos/msgs/foxglove_msgs/CompressedVideo.py new file mode 100644 index 00000000000..b13089c303b --- /dev/null +++ b/dimos/msgs/foxglove_msgs/CompressedVideo.py @@ -0,0 +1,107 @@ +# Copyright 2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""foxglove_msgs::msg::CompressedVideo — one encoded video packet. + +Just the encoded bytes + codec name. Inter-frame codecs (h264) can't be decoded +one packet at a time — feed the ordered stream through +:class:`~dimos.robot.unitree.go2.dds.video.H264Decoder` to get ``Image`` frames, +or let the rerun bridge log it as a ``VideoStream`` and decode in-viewer. +""" + +from __future__ import annotations + +import time +from typing import TYPE_CHECKING + +from dimos_lcm.foxglove_msgs import CompressedVideo as LCMCompressedVideo +import numpy as np + +from dimos.types.timestamped import Timestamped + +if TYPE_CHECKING: + from dimos.visualization.rerun.bridge import RerunData + + +class CompressedVideo(Timestamped): + """One encoded video packet (Annex-B for h264).""" + + msg_name = "foxglove_msgs.CompressedVideo" + + def __init__( + self, + data: np.ndarray | bytes, + format: str = "h264", + frame_id: str = "", + ts: float | None = None, + ) -> None: + """Initialize a CompressedVideo. + + Args: + data: The encoded packet, u8 + format: Codec name, e.g. "h264" + frame_id: Frame ID + ts: Timestamp in seconds + """ + self.data = data if isinstance(data, np.ndarray) else np.frombuffer(data, dtype=np.uint8) + self.format = format + self.frame_id = frame_id + self.ts = ts if ts is not None else time.time() + + def lcm_encode(self) -> bytes: + msg = LCMCompressedVideo() + msg.timestamp.sec = int(self.ts) + msg.timestamp.nanosec = int((self.ts - int(self.ts)) * 1e9) + msg.frame_id = self.frame_id + msg.data = self.data.tobytes() + msg.data_length = len(msg.data) + msg.format = self.format + return msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes) -> CompressedVideo: + msg = LCMCompressedVideo.lcm_decode(data) + return cls( + data=bytes(msg.data), + format=msg.format, + frame_id=msg.frame_id, + ts=msg.timestamp.sec + msg.timestamp.nanosec * 1e-9, + ) + + def to_rerun(self) -> RerunData: + """Log the encoded packet as a rerun ``VideoStream`` sample (viewer decodes). + + rerun decodes the stream in-viewer, so this stays per-packet and cheap — + no server-side decode, and the .rrd holds the compressed bytes. Iterate + from the start (or a keyframe) so the first sample the viewer sees is one. + """ + import rerun as rr + + codecs = { + "h264": rr.VideoCodec.H264, + "h265": rr.VideoCodec.H265, + "av1": rr.VideoCodec.AV1, + "vp8": rr.VideoCodec.VP8, + "vp9": rr.VideoCodec.VP9, + } + codec = codecs.get(self.format.lower()) + if codec is None: + raise ValueError(f"no rerun VideoCodec for format {self.format!r}") + return rr.VideoStream(codec, sample=self.data.tobytes()) + + def __repr__(self) -> str: + return ( + f"CompressedVideo(format='{self.format}', bytes={self.data.size}, " + f"frame_id='{self.frame_id}', ts={self.ts})" + ) diff --git a/dimos/msgs/geometry_msgs/Point.py b/dimos/msgs/geometry_msgs/Point.py new file mode 100644 index 00000000000..84f260dc8a4 --- /dev/null +++ b/dimos/msgs/geometry_msgs/Point.py @@ -0,0 +1,33 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from dimos_lcm.geometry_msgs import Point as LCMPoint + + +class Point(LCMPoint): # type: ignore[misc] + """DimOS wrapper for geometry_msgs.Point (3D position). + + Inherits x/y/z from LCMPoint. Wire-identical to Vector3 but + semantically represents a position, not a direction/displacement. + """ + + msg_name = "geometry_msgs.Point" + + def __init__(self, x: float = 0.0, y: float = 0.0, z: float = 0.0) -> None: + super().__init__(float(x), float(y), float(z)) + + def __repr__(self) -> str: + return f"Point(x={self.x}, y={self.y}, z={self.z})" diff --git a/dimos/msgs/geometry_msgs/PointStamped.py b/dimos/msgs/geometry_msgs/PointStamped.py new file mode 100644 index 00000000000..8d305d99493 --- /dev/null +++ b/dimos/msgs/geometry_msgs/PointStamped.py @@ -0,0 +1,102 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import time +from typing import TYPE_CHECKING, BinaryIO + +if TYPE_CHECKING: + from rerun._baseclasses import Archetype + + from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped + +from dimos_lcm.geometry_msgs import PointStamped as LCMPointStamped + +from dimos.msgs.geometry_msgs.Point import Point +from dimos.types.timestamped import Timestamped + + +class PointStamped(Point, Timestamped): + """A 3D point with timestamp and frame_id. + + Follows the same pattern as PoseStamped(Pose, Timestamped) and + TwistStamped(Twist, Timestamped). Inherits x/y/z from Point + (which inherits from LCMPoint). + """ + + msg_name = "geometry_msgs.PointStamped" + ts: float + frame_id: str + + def __init__( + self, + x: float = 0.0, + y: float = 0.0, + z: float = 0.0, + ts: float | None = None, + frame_id: str = "", + ) -> None: + self.frame_id = frame_id + self.ts = time.time() if ts is None else ts + super().__init__(float(x), float(y), float(z)) + + # -- LCM encode / decode -- + + def lcm_encode(self) -> bytes: + """Encode to LCM binary format.""" + lcm_msg = LCMPointStamped() + lcm_msg.point = self # Works because Point inherits from LCMPoint + [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = self.ros_timestamp() + lcm_msg.header.frame_id = self.frame_id + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes | BinaryIO) -> PointStamped: + """Decode from LCM binary format.""" + lcm_msg = LCMPointStamped.lcm_decode(data) + return cls( + x=lcm_msg.point.x, + y=lcm_msg.point.y, + z=lcm_msg.point.z, + ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), + frame_id=lcm_msg.header.frame_id, + ) + + # -- Conversion methods -- + + def to_rerun(self) -> Archetype: + """Convert to rerun Points3D archetype for visualization.""" + import rerun as rr + + return rr.Points3D(positions=[[self.x, self.y, self.z]]) + + def to_pose_stamped(self) -> PoseStamped: + """Convert to PoseStamped with identity quaternion orientation.""" + from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped + + return PoseStamped( + ts=self.ts, + frame_id=self.frame_id, + position=[self.x, self.y, self.z], + orientation=[0.0, 0.0, 0.0, 1.0], + ) + + # -- String representations -- + + def __str__(self) -> str: + return f"PointStamped(point=[{self.x:.3f}, {self.y:.3f}, {self.z:.3f}], frame_id={self.frame_id!r})" + + def __repr__(self) -> str: + return f"PointStamped(x={self.x}, y={self.y}, z={self.z}, ts={self.ts}, frame_id={self.frame_id!r})" diff --git a/dimos/msgs/geometry_msgs/Pose.py b/dimos/msgs/geometry_msgs/Pose.py new file mode 100644 index 00000000000..985a677c70f --- /dev/null +++ b/dimos/msgs/geometry_msgs/Pose.py @@ -0,0 +1,265 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from typing import Any, TypeAlias, overload + +from dimos_lcm.geometry_msgs import ( + Pose as LCMPose, + Transform as LCMTransform, +) +from plum import dispatch + +from dimos.msgs.geometry_msgs.Quaternion import Quaternion, QuaternionConvertable +from dimos.msgs.geometry_msgs.Transform import Transform +from dimos.msgs.geometry_msgs.Vector3 import Vector3, VectorConvertable + +# Types that can be converted to/from Pose +PoseConvertable: TypeAlias = ( + tuple[VectorConvertable, QuaternionConvertable] + | LCMPose + | Vector3 + | dict[str, VectorConvertable | QuaternionConvertable] +) + + +def _is_position_orientation_pair(value: Any) -> bool: + """True for a 2-element (position, orientation) pair, false for a 2D position.""" + return ( + isinstance(value, tuple | list) + and len(value) == 2 + and not isinstance(value[0], int | float) + and not isinstance(value[1], int | float) + ) + + +class Pose(LCMPose): # type: ignore[misc] + position: Vector3 + orientation: Quaternion + msg_name = "geometry_msgs.Pose" + + @overload + def __init__(self) -> None: ... + + @overload + def __init__(self, x: int | float, y: int | float, z: int | float) -> None: ... + + @overload + def __init__( + self, + x: int | float, + y: int | float, + z: int | float, + qx: int | float, + qy: int | float, + qz: int | float, + qw: int | float, + ) -> None: ... + + @overload + def __init__( + self, + position: VectorConvertable | Vector3 | None = ..., + orientation: QuaternionConvertable | Quaternion | None = ..., + ) -> None: ... + + @overload + def __init__(self, value: PoseConvertable | Pose, /) -> None: ... + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize a pose. + + Supported forms: + Pose() # origin, identity orientation + Pose(x, y, z) + Pose(x, y, z, qx, qy, qz, qw) + Pose(position) # any Vector3-convertable + Pose(position, orientation) + Pose(position=..., orientation=...) # keyword args + Pose((position, orientation)) # pair + Pose({"position": ..., "orientation": ...}) + Pose(other_pose) # copy constructor + Pose(lcm_pose) # from LCM message + """ + position: Any = None + orientation: Any = None + + if len(args) == 3: + position = args + elif len(args) == 7: + position, orientation = args[:3], args[3:] + elif len(args) == 2: + position, orientation = args + elif len(args) == 1: + value = args[0] + # Pose before LCMPose (it is a subclass); dict and pair before the + # generic "it is a position" fallback. + if isinstance(value, Pose): + position, orientation = value.position, value.orientation + elif isinstance(value, LCMPose): + position = (value.position.x, value.position.y, value.position.z) + orientation = ( + value.orientation.x, + value.orientation.y, + value.orientation.z, + value.orientation.w, + ) + elif isinstance(value, dict): + position, orientation = value["position"], value["orientation"] + elif _is_position_orientation_pair(value): + position, orientation = value + else: + position = value + elif args: + raise TypeError(f"Pose takes 1, 2, 3 or 7 positional arguments ({len(args)} given)") + + if kwargs: + position = kwargs.pop("position", position) + orientation = kwargs.pop("orientation", orientation) + if kwargs: + raise TypeError(f"Pose got unexpected keyword arguments {sorted(kwargs)}") + + self.position = Vector3(0.0, 0.0, 0.0) if position is None else Vector3(position) + self.orientation = ( + Quaternion(0.0, 0.0, 0.0, 1.0) if orientation is None else Quaternion(orientation) + ) + + @property + def x(self) -> float: + """X coordinate of position.""" + return self.position.x + + @property + def y(self) -> float: + """Y coordinate of position.""" + return self.position.y + + @property + def z(self) -> float: + """Z coordinate of position.""" + return self.position.z + + @property + def roll(self) -> float: + """Roll angle in radians.""" + return self.orientation.to_euler().roll + + @property + def pitch(self) -> float: + """Pitch angle in radians.""" + return self.orientation.to_euler().pitch + + @property + def yaw(self) -> float: + """Yaw angle in radians.""" + return self.orientation.to_euler().yaw + + def __repr__(self) -> str: + return f"Pose(position={self.position!r}, orientation={self.orientation!r})" + + def __str__(self) -> str: + return ( + f"Pose(pos=[{self.x:.3f}, {self.y:.3f}, {self.z:.3f}], " + f"euler=[{self.roll:.3f}, {self.pitch:.3f}, {self.yaw:.3f}]), " + f"quaternion=[{self.orientation}])" + ) + + def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] + """Check if two poses are equal.""" + if not isinstance(other, Pose): + return False + return self.position == other.position and self.orientation == other.orientation + + def __matmul__(self, transform: LCMTransform | Transform) -> Pose: + return self + transform + + def __add__(self, other: Pose | PoseConvertable | LCMTransform | Transform) -> Pose: + """Compose two poses or apply a transform (transform composition). + + The operation self + other represents applying transformation 'other' + in the coordinate frame defined by 'self'. This is equivalent to: + - First apply transformation 'self' (from world to self's frame) + - Then apply transformation 'other' (from self's frame to other's frame) + + This matches ROS tf convention where: + T_world_to_other = T_world_to_self * T_self_to_other + + Args: + other: The pose or transform to compose with this one + + Returns: + A new Pose representing the composed transformation + + Example: + robot_pose = Pose(1, 0, 0) # Robot at (1,0,0) facing forward + object_in_robot = Pose(2, 0, 0) # Object 2m in front of robot + object_in_world = robot_pose + object_in_robot # Object at (3,0,0) in world + + # Or with a Transform: + transform = Transform() + transform.translation = Vector3(2, 0, 0) + transform.rotation = Quaternion(0, 0, 0, 1) + new_pose = pose + transform + """ + # Handle Transform objects + if isinstance(other, LCMTransform | Transform): + # Convert Transform to Pose using its translation and rotation + other_position = Vector3(other.translation) + other_orientation = Quaternion(other.rotation) + elif isinstance(other, Pose): + other_position = other.position + other_orientation = other.orientation + else: + # Convert to Pose if it's a convertible type + other_pose = Pose(other) + other_position = other_pose.position + other_orientation = other_pose.orientation + + # Compose orientations: self.orientation * other.orientation + new_orientation = self.orientation * other_orientation + + # Transform other's position by self's orientation, then add to self's position + rotated_position = self.orientation.rotate_vector(other_position) + new_position = self.position + rotated_position + + return Pose(new_position, new_orientation) + + def __sub__(self, other: Pose) -> Pose: + """Compute the delta pose: self - other. + + For position: simple subtraction. + For orientation: delta_quat = self.orientation * inverse(other.orientation) + + Returns: + A new Pose representing the delta transformation + """ + delta_position = self.position - other.position + delta_orientation = self.orientation * other.orientation.inverse() + return Pose(delta_position, delta_orientation) + + +@dispatch +def to_pose(value: Pose) -> Pose: + """Pass through Pose objects.""" + return value + + +@dispatch # type: ignore[no-redef] +def to_pose(value: PoseConvertable) -> Pose: + """Convert a pose-compatible value to a Pose object.""" + return Pose(value) + + +PoseLike: TypeAlias = PoseConvertable | Pose diff --git a/dimos/msgs/geometry_msgs/PoseWithCovariance.py b/dimos/msgs/geometry_msgs/PoseWithCovariance.py new file mode 100644 index 00000000000..f26a987bee1 --- /dev/null +++ b/dimos/msgs/geometry_msgs/PoseWithCovariance.py @@ -0,0 +1,201 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, TypeAlias + +from dimos_lcm.geometry_msgs import ( + PoseWithCovariance as LCMPoseWithCovariance, +) +import numpy as np + +from dimos.msgs.geometry_msgs.Pose import Pose, PoseConvertable + +if TYPE_CHECKING: + from dimos.msgs.geometry_msgs.Quaternion import Quaternion + from dimos.msgs.geometry_msgs.Vector3 import Vector3 + +# Types that can be converted to/from PoseWithCovariance +PoseWithCovarianceConvertable: TypeAlias = ( + tuple[PoseConvertable, list[float] | np.ndarray] + | LCMPoseWithCovariance + | dict[str, PoseConvertable | list[float] | np.ndarray] +) + +COVARIANCE_SIZE = 36 + + +def _is_value_covariance_pair(value: Any) -> bool: + """True for a 2-element (value, covariance) pair, where covariance is 36 long.""" + if not isinstance(value, tuple | list) or len(value) != 2: + return False + covariance = value[1] + return isinstance(covariance, list | np.ndarray) and np.size(covariance) == COVARIANCE_SIZE + + +class PoseWithCovariance(LCMPoseWithCovariance): # type: ignore[misc] + pose: Pose + covariance: np.ndarray[tuple[int], np.dtype[np.floating[Any]]] + msg_name = "geometry_msgs.PoseWithCovariance" + + def __init__( + self, + pose: Pose | PoseConvertable | PoseWithCovarianceConvertable | None = None, + covariance: list[float] | np.ndarray | None = None, + ) -> None: + """Initialize a pose with covariance. + + Supported forms: + PoseWithCovariance() # origin, zero covariance + PoseWithCovariance(pose) + PoseWithCovariance(pose, covariance) + PoseWithCovariance(pose=..., covariance=...) + PoseWithCovariance((pose, covariance)) # pair + PoseWithCovariance({"pose": ..., "covariance": ...}) + PoseWithCovariance(other) # copy constructor + PoseWithCovariance(lcm_pose_with_cov) # from LCM message + """ + source: Any = pose + cov: Any = covariance + + # PoseWithCovariance before LCMPoseWithCovariance (it is a subclass). + if isinstance(source, PoseWithCovariance): + if cov is None: + cov = np.array(source.covariance).copy() + source = Pose(source.pose) # copy constructor: don't alias the source pose + elif isinstance(source, LCMPoseWithCovariance): + if cov is None: + cov = np.array(source.covariance) + source = source.pose + elif isinstance(source, dict) and "pose" in source: + cov = source.get("covariance", cov) + source = source["pose"] + elif _is_value_covariance_pair(source): + source, cov = source + + self.pose = source if isinstance(source, Pose) else Pose(source) + self.covariance = ( + np.zeros(COVARIANCE_SIZE) + if cov is None + else np.array(cov, dtype=float).reshape(COVARIANCE_SIZE) + ) + + def __getattribute__(self, name: str): # type: ignore[no-untyped-def] + """Override to ensure covariance is always returned as numpy array.""" + if name == "covariance": + cov = object.__getattribute__(self, "covariance") + if not isinstance(cov, np.ndarray): + return np.array(cov, dtype=float) + return cov + return super().__getattribute__(name) + + def __setattr__(self, name: str, value) -> None: # type: ignore[no-untyped-def] + """Override to ensure covariance is stored as numpy array.""" + if name == "covariance": + if not isinstance(value, np.ndarray): + value = np.array(value, dtype=float).reshape(36) + super().__setattr__(name, value) + + @property + def x(self) -> float: + """X coordinate of position.""" + return self.pose.x + + @property + def y(self) -> float: + """Y coordinate of position.""" + return self.pose.y + + @property + def z(self) -> float: + """Z coordinate of position.""" + return self.pose.z + + @property + def position(self) -> Vector3: + """Position vector.""" + return self.pose.position + + @property + def orientation(self) -> Quaternion: + """Orientation quaternion.""" + return self.pose.orientation + + @property + def roll(self) -> float: + """Roll angle in radians.""" + return self.pose.roll + + @property + def pitch(self) -> float: + """Pitch angle in radians.""" + return self.pose.pitch + + @property + def yaw(self) -> float: + """Yaw angle in radians.""" + return self.pose.yaw + + @property + def covariance_matrix(self) -> np.ndarray: + """Get covariance as 6x6 matrix.""" + return self.covariance.reshape(6, 6) + + @covariance_matrix.setter + def covariance_matrix(self, value: np.ndarray) -> None: + """Set covariance from 6x6 matrix.""" + self.covariance = np.array(value).reshape(36) + + def __repr__(self) -> str: + return f"PoseWithCovariance(pose={self.pose!r}, covariance=<{self.covariance.shape[0] if isinstance(self.covariance, np.ndarray) else len(self.covariance)} elements>)" + + def __str__(self) -> str: + return ( + f"PoseWithCovariance(pos=[{self.x:.3f}, {self.y:.3f}, {self.z:.3f}], " + f"euler=[{self.roll:.3f}, {self.pitch:.3f}, {self.yaw:.3f}], " + f"cov_trace={np.trace(self.covariance_matrix):.3f})" + ) + + def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] + """Check if two PoseWithCovariance are equal.""" + if not isinstance(other, PoseWithCovariance): + return False + return self.pose == other.pose and np.allclose(self.covariance, other.covariance) + + def lcm_encode(self) -> bytes: + """Encode to LCM binary format.""" + lcm_msg = LCMPoseWithCovariance() + lcm_msg.pose = self.pose + # LCM expects list, not numpy array + if isinstance(self.covariance, np.ndarray): + lcm_msg.covariance = self.covariance.tolist() + else: + lcm_msg.covariance = list(self.covariance) + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes) -> PoseWithCovariance: + """Decode from LCM binary format.""" + lcm_msg = LCMPoseWithCovariance.lcm_decode(data) + pose = Pose( + position=[lcm_msg.pose.position.x, lcm_msg.pose.position.y, lcm_msg.pose.position.z], + orientation=[ + lcm_msg.pose.orientation.x, + lcm_msg.pose.orientation.y, + lcm_msg.pose.orientation.z, + lcm_msg.pose.orientation.w, + ], + ) + return cls(pose, lcm_msg.covariance) diff --git a/dimos/msgs/geometry_msgs/PoseWithCovarianceStamped.py b/dimos/msgs/geometry_msgs/PoseWithCovarianceStamped.py new file mode 100644 index 00000000000..17f3f2b6d41 --- /dev/null +++ b/dimos/msgs/geometry_msgs/PoseWithCovarianceStamped.py @@ -0,0 +1,98 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import time +from typing import TypeAlias + +from dimos_lcm.geometry_msgs import ( + PoseWithCovarianceStamped as LCMPoseWithCovarianceStamped, +) +import numpy as np + +from dimos.msgs.geometry_msgs.Pose import Pose, PoseConvertable +from dimos.msgs.geometry_msgs.PoseWithCovariance import PoseWithCovariance +from dimos.types.timestamped import Timestamped + +# Types that can be converted to/from PoseWithCovarianceStamped +PoseWithCovarianceStampedConvertable: TypeAlias = ( + tuple[PoseConvertable, list[float] | np.ndarray] + | LCMPoseWithCovarianceStamped + | dict[str, PoseConvertable | list[float] | np.ndarray | float | str] +) + + +def sec_nsec(ts): # type: ignore[no-untyped-def] + s = int(ts) + return [s, int((ts - s) * 1_000_000_000)] + + +class PoseWithCovarianceStamped(PoseWithCovariance, Timestamped): + msg_name = "geometry_msgs.PoseWithCovarianceStamped" + ts: float + frame_id: str + + def __init__( + self, + ts: float | None = None, + frame_id: str = "", + pose: Pose | PoseConvertable | None = None, + covariance: list[float] | np.ndarray | None = None, + ) -> None: + """Initialize with timestamp, frame_id, pose and covariance.""" + self.frame_id = frame_id + self.ts = time.time() if ts is None else ts + super().__init__(pose, covariance) + + def lcm_encode(self) -> bytes: + lcm_msg = LCMPoseWithCovarianceStamped() + lcm_msg.pose.pose = self.pose + # LCM expects list, not numpy array + if isinstance(self.covariance, np.ndarray): + lcm_msg.pose.covariance = self.covariance.tolist() + else: + lcm_msg.pose.covariance = list(self.covariance) + [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] + lcm_msg.header.frame_id = self.frame_id + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes) -> PoseWithCovarianceStamped: + lcm_msg = LCMPoseWithCovarianceStamped.lcm_decode(data) + return cls( + ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), + frame_id=lcm_msg.header.frame_id, + pose=Pose( + position=[ + lcm_msg.pose.pose.position.x, + lcm_msg.pose.pose.position.y, + lcm_msg.pose.pose.position.z, + ], + orientation=[ + lcm_msg.pose.pose.orientation.x, + lcm_msg.pose.pose.orientation.y, + lcm_msg.pose.pose.orientation.z, + lcm_msg.pose.pose.orientation.w, + ], + ), + covariance=lcm_msg.pose.covariance, + ) + + def __str__(self) -> str: + return ( + f"PoseWithCovarianceStamped(pos=[{self.x:.3f}, {self.y:.3f}, {self.z:.3f}], " + f"euler=[{self.roll:.3f}, {self.pitch:.3f}, {self.yaw:.3f}], " + f"cov_trace={np.trace(self.covariance_matrix):.3f})" + ) diff --git a/dimos/msgs/geometry_msgs/Quaternion.py b/dimos/msgs/geometry_msgs/Quaternion.py new file mode 100644 index 00000000000..e782bc71142 --- /dev/null +++ b/dimos/msgs/geometry_msgs/Quaternion.py @@ -0,0 +1,325 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from collections.abc import Sequence +from io import BytesIO +import math +import struct +from typing import TYPE_CHECKING, Any, BinaryIO, TypeAlias, overload + +if TYPE_CHECKING: + import rerun as rr + +from dimos_lcm.geometry_msgs import Quaternion as LCMQuaternion +import numpy as np + +from dimos.msgs.geometry_msgs.Vector3 import Vector3 + +# Types that can be converted to/from Quaternion +QuaternionConvertable: TypeAlias = Sequence[int | float] | LCMQuaternion | np.ndarray + + +def _four_components(value: Any) -> tuple[float, float, float, float]: + """Unpack a length-4 sequence or array into (x, y, z, w).""" + if not isinstance(value, np.ndarray | Sequence): + raise TypeError(f"Cannot initialize Quaternion from {type(value)}") + size = value.size if isinstance(value, np.ndarray) else len(value) + if size != 4: + raise ValueError("Quaternion requires exactly 4 components [x, y, z, w]") + return (float(value[0]), float(value[1]), float(value[2]), float(value[3])) + + +class Quaternion(LCMQuaternion): # type: ignore[misc] + x: float = 0.0 + y: float = 0.0 + z: float = 0.0 + w: float = 1.0 + msg_name = "geometry_msgs.Quaternion" + + @classmethod + def lcm_decode(cls, data: bytes | BinaryIO): # type: ignore[no-untyped-def] + if not hasattr(data, "read"): + data = BytesIO(data) + if data.read(8) != cls._get_packed_fingerprint(): + raise ValueError("Decode error") + return cls._lcm_decode_one(data) # type: ignore[no-untyped-call] + + @classmethod + def _lcm_decode_one(cls, buf): # type: ignore[no-untyped-def] + return cls(struct.unpack(">dddd", buf.read(32))) + + @overload + def __init__(self) -> None: ... + + @overload + def __init__( + self, + x: int | float = ..., + y: int | float = ..., + z: int | float = ..., + w: int | float = ..., + ) -> None: ... + + @overload + def __init__(self, value: QuaternionConvertable | Quaternion, /) -> None: ... + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize a quaternion. + + Supported forms: + Quaternion() # identity (0, 0, 0, 1) + Quaternion(x, y, z, w) + Quaternion(x=1, y=2, z=3, w=4) # keyword args + Quaternion([x, y, z, w]) # sequence + Quaternion(np.array([x, y, z, w])) # numpy array + Quaternion(other_quaternion) # copy constructor + Quaternion(lcm_quaternion) # from LCM message + """ + if len(args) == 4: + self.x = float(args[0]) + self.y = float(args[1]) + self.z = float(args[2]) + self.w = float(args[3]) + elif len(args) == 1: + value = args[0] + # Quaternion before LCMQuaternion (it is a subclass) and before the + # generic sequence branch (a Quaternion is indexable). + if isinstance(value, Quaternion): + self.x, self.y, self.z, self.w = value.x, value.y, value.z, value.w + elif isinstance(value, LCMQuaternion): + self.x, self.y, self.z, self.w = value.x, value.y, value.z, value.w + else: + self.x, self.y, self.z, self.w = _four_components(value) + elif args: + raise TypeError( + f"Quaternion takes 1 sequence or 4 components ({len(args)} positional given)" + ) + elif kwargs: + self.x = float(kwargs.pop("x", 0.0)) + self.y = float(kwargs.pop("y", 0.0)) + self.z = float(kwargs.pop("z", 0.0)) + self.w = float(kwargs.pop("w", 1.0)) + # else: no arguments — the class defaults already spell the identity. + + if kwargs: + raise TypeError(f"Quaternion got unexpected keyword arguments {sorted(kwargs)}") + + def to_tuple(self) -> tuple[float, float, float, float]: + """Tuple representation of the quaternion (x, y, z, w).""" + return (self.x, self.y, self.z, self.w) + + def to_list(self) -> list[float]: + """List representation of the quaternion (x, y, z, w).""" + return [self.x, self.y, self.z, self.w] + + def to_numpy(self) -> np.ndarray: + """Numpy array representation of the quaternion (x, y, z, w).""" + return np.array([self.x, self.y, self.z, self.w]) + + @property + def euler(self) -> Vector3: + return self.to_euler() + + @property + def radians(self) -> Vector3: + return self.to_euler() + + def to_radians(self) -> Vector3: + """Radians representation of the quaternion (x, y, z, w).""" + return self.to_euler() + + def to_rerun(self) -> rr.Quaternion: + import rerun as rr + + return rr.Quaternion(xyzw=[self.x, self.y, self.z, self.w]) + + @classmethod + def from_euler(cls, vector: Vector3) -> Quaternion: + """Convert Euler angles (roll, pitch, yaw) in radians to quaternion. + + Args: + vector: Vector3 containing (roll, pitch, yaw) in radians + + Returns: + Quaternion representation + """ + + # Calculate quaternion components + cy = np.cos(vector.yaw * 0.5) + sy = np.sin(vector.yaw * 0.5) + cp = np.cos(vector.pitch * 0.5) + sp = np.sin(vector.pitch * 0.5) + cr = np.cos(vector.roll * 0.5) + sr = np.sin(vector.roll * 0.5) + + w = cr * cp * cy + sr * sp * sy + x = sr * cp * cy - cr * sp * sy + y = cr * sp * cy + sr * cp * sy + z = cr * cp * sy - sr * sp * cy + + return cls(x, y, z, w) + + @classmethod + def from_rotation_matrix(cls, matrix: np.ndarray) -> Quaternion: + """Convert a 3x3 rotation matrix to quaternion. + + Args: + matrix: 3x3 rotation matrix (numpy array) + + Returns: + Quaternion representation + """ + from scipy.spatial.transform import ( + Rotation, # ~330ms: deferred to avoid startup cost + ) + + rotation = Rotation.from_matrix(matrix) + quat = rotation.as_quat() # Returns [x, y, z, w] + return cls(quat[0], quat[1], quat[2], quat[3]) + + def to_rotation_matrix(self) -> np.ndarray: + """Convert quaternion to a 3x3 rotation matrix.""" + from scipy.spatial.transform import ( + Rotation, # ~330ms: deferred to avoid startup cost + ) + + return np.asarray(Rotation.from_quat([self.x, self.y, self.z, self.w]).as_matrix()) + + def to_euler(self) -> Vector3: + """Convert quaternion to Euler angles (roll, pitch, yaw) in radians. + + Returns: + Vector3: Euler angles as (roll, pitch, yaw) in radians + """ + # Use scipy for accurate quaternion to euler conversion + from scipy.spatial.transform import ( + Rotation, # ~330ms: deferred to avoid startup cost + ) + + quat = [self.x, self.y, self.z, self.w] + rotation = Rotation.from_quat(quat) + euler_angles = rotation.as_euler("xyz") # roll, pitch, yaw + + return Vector3(euler_angles[0], euler_angles[1], euler_angles[2]) + + def __getitem__(self, idx: int) -> float: + """Allow indexing into quaternion components: 0=x, 1=y, 2=z, 3=w.""" + if idx == 0: + return self.x + elif idx == 1: + return self.y + elif idx == 2: + return self.z + elif idx == 3: + return self.w + else: + raise IndexError(f"Quaternion index {idx} out of range [0-3]") + + def __repr__(self) -> str: + return f"Quaternion({self.x:.6f}, {self.y:.6f}, {self.z:.6f}, {self.w:.6f})" + + def __str__(self) -> str: + return self.__repr__() + + def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] + if not isinstance(other, Quaternion): + return False + return self.x == other.x and self.y == other.y and self.z == other.z and self.w == other.w + + def is_zero(self) -> bool: + """All components are zero — i.e. an uninitialized placeholder, not a valid rotation.""" + return self.x == 0.0 and self.y == 0.0 and self.z == 0.0 and self.w == 0.0 + + def __mul__(self, other: Quaternion) -> Quaternion: + """Multiply two quaternions (Hamilton product). + + The result represents the composition of rotations: + q1 * q2 represents rotating by q2 first, then by q1. + """ + if not isinstance(other, Quaternion): + raise TypeError(f"Cannot multiply Quaternion with {type(other)}") + + # Hamilton product formula + w = self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z + x = self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y + y = self.w * other.y - self.x * other.z + self.y * other.w + self.z * other.x + z = self.w * other.z + self.x * other.y - self.y * other.x + self.z * other.w + + return Quaternion(x, y, z, w) + + def dot(self, other: Quaternion) -> float: + return float(self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w) + + def angle_to(self, other: Quaternion) -> float: + """Smallest rotation angle (radians) between two unit quaternions. + + ``abs(self.dot(other))`` collapses the double-cover sign ambiguity; + the ``min(1.0, ...)`` clamps against numerical drift past 1. + """ + return 2.0 * math.acos(min(1.0, abs(self.dot(other)))) + + def conjugate(self) -> Quaternion: + """Return the conjugate of the quaternion. + + For unit quaternions, the conjugate represents the inverse rotation. + """ + return Quaternion(-self.x, -self.y, -self.z, self.w) + + def inverse(self) -> Quaternion: + """Return the inverse of the quaternion. + + For unit quaternions, this is equivalent to the conjugate. + For non-unit quaternions, this is conjugate / norm^2. + """ + norm_sq = self.x**2 + self.y**2 + self.z**2 + self.w**2 + if norm_sq == 0: + raise ZeroDivisionError("Cannot invert zero quaternion") + + # For unit quaternions (norm_sq ≈ 1), this simplifies to conjugate + if np.isclose(norm_sq, 1.0): + return self.conjugate() + + # For non-unit quaternions + conj = self.conjugate() + return Quaternion(conj.x / norm_sq, conj.y / norm_sq, conj.z / norm_sq, conj.w / norm_sq) + + def normalize(self) -> Quaternion: + """Return a normalized (unit) quaternion.""" + norm = np.sqrt(self.x**2 + self.y**2 + self.z**2 + self.w**2) + if norm == 0: + raise ZeroDivisionError("Cannot normalize zero quaternion") + return Quaternion(self.x / norm, self.y / norm, self.z / norm, self.w / norm) + + def rotate_vector(self, vector: Vector3) -> Vector3: + """Rotate a 3D vector by this quaternion. + + Args: + vector: The vector to rotate + + Returns: + The rotated vector + """ + # For unit quaternions, conjugate equals inverse, so we use conjugate for efficiency + # The rotation formula is: q * v * q^* where q^* is the conjugate + + # Convert vector to pure quaternion (w=0) + v_quat = Quaternion(vector.x, vector.y, vector.z, 0) + + # Apply rotation: q * v * q^* (conjugate for unit quaternions) + rotated = self * v_quat * self.conjugate() + + # Extract vector components + return Vector3(rotated.x, rotated.y, rotated.z) diff --git a/dimos/msgs/geometry_msgs/Transform.py b/dimos/msgs/geometry_msgs/Transform.py new file mode 100644 index 00000000000..6499905da1a --- /dev/null +++ b/dimos/msgs/geometry_msgs/Transform.py @@ -0,0 +1,329 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import time +from typing import TYPE_CHECKING, Any, BinaryIO + +if TYPE_CHECKING: + import numpy as np + import rerun as rr + + from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped + +from dimos_lcm.geometry_msgs import ( + Transform as LCMTransform, + TransformStamped as LCMTransformStamped, +) + +from dimos.msgs.geometry_msgs.Quaternion import Quaternion +from dimos.msgs.geometry_msgs.Vector3 import Vector3 +from dimos.msgs.std_msgs.Header import Header +from dimos.types.timestamped import Timestamped + + +class Transform(Timestamped): + translation: Vector3 + rotation: Quaternion + ts: float + frame_id: str + child_frame_id: str + msg_name = "tf2_msgs.TFMessage" + + def __init__( # type: ignore[no-untyped-def] + self, + translation: Vector3 | None = None, + rotation: Quaternion | None = None, + frame_id: str = "world", + child_frame_id: str = "unset", + ts: float | None = None, + **kwargs, + ) -> None: + self.frame_id = frame_id + self.child_frame_id = child_frame_id + self.ts = time.time() if ts is None else ts + self.translation = translation if translation is not None else Vector3() + self.rotation = rotation if rotation is not None else Quaternion() + + def now(self) -> Transform: + """Return a copy of this Transform with the current timestamp.""" + return Transform( + translation=self.translation, + rotation=self.rotation, + frame_id=self.frame_id, + child_frame_id=self.child_frame_id, + ts=time.time(), + ) + + def __repr__(self) -> str: + return f"Transform(translation={self.translation!r}, rotation={self.rotation!r})" + + def __str__(self) -> str: + return f"{self.frame_id} -> {self.child_frame_id}\n Translation: {self.translation}\n Rotation: {self.rotation}" + + def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] + """Check if two transforms are equal.""" + if not isinstance(other, Transform): + return False + return self.translation == other.translation and self.rotation == other.rotation + + @classmethod + def identity(cls) -> Transform: + """Create an identity transform.""" + return cls() + + def lcm_transform(self) -> LCMTransformStamped: + return LCMTransformStamped( + child_frame_id=self.child_frame_id, + header=Header(self.ts, self.frame_id), + transform=LCMTransform( + translation=self.translation, + rotation=self.rotation, + ), + ) + + def apply(self, other: Transform) -> Transform: + return self.__add__(other) + + def __add__(self, other: Transform) -> Transform: + """Compose two transforms (transform composition). + + The operation self + other represents applying transformation 'other' + in the coordinate frame defined by 'self'. This is equivalent to: + - First apply transformation 'self' (from frame A to frame B) + - Then apply transformation 'other' (from frame B to frame C) + + Args: + other: The transform to compose with this one + + Returns: + A new Transform representing the composed transformation + + Example: + t1 = Transform(Vector3(1, 0, 0), Quaternion(0, 0, 0, 1)) + t2 = Transform(Vector3(2, 0, 0), Quaternion(0, 0, 0, 1)) + t3 = t1 + t2 # Combined transform: translation (3, 0, 0) + """ + if not isinstance(other, Transform): + raise TypeError(f"Cannot add Transform and {type(other).__name__}") + + # Compose orientations: self.rotation * other.rotation + new_rotation = self.rotation * other.rotation + + # Transform other's translation by self's rotation, then add to self's translation + rotated_translation = self.rotation.rotate_vector(other.translation) + new_translation = self.translation + rotated_translation + + return Transform( + translation=new_translation, + rotation=new_rotation, + frame_id=self.frame_id, + child_frame_id=other.child_frame_id, + ts=self.ts, + ) + + def inverse(self) -> Transform: + """Compute the inverse transform. + + The inverse transform reverses the direction of the transformation. + If this transform goes from frame A to frame B, the inverse goes from B to A. + + Returns: + A new Transform representing the inverse transformation + """ + # Inverse rotation + inv_rotation = self.rotation.inverse() + + # Inverse translation: -R^(-1) * t + inv_translation = inv_rotation.rotate_vector(self.translation) + inv_translation = Vector3(-inv_translation.x, -inv_translation.y, -inv_translation.z) + + return Transform( + translation=inv_translation, + rotation=inv_rotation, + frame_id=self.child_frame_id, # Swap frame references + child_frame_id=self.frame_id, + ts=self.ts, + ) + + def __neg__(self) -> Transform: + """Unary minus operator returns the inverse transform.""" + return self.inverse() + + @classmethod + def from_pose(cls, frame_id: str, pose: Pose | PoseStamped) -> Transform: # type: ignore[name-defined] + """Create a Transform from a Pose or PoseStamped. + + Args: + pose: A Pose or PoseStamped object to convert + + Returns: + A Transform with the same translation and rotation as the pose + """ + # Import locally to avoid circular imports + from dimos.msgs.geometry_msgs.Pose import Pose + from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped + + # Handle both Pose and PoseStamped + if isinstance(pose, PoseStamped): + return cls( + translation=pose.position, + rotation=pose.orientation, + frame_id=pose.frame_id, + child_frame_id=frame_id, + ts=pose.ts, + ) + elif isinstance(pose, Pose): + return cls( + translation=pose.position, + rotation=pose.orientation, + child_frame_id=frame_id, + ) + else: + raise TypeError(f"Expected Pose or PoseStamped, got {type(pose).__name__}") + + def to_pose(self, **kwargs: Any) -> PoseStamped: + """Create a Transform from a Pose or PoseStamped. + + Args: + pose: A Pose or PoseStamped object to convert + + Returns: + A Transform with the same translation and rotation as the pose + """ + # Import locally to avoid circular imports + from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped as _PoseStamped + + # Handle both Pose and PoseStamped + fields: dict[str, Any] = { + "position": self.translation, + "orientation": self.rotation, + "frame_id": self.frame_id, + } + result: PoseStamped = _PoseStamped(**fields, **kwargs) + return result + + @classmethod + def from_matrix( + cls, + matrix: np.ndarray, + *, + ts: float | None = None, + frame_id: str = "world", + child_frame_id: str = "unset", + ) -> Transform: + """Build a Transform from a 4x4 homogeneous transformation matrix.""" + return cls( + translation=Vector3(matrix[:3, 3]), + rotation=Quaternion.from_rotation_matrix(matrix[:3, :3]), + frame_id=frame_id, + child_frame_id=child_frame_id, + ts=ts, + ) + + def to_matrix(self) -> np.ndarray: # type: ignore[name-defined] + """Convert Transform to a 4x4 transformation matrix. + + Returns a homogeneous transformation matrix that represents both + the rotation and translation of this transform. + + Returns: + np.ndarray: A 4x4 homogeneous transformation matrix + """ + import numpy as np + + # Extract quaternion components + x, y, z, w = self.rotation.x, self.rotation.y, self.rotation.z, self.rotation.w + + # Build rotation matrix from quaternion using standard formula + # This avoids numerical issues compared to converting to axis-angle first + rotation_matrix = np.array( + [ + [1 - 2 * (y * y + z * z), 2 * (x * y - z * w), 2 * (x * z + y * w)], + [2 * (x * y + z * w), 1 - 2 * (x * x + z * z), 2 * (y * z - x * w)], + [2 * (x * z - y * w), 2 * (y * z + x * w), 1 - 2 * (x * x + y * y)], + ] + ) + + # Build 4x4 homogeneous transformation matrix + matrix = np.eye(4) + matrix[:3, :3] = rotation_matrix + matrix[:3, 3] = [self.translation.x, self.translation.y, self.translation.z] + + return matrix + + def lcm_encode(self) -> bytes: + # we get a circular import otherwise + from dimos.msgs.tf2_msgs.TFMessage import TFMessage + + return TFMessage(self).lcm_encode() + + @classmethod + def lcm_decode(cls, data: bytes | BinaryIO) -> Transform: + """Decode from LCM TFMessage bytes.""" + from dimos_lcm.tf2_msgs import TFMessage as LCMTFMessage + + lcm_msg = LCMTFMessage.lcm_decode(data) + + if not lcm_msg.transforms: + raise ValueError("No transforms found in LCM message") + + # Get the first transform from the message + lcm_transform_stamped = lcm_msg.transforms[0] + + # Extract timestamp from header + ts = lcm_transform_stamped.header.stamp.sec + ( + lcm_transform_stamped.header.stamp.nsec / 1_000_000_000 + ) + + # Create and return Transform instance + return cls( + translation=Vector3( + lcm_transform_stamped.transform.translation.x, + lcm_transform_stamped.transform.translation.y, + lcm_transform_stamped.transform.translation.z, + ), + rotation=Quaternion( + lcm_transform_stamped.transform.rotation.x, + lcm_transform_stamped.transform.rotation.y, + lcm_transform_stamped.transform.rotation.z, + lcm_transform_stamped.transform.rotation.w, + ), + frame_id=lcm_transform_stamped.header.frame_id, + child_frame_id=lcm_transform_stamped.child_frame_id, + ts=ts, + ) + + def to_rerun(self, frameless: bool = False) -> rr.Transform3D: + """Convert to a rerun Transform3D. + + Args: + frameless: omit ``parent_frame``/``child_frame``. By default the + transform carries its frame IDs (resolved via rerun's tf-graph); + set this when positioning by entity-path hierarchy instead, where + the named frames would not compose. + """ + import rerun as rr + + translation = [self.translation.x, self.translation.y, self.translation.z] + rotation = self.rotation.to_rerun() + if frameless: + return rr.Transform3D(translation=translation, rotation=rotation) + return rr.Transform3D( + translation=translation, + rotation=rotation, + parent_frame="tf#/" + self.frame_id, + child_frame="tf#/" + self.child_frame_id, + ) diff --git a/dimos/msgs/geometry_msgs/Twist.py b/dimos/msgs/geometry_msgs/Twist.py new file mode 100644 index 00000000000..d08f61211f0 --- /dev/null +++ b/dimos/msgs/geometry_msgs/Twist.py @@ -0,0 +1,132 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from typing import Any, overload + +from dimos_lcm.geometry_msgs import Twist as LCMTwist + +from dimos.msgs.geometry_msgs.Quaternion import Quaternion +from dimos.msgs.geometry_msgs.Vector3 import Vector3, VectorLike + + +class Twist(LCMTwist): # type: ignore[misc] + linear: Vector3 + angular: Vector3 + msg_name = "geometry_msgs.Twist" + + @overload + def __init__(self) -> None: ... + + @overload + def __init__( + self, + linear: VectorLike | None = ..., + angular: VectorLike | Quaternion | None = ..., + ) -> None: ... + + @overload + def __init__(self, twist: Twist | LCMTwist, /) -> None: ... + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize a twist. + + Supported forms: + Twist() # zero twist + Twist(linear, angular) + Twist(linear=..., angular=...) # keyword args, either optional + Twist(linear, quaternion) # angular converted to euler + Twist(other_twist) # copy constructor + Twist(lcm_twist) # from LCM message + """ + linear: Any = None + angular: Any = None + + if len(args) == 2: + linear, angular = args + elif len(args) == 1: + value = args[0] + # Twist before LCMTwist (it is a subclass); anything else is a + # linear velocity, same as the `linear=` keyword. + if isinstance(value, Twist | LCMTwist): + linear, angular = value.linear, value.angular + else: + linear = value + elif args: + raise TypeError(f"Twist takes 1 or 2 positional arguments ({len(args)} given)") + + if kwargs: + linear = kwargs.pop("linear", linear) + angular = kwargs.pop("angular", angular) + if kwargs: + raise TypeError(f"Twist got unexpected keyword arguments {sorted(kwargs)}") + + self.linear = Vector3() if linear is None else Vector3(linear) + if angular is None: + self.angular = Vector3() + elif isinstance(angular, Quaternion): + self.angular = angular.to_euler() + else: + self.angular = Vector3(angular) + + def __repr__(self) -> str: + return f"Twist(linear={self.linear!r}, angular={self.angular!r})" + + def __str__(self) -> str: + return f"Twist:\n Linear: {self.linear}\n Angular: {self.angular}" + + def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] + """Check if two twists are equal.""" + if not isinstance(other, Twist): + return False + return self.linear == other.linear and self.angular == other.angular + + @classmethod + def zero(cls) -> Twist: + """Create a zero twist (no motion).""" + return cls() + + def is_zero(self) -> bool: + """Check if this is a zero twist (no linear or angular velocity).""" + return self.linear.is_zero() and self.angular.is_zero() + + def __sub__(self, other: Twist) -> Twist: + """Component-wise subtraction: self - other.""" + if not isinstance(other, Twist): + return NotImplemented + return Twist( + linear=self.linear - other.linear, + angular=self.angular - other.angular, + ) + + def __add__(self, other: Twist) -> Twist: + """Component-wise addition: self + other.""" + if not isinstance(other, Twist): + return NotImplemented + return Twist( + linear=self.linear + other.linear, + angular=self.angular + other.angular, + ) + + def __bool__(self) -> bool: + """Boolean conversion for Twist. + + A Twist is considered False if it's a zero twist (no motion), + and True otherwise. + + Returns: + False if twist is zero, True otherwise + """ + return not self.is_zero() diff --git a/dimos/msgs/geometry_msgs/TwistStamped.py b/dimos/msgs/geometry_msgs/TwistStamped.py new file mode 100644 index 00000000000..4377687e564 --- /dev/null +++ b/dimos/msgs/geometry_msgs/TwistStamped.py @@ -0,0 +1,85 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import time +from typing import Any, BinaryIO, TypeAlias + +from dimos_lcm.geometry_msgs import TwistStamped as LCMTwistStamped + +from dimos.msgs.geometry_msgs.Twist import Twist +from dimos.msgs.geometry_msgs.Vector3 import VectorConvertable +from dimos.types.timestamped import Timestamped + +# Types that can be converted to/from TwistStamped +TwistConvertable: TypeAlias = ( + tuple[VectorConvertable, VectorConvertable] | LCMTwistStamped | dict[str, VectorConvertable] +) + + +def sec_nsec(ts): # type: ignore[no-untyped-def] + s = int(ts) + return [s, int((ts - s) * 1_000_000_000)] + + +class TwistStamped(Twist, Timestamped): + msg_name = "geometry_msgs.TwistStamped" + ts: float + frame_id: str + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize a stamped twist. + + Takes ``(ts, frame_id)`` positionally, plus every Twist keyword. Any other + positional form belongs to Twist, so ``TwistStamped(linear, angular)`` + works as it does on the base class. + """ + ts: Any + # A leading number or string is a timestamp; anything else is a Twist argument. + if args and isinstance(args[0], int | float | str): + ts = args[0] + frame_id = args[1] if len(args) > 1 else kwargs.pop("frame_id", "") + twist_args: tuple[Any, ...] = () + else: + ts = kwargs.pop("ts", None) + frame_id = kwargs.pop("frame_id", "") + twist_args = args + + self.frame_id = frame_id + self.ts = time.time() if ts is None else ts + super().__init__(*twist_args, **kwargs) + + def lcm_encode(self) -> bytes: + lcm_msg = LCMTwistStamped() + lcm_msg.twist = self + [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] + lcm_msg.header.frame_id = self.frame_id + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes | BinaryIO) -> TwistStamped: + lcm_msg = LCMTwistStamped.lcm_decode(data) + return cls( + ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), + frame_id=lcm_msg.header.frame_id, + linear=[lcm_msg.twist.linear.x, lcm_msg.twist.linear.y, lcm_msg.twist.linear.z], + angular=[lcm_msg.twist.angular.x, lcm_msg.twist.angular.y, lcm_msg.twist.angular.z], + ) + + def __str__(self) -> str: + return ( + f"TwistStamped(linear=[{self.linear.x:.3f}, {self.linear.y:.3f}, {self.linear.z:.3f}], " + f"angular=[{self.angular.x:.3f}, {self.angular.y:.3f}, {self.angular.z:.3f}])" + ) diff --git a/dimos/msgs/geometry_msgs/TwistWithCovariance.py b/dimos/msgs/geometry_msgs/TwistWithCovariance.py new file mode 100644 index 00000000000..3786a013f54 --- /dev/null +++ b/dimos/msgs/geometry_msgs/TwistWithCovariance.py @@ -0,0 +1,181 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from typing import Any, TypeAlias + +from dimos_lcm.geometry_msgs import ( + TwistWithCovariance as LCMTwistWithCovariance, +) +import numpy as np + +from dimos.msgs.geometry_msgs.Twist import Twist +from dimos.msgs.geometry_msgs.Vector3 import Vector3, VectorConvertable + +# Types that can be converted to/from TwistWithCovariance +TwistWithCovarianceConvertable: TypeAlias = ( + tuple[Twist | tuple[VectorConvertable, VectorConvertable], list[float] | np.ndarray] + | LCMTwistWithCovariance + | dict[str, Twist | tuple[VectorConvertable, VectorConvertable] | list[float] | np.ndarray] +) + +COVARIANCE_SIZE = 36 + + +def _is_twist_covariance_pair(value: Any) -> bool: + """True for a 2-element (twist, covariance) pair, where covariance is 36 long.""" + if not isinstance(value, tuple | list) or len(value) != 2: + return False + covariance = value[1] + return isinstance(covariance, list | np.ndarray) and np.size(covariance) == COVARIANCE_SIZE + + +def _to_twist(value: Any) -> Twist: + """A Twist, or a (linear, angular) pair to build one from.""" + if isinstance(value, Twist): + return value + if value is None: + return Twist() + return Twist(value[0], value[1]) + + +class TwistWithCovariance(LCMTwistWithCovariance): # type: ignore[misc] + twist: Twist + covariance: np.ndarray[tuple[int], np.dtype[np.floating[Any]]] + msg_name = "geometry_msgs.TwistWithCovariance" + + def __init__( + self, + twist: Twist | TwistWithCovarianceConvertable | None = None, + covariance: list[float] | np.ndarray | None = None, + ) -> None: + """Initialize a twist with covariance. + + Supported forms: + TwistWithCovariance() # zero twist and covariance + TwistWithCovariance(twist) + TwistWithCovariance(twist, covariance) + TwistWithCovariance(twist=..., covariance=...) + TwistWithCovariance((linear, angular)) + TwistWithCovariance((twist, covariance)) # pair + TwistWithCovariance({"twist": ..., "covariance": ...}) + TwistWithCovariance(other) # copy constructor + TwistWithCovariance(lcm_twist_with_cov) # from LCM message + """ + source: Any = twist + cov: Any = covariance + + # TwistWithCovariance before LCMTwistWithCovariance (it is a subclass). + if isinstance(source, TwistWithCovariance): + if cov is None: + cov = np.array(source.covariance).copy() + source = Twist(source.twist) # copy constructor: don't alias the source twist + elif isinstance(source, LCMTwistWithCovariance): + if cov is None: + cov = np.array(source.covariance) + source = Twist(source.twist) + elif isinstance(source, dict) and "twist" in source: + cov = source.get("covariance", cov) + source = source["twist"] + elif _is_twist_covariance_pair(source): + source, cov = source + + self.twist = _to_twist(source) + self.covariance = ( + np.zeros(COVARIANCE_SIZE) + if cov is None + else np.array(cov, dtype=float).reshape(COVARIANCE_SIZE) + ) + + def __getattribute__(self, name: str): # type: ignore[no-untyped-def] + """Override to ensure covariance is always returned as numpy array.""" + if name == "covariance": + cov = object.__getattribute__(self, "covariance") + if not isinstance(cov, np.ndarray): + return np.array(cov, dtype=float) + return cov + return super().__getattribute__(name) + + def __setattr__(self, name: str, value) -> None: # type: ignore[no-untyped-def] + """Override to ensure covariance is stored as numpy array.""" + if name == "covariance": + if not isinstance(value, np.ndarray): + value = np.array(value, dtype=float).reshape(36) + super().__setattr__(name, value) + + @property + def linear(self) -> Vector3: + """Linear velocity vector.""" + return self.twist.linear + + @property + def angular(self) -> Vector3: + """Angular velocity vector.""" + return self.twist.angular + + @property + def covariance_matrix(self) -> np.ndarray: + """Get covariance as 6x6 matrix.""" + return self.covariance.reshape(6, 6) + + @covariance_matrix.setter + def covariance_matrix(self, value: np.ndarray) -> None: + """Set covariance from 6x6 matrix.""" + self.covariance = np.array(value).reshape(36) + + def __repr__(self) -> str: + return f"TwistWithCovariance(twist={self.twist!r}, covariance=<{self.covariance.shape[0] if isinstance(self.covariance, np.ndarray) else len(self.covariance)} elements>)" + + def __str__(self) -> str: + return ( + f"TwistWithCovariance(linear=[{self.linear.x:.3f}, {self.linear.y:.3f}, {self.linear.z:.3f}], " + f"angular=[{self.angular.x:.3f}, {self.angular.y:.3f}, {self.angular.z:.3f}], " + f"cov_trace={np.trace(self.covariance_matrix):.3f})" + ) + + def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] + """Check if two TwistWithCovariance are equal.""" + if not isinstance(other, TwistWithCovariance): + return False + return self.twist == other.twist and np.allclose(self.covariance, other.covariance) + + def is_zero(self) -> bool: + """Check if this is a zero twist (no linear or angular velocity).""" + return self.twist.is_zero() + + def __bool__(self) -> bool: + """Boolean conversion - False if zero twist, True otherwise.""" + return not self.is_zero() + + def lcm_encode(self) -> bytes: + """Encode to LCM binary format.""" + lcm_msg = LCMTwistWithCovariance() + lcm_msg.twist = self.twist + # LCM expects list, not numpy array + if isinstance(self.covariance, np.ndarray): + lcm_msg.covariance = self.covariance.tolist() + else: + lcm_msg.covariance = list(self.covariance) + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes) -> TwistWithCovariance: + """Decode from LCM binary format.""" + lcm_msg = LCMTwistWithCovariance.lcm_decode(data) + twist = Twist( + linear=[lcm_msg.twist.linear.x, lcm_msg.twist.linear.y, lcm_msg.twist.linear.z], + angular=[lcm_msg.twist.angular.x, lcm_msg.twist.angular.y, lcm_msg.twist.angular.z], + ) + return cls(twist, lcm_msg.covariance) diff --git a/dimos/msgs/geometry_msgs/TwistWithCovarianceStamped.py b/dimos/msgs/geometry_msgs/TwistWithCovarianceStamped.py new file mode 100644 index 00000000000..a828fdaa836 --- /dev/null +++ b/dimos/msgs/geometry_msgs/TwistWithCovarianceStamped.py @@ -0,0 +1,106 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import time +from typing import TypeAlias + +from dimos_lcm.geometry_msgs import ( + TwistWithCovarianceStamped as LCMTwistWithCovarianceStamped, +) +import numpy as np + +from dimos.msgs.geometry_msgs.Twist import Twist +from dimos.msgs.geometry_msgs.TwistWithCovariance import TwistWithCovariance +from dimos.msgs.geometry_msgs.Vector3 import VectorConvertable +from dimos.types.timestamped import Timestamped + +# Types that can be converted to/from TwistWithCovarianceStamped +TwistWithCovarianceStampedConvertable: TypeAlias = ( + tuple[Twist | tuple[VectorConvertable, VectorConvertable], list[float] | np.ndarray] + | LCMTwistWithCovarianceStamped + | dict[ + str, + Twist + | tuple[VectorConvertable, VectorConvertable] + | list[float] + | np.ndarray + | float + | str, + ] +) + + +def sec_nsec(ts): # type: ignore[no-untyped-def] + s = int(ts) + return [s, int((ts - s) * 1_000_000_000)] + + +class TwistWithCovarianceStamped(TwistWithCovariance, Timestamped): + msg_name = "geometry_msgs.TwistWithCovarianceStamped" + ts: float + frame_id: str + + def __init__( + self, + ts: float | None = None, + frame_id: str = "", + twist: Twist | tuple[VectorConvertable, VectorConvertable] | None = None, + covariance: list[float] | np.ndarray | None = None, + ) -> None: + """Initialize with timestamp, frame_id, twist and covariance.""" + self.frame_id = frame_id + self.ts = time.time() if ts is None else ts + super().__init__(twist, covariance) + + def lcm_encode(self) -> bytes: + lcm_msg = LCMTwistWithCovarianceStamped() + lcm_msg.twist.twist = self.twist + # LCM expects list, not numpy array + if isinstance(self.covariance, np.ndarray): + lcm_msg.twist.covariance = self.covariance.tolist() + else: + lcm_msg.twist.covariance = list(self.covariance) + [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] + lcm_msg.header.frame_id = self.frame_id + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes) -> TwistWithCovarianceStamped: + lcm_msg = LCMTwistWithCovarianceStamped.lcm_decode(data) + return cls( + ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), + frame_id=lcm_msg.header.frame_id, + twist=Twist( + linear=[ + lcm_msg.twist.twist.linear.x, + lcm_msg.twist.twist.linear.y, + lcm_msg.twist.twist.linear.z, + ], + angular=[ + lcm_msg.twist.twist.angular.x, + lcm_msg.twist.twist.angular.y, + lcm_msg.twist.twist.angular.z, + ], + ), + covariance=lcm_msg.twist.covariance, + ) + + def __str__(self) -> str: + return ( + f"TwistWithCovarianceStamped(linear=[{self.linear.x:.3f}, {self.linear.y:.3f}, {self.linear.z:.3f}], " + f"angular=[{self.angular.x:.3f}, {self.angular.y:.3f}, {self.angular.z:.3f}], " + f"cov_trace={np.trace(self.covariance_matrix):.3f})" + ) diff --git a/dimos/msgs/geometry_msgs/Vector3.py b/dimos/msgs/geometry_msgs/Vector3.py new file mode 100644 index 00000000000..99c98677182 --- /dev/null +++ b/dimos/msgs/geometry_msgs/Vector3.py @@ -0,0 +1,434 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from collections.abc import Sequence +from typing import Any, TypeAlias + +from dimos_lcm.geometry_msgs import Vector3 as LCMVector3 +import numpy as np + +# Types that can be converted to/from Vector +VectorConvertable: TypeAlias = Sequence[int | float] | LCMVector3 | np.ndarray + + +def _ensure_3d(data: np.ndarray) -> np.ndarray: + """Ensure the data array is exactly 3D by padding with zeros or raising an exception if too long.""" + if len(data) == 3: + return data + elif len(data) < 3: + padded = np.zeros(3, dtype=float) + padded[: len(data)] = data + return padded + else: + raise ValueError( + f"Vector3 cannot be initialized with more than 3 components. Got {len(data)} components." + ) + + +class Vector3(LCMVector3): # type: ignore[misc] + x: float = 0.0 + y: float = 0.0 + z: float = 0.0 + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize a 3D vector. + + Supported forms: + Vector3() # zero vector + Vector3(x) # (x, 0, 0) + Vector3(x, y) # (x, y, 0) + Vector3(x, y, z) # (x, y, z) + Vector3(x=1, y=2, z=3) # keyword args + Vector3([x, y, z]) # sequence + Vector3(np.array([x, y, z])) # numpy array + Vector3(other_vector3) # copy constructor + Vector3(lcm_vector3) # from LCM message + """ + if kwargs and not args: + # Keyword arguments: Vector3(x=1, y=2, z=3) + self.x = float(kwargs.get("x", 0.0)) + self.y = float(kwargs.get("y", 0.0)) + self.z = float(kwargs.get("z", 0.0)) + elif not args: + # No arguments: zero vector + self.x = 0.0 + self.y = 0.0 + self.z = 0.0 + elif len(args) == 1: + arg = args[0] + if isinstance(arg, Vector3): + # Copy constructor + self.x = arg.x + self.y = arg.y + self.z = arg.z + elif isinstance(arg, LCMVector3): + # From LCM Vector3 + self.x = float(arg.x) + self.y = float(arg.y) + self.z = float(arg.z) + elif isinstance(arg, np.ndarray): + # From numpy array + data = _ensure_3d(np.array(arg, dtype=float)) + self.x = float(data[0]) + self.y = float(data[1]) + self.z = float(data[2]) + elif isinstance(arg, (list, tuple)): + # From sequence + data = _ensure_3d(np.array(arg, dtype=float)) + self.x = float(data[0]) + self.y = float(data[1]) + self.z = float(data[2]) + elif isinstance(arg, (int, float)): + # Single numeric value: (x, 0, 0) + self.x = float(arg) + self.y = 0.0 + self.z = 0.0 + else: + raise TypeError(f"Cannot initialize Vector3 from {type(arg)}") + elif len(args) == 2: + # Two numeric values: (x, y, 0) + self.x = float(args[0]) + self.y = float(args[1]) + self.z = 0.0 + elif len(args) == 3: + # Three numeric values: (x, y, z) + self.x = float(args[0]) + self.y = float(args[1]) + self.z = float(args[2]) + else: + raise TypeError(f"Vector3 takes at most 3 positional arguments ({len(args)} given)") + + @property + def as_tuple(self) -> tuple[float, float, float]: + return (self.x, self.y, self.z) + + @property + def yaw(self) -> float: + return self.z + + @property + def pitch(self) -> float: + return self.y + + @property + def roll(self) -> float: + return self.x + + @property + def data(self) -> np.ndarray: + """Get the underlying numpy array.""" + return np.array([self.x, self.y, self.z], dtype=float) + + def __getitem__(self, idx: int) -> float: + if idx == 0: + return self.x + elif idx == 1: + return self.y + elif idx == 2: + return self.z + else: + raise IndexError(f"Vector3 index {idx} out of range [0-2]") + + def __repr__(self) -> str: + return f"Vector({self.data})" + + def __str__(self) -> str: + def getArrow() -> str: + repr = ["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"] + + if self.x == 0 and self.y == 0: + return "·" + + # Calculate angle in radians and convert to directional index + angle = np.arctan2(self.y, self.x) + # Map angle to 0-7 index (8 directions) with proper orientation + dir_index = int(((angle + np.pi) * 4 / np.pi) % 8) + # Get directional arrow symbol + return repr[dir_index] + + return f"{getArrow()} Vector {self.__repr__()}" + + def agent_encode(self) -> dict[str, float]: + """Encode the vector for agent communication.""" + return {"x": self.x, "y": self.y, "z": self.z} + + def serialize(self) -> dict[str, Any]: + """Serialize the vector to a tuple.""" + return {"type": "vector", "c": (self.x, self.y, self.z)} + + def __eq__(self, other: object) -> bool: + """Check if two vectors are equal using numpy's allclose for floating point comparison.""" + if not isinstance(other, Vector3): + return False + return bool(np.allclose([self.x, self.y, self.z], [other.x, other.y, other.z])) + + def __add__(self, other: VectorConvertable | Vector3) -> Vector3: + other_vector: Vector3 = to_vector(other) + return self.__class__( + self.x + other_vector.x, self.y + other_vector.y, self.z + other_vector.z + ) + + def __sub__(self, other: VectorConvertable | Vector3) -> Vector3: + other_vector = to_vector(other) + return self.__class__( + self.x - other_vector.x, self.y - other_vector.y, self.z - other_vector.z + ) + + def __mul__(self, scalar: float) -> Vector3: + return self.__class__(self.x * scalar, self.y * scalar, self.z * scalar) + + def __rmul__(self, scalar: float) -> Vector3: + return self.__mul__(scalar) + + def __truediv__(self, scalar: float) -> Vector3: + return self.__class__(self.x / scalar, self.y / scalar, self.z / scalar) + + def __neg__(self) -> Vector3: + return self.__class__(-self.x, -self.y, -self.z) + + def dot(self, other: VectorConvertable | Vector3) -> float: + """Compute dot product.""" + other_vector = to_vector(other) + return float(self.x * other_vector.x + self.y * other_vector.y + self.z * other_vector.z) + + def cross(self, other: VectorConvertable | Vector3) -> Vector3: + """Compute cross product (3D vectors only).""" + other_vector = to_vector(other) + return self.__class__( + self.y * other_vector.z - self.z * other_vector.y, + self.z * other_vector.x - self.x * other_vector.z, + self.x * other_vector.y - self.y * other_vector.x, + ) + + def magnitude(self) -> float: + """Alias for length().""" + return self.length() + + def length(self) -> float: + """Compute the Euclidean length (magnitude) of the vector.""" + return float(np.sqrt(self.x * self.x + self.y * self.y + self.z * self.z)) + + def length_squared(self) -> float: + """Compute the squared length of the vector (faster than length()).""" + return float(self.x * self.x + self.y * self.y + self.z * self.z) + + def normalize(self) -> Vector3: + """Return a normalized unit vector in the same direction.""" + length = self.length() + if length < 1e-10: # Avoid division by near-zero + return self.__class__(0.0, 0.0, 0.0) + return self.__class__(self.x / length, self.y / length, self.z / length) + + def to_2d(self) -> Vector3: + """Convert a vector to a 2D vector by taking only the x and y components (z=0).""" + return self.__class__(self.x, self.y, 0.0) + + def distance(self, other: VectorConvertable | Vector3) -> float: + """Compute Euclidean distance to another vector.""" + other_vector = to_vector(other) + dx = self.x - other_vector.x + dy = self.y - other_vector.y + dz = self.z - other_vector.z + return float(np.sqrt(dx * dx + dy * dy + dz * dz)) + + def distance_squared(self, other: VectorConvertable | Vector3) -> float: + """Compute squared Euclidean distance to another vector (faster than distance()).""" + other_vector = to_vector(other) + dx = self.x - other_vector.x + dy = self.y - other_vector.y + dz = self.z - other_vector.z + return float(dx * dx + dy * dy + dz * dz) + + def angle(self, other: VectorConvertable | Vector3) -> float: + """Compute the angle (in radians) between this vector and another.""" + other_vector = to_vector(other) + this_length = self.length() + other_length = other_vector.length() + + if this_length < 1e-10 or other_length < 1e-10: + return 0.0 + + cos_angle = np.clip( + self.dot(other_vector) / (this_length * other_length), + -1.0, + 1.0, + ) + return float(np.arccos(cos_angle)) + + def project(self, onto: VectorConvertable | Vector3) -> Vector3: + """Project this vector onto another vector.""" + onto_vector = to_vector(onto) + onto_length_sq = ( + onto_vector.x * onto_vector.x + + onto_vector.y * onto_vector.y + + onto_vector.z * onto_vector.z + ) + if onto_length_sq < 1e-10: + return self.__class__(0.0, 0.0, 0.0) + + scalar_projection = self.dot(onto_vector) / onto_length_sq + return self.__class__( + scalar_projection * onto_vector.x, + scalar_projection * onto_vector.y, + scalar_projection * onto_vector.z, + ) + + @classmethod + def zeros(cls) -> Vector3: + """Create a zero 3D vector.""" + return cls() + + @classmethod + def ones(cls) -> Vector3: + """Create a 3D vector of ones.""" + return cls(1.0, 1.0, 1.0) + + @classmethod + def unit_x(cls) -> Vector3: + """Create a unit vector in the x direction.""" + return cls(1.0, 0.0, 0.0) + + @classmethod + def unit_y(cls) -> Vector3: + """Create a unit vector in the y direction.""" + return cls(0.0, 1.0, 0.0) + + @classmethod + def unit_z(cls) -> Vector3: + """Create a unit vector in the z direction.""" + return cls(0.0, 0.0, 1.0) + + def to_list(self) -> list[float]: + """Convert the vector to a list.""" + return [self.x, self.y, self.z] + + def to_tuple(self) -> tuple[float, float, float]: + """Convert the vector to a tuple.""" + return (self.x, self.y, self.z) + + def to_numpy(self) -> np.ndarray: + """Convert the vector to a numpy array.""" + return np.array([self.x, self.y, self.z], dtype=float) + + def is_zero(self) -> bool: + """Check if this is a zero vector (all components are zero). + + Returns: + True if all components are zero, False otherwise + """ + return bool(np.allclose([self.x, self.y, self.z], 0.0)) + + @property + def quaternion(self) -> Quaternion: # type: ignore[name-defined] + return self.to_quaternion() + + def to_quaternion(self) -> Quaternion: # type: ignore[name-defined] + """Convert Vector3 representing Euler angles (roll, pitch, yaw) to a Quaternion. + + Assumes this Vector3 contains Euler angles in radians: + - x component: roll (rotation around x-axis) + - y component: pitch (rotation around y-axis) + - z component: yaw (rotation around z-axis) + + Returns: + Quaternion: The equivalent quaternion representation + """ + # Import here to avoid circular imports + from dimos.msgs.geometry_msgs.Quaternion import Quaternion + + # Extract Euler angles + roll = self.x + pitch = self.y + yaw = self.z + + # Convert Euler angles to quaternion using ZYX convention + # Source: https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles + + # Compute half angles + cy = np.cos(yaw * 0.5) + sy = np.sin(yaw * 0.5) + cp = np.cos(pitch * 0.5) + sp = np.sin(pitch * 0.5) + cr = np.cos(roll * 0.5) + sr = np.sin(roll * 0.5) + + # Compute quaternion components + w = cr * cp * cy + sr * sp * sy + x = sr * cp * cy - cr * sp * sy + y = cr * sp * cy + sr * cp * sy + z = cr * cp * sy - sr * sp * cy + + return Quaternion(x, y, z, w) + + def __bool__(self) -> bool: + """Boolean conversion for Vector. + + A Vector is considered False if it's a zero vector (all components are zero), + and True otherwise. + + Returns: + False if vector is zero, True otherwise + """ + return not self.is_zero() + + +def to_numpy(value: Vector3 | np.ndarray | Sequence[int | float]) -> np.ndarray: + """Convert a value to a numpy array.""" + if isinstance(value, Vector3): + return value.to_numpy() + elif isinstance(value, np.ndarray): + return value + else: + return np.array(value, dtype=float) + + +def to_vector(value: VectorConvertable | Vector3) -> Vector3: + """Convert a vector-compatible value to a Vector3 object.""" + if isinstance(value, Vector3): + return value + return Vector3(value) + + +def to_tuple(value: Vector3 | np.ndarray | Sequence[int | float]) -> tuple[float, ...]: + """Convert a value to a tuple.""" + if isinstance(value, Vector3): + return value.to_tuple() + elif isinstance(value, np.ndarray): + return tuple(value.tolist()) + elif isinstance(value, tuple): + return value + else: + return tuple(value) + + +def to_list(value: Vector3 | np.ndarray | Sequence[int | float]) -> list[float]: + """Convert a value to a list.""" + if isinstance(value, Vector3): + return value.to_list() + elif isinstance(value, np.ndarray): + result: list[float] = value.tolist() + return result + elif isinstance(value, list): + return value + else: + return list(value) + + +VectorLike: TypeAlias = VectorConvertable | Vector3 + + +def make_vector3(x: float, y: float, z: float) -> Vector3: + return Vector3(x, y, z) diff --git a/dimos/msgs/geometry_msgs/Wrench.py b/dimos/msgs/geometry_msgs/Wrench.py new file mode 100644 index 00000000000..7b3a4427758 --- /dev/null +++ b/dimos/msgs/geometry_msgs/Wrench.py @@ -0,0 +1,121 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from collections.abc import Sequence +from typing import Any, overload + +from dimos_lcm.geometry_msgs import Wrench as LCMWrench +import numpy as np + +from dimos.msgs.geometry_msgs.Vector3 import Vector3, VectorLike + + +class Wrench(LCMWrench): # type: ignore[misc] + """Force (N) and torque (Nm) in 3D space.""" + + force: Vector3 + torque: Vector3 + msg_name = "geometry_msgs.Wrench" + + @overload + def __init__(self) -> None: ... + + @overload + def __init__( + self, + force: VectorLike | None = ..., + torque: VectorLike | None = ..., + ) -> None: ... + + @overload + def __init__(self, wrench: Wrench | LCMWrench, /) -> None: ... + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize a wrench. + + Supported forms: + Wrench() # zero wrench + Wrench(force, torque) + Wrench(force=..., torque=...) # keyword args, either optional + Wrench(other_wrench) # copy constructor + Wrench(lcm_wrench) # from LCM message + """ + force: Any = None + torque: Any = None + + if len(args) == 2: + force, torque = args + elif len(args) == 1: + value = args[0] + # Wrench before LCMWrench (it is a subclass); anything else is a + # force, same as the `force=` keyword. + if isinstance(value, Wrench | LCMWrench): + force, torque = value.force, value.torque + else: + force = value + elif args: + raise TypeError(f"Wrench takes 1 or 2 positional arguments ({len(args)} given)") + + if kwargs: + force = kwargs.pop("force", force) + torque = kwargs.pop("torque", torque) + if kwargs: + raise TypeError(f"Wrench got unexpected keyword arguments {sorted(kwargs)}") + + self.force = Vector3() if force is None else Vector3(force) + self.torque = Vector3() if torque is None else Vector3(torque) + + @classmethod + def from_array(cls, ft: Sequence[float] | np.ndarray) -> Wrench: + """Build from a 6-element ``[fx, fy, fz, tx, ty, tz]`` sensor reading.""" + if len(ft) != 6: + raise ValueError(f"Expected 6 elements [fx, fy, fz, tx, ty, tz], got {len(ft)}") + return cls(force=ft[:3], torque=ft[3:]) + + def to_array(self) -> np.ndarray: + """``[fx, fy, fz, tx, ty, tz]``.""" + return np.concatenate([self.force.to_numpy(), self.torque.to_numpy()]) + + @classmethod + def zero(cls) -> Wrench: + return cls() + + def is_zero(self) -> bool: + return self.force.is_zero() and self.torque.is_zero() + + def __add__(self, other: Wrench) -> Wrench: + if not isinstance(other, Wrench): + return NotImplemented + return Wrench(force=self.force + other.force, torque=self.torque + other.torque) + + def __sub__(self, other: Wrench) -> Wrench: + if not isinstance(other, Wrench): + return NotImplemented + return Wrench(force=self.force - other.force, torque=self.torque - other.torque) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Wrench): + return False + return self.force == other.force and self.torque == other.torque + + def __bool__(self) -> bool: + return not self.is_zero() + + def __repr__(self) -> str: + return f"Wrench(force={self.force!r}, torque={self.torque!r})" + + def __str__(self) -> str: + return f"Wrench:\n Force: {self.force}\n Torque: {self.torque}" diff --git a/dimos/msgs/geometry_msgs/WrenchStamped.py b/dimos/msgs/geometry_msgs/WrenchStamped.py new file mode 100644 index 00000000000..12e6e940072 --- /dev/null +++ b/dimos/msgs/geometry_msgs/WrenchStamped.py @@ -0,0 +1,97 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from collections.abc import Sequence +import time +from typing import Any, BinaryIO + +from dimos_lcm.geometry_msgs import WrenchStamped as LCMWrenchStamped +import numpy as np + +from dimos.msgs.geometry_msgs.Wrench import Wrench +from dimos.types.timestamped import Timestamped + + +class WrenchStamped(Wrench, Timestamped): + """A force/torque measurement with a timestamp and frame_id.""" + + msg_name = "geometry_msgs.WrenchStamped" + ts: float + frame_id: str + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize a stamped wrench. + + Takes ``(ts, frame_id)`` positionally, plus every Wrench keyword. Any other + positional form belongs to Wrench, so ``WrenchStamped(force, torque)`` works + as it does on the base class. + """ + ts: Any + # A leading number or string is a timestamp; anything else is a Wrench argument. + if args and isinstance(args[0], int | float | str): + ts = args[0] + frame_id = args[1] if len(args) > 1 else kwargs.pop("frame_id", "") + wrench_args: tuple[Any, ...] = () + else: + ts = kwargs.pop("ts", None) + frame_id = kwargs.pop("frame_id", "") + wrench_args = args + + self.frame_id = frame_id + self.ts = time.time() if ts is None else ts + super().__init__(*wrench_args, **kwargs) + + @classmethod + def from_array( # type: ignore[override] + cls, + ft: Sequence[float] | np.ndarray, + frame_id: str = "ft_sensor", + ts: float | None = None, + ) -> WrenchStamped: + """Build from a 6-element ``[fx, fy, fz, tx, ty, tz]`` sensor reading.""" + if len(ft) != 6: + raise ValueError(f"Expected 6 elements [fx, fy, fz, tx, ty, tz], got {len(ft)}") + return cls(ts=ts, frame_id=frame_id, force=ft[:3], torque=ft[3:]) + + def lcm_encode(self) -> bytes: + lcm_msg = LCMWrenchStamped() + lcm_msg.wrench = self + [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = self.ros_timestamp() + lcm_msg.header.frame_id = self.frame_id + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes | BinaryIO) -> WrenchStamped: + lcm_msg = LCMWrenchStamped.lcm_decode(data) + return cls( + ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), + frame_id=lcm_msg.header.frame_id, + force=[lcm_msg.wrench.force.x, lcm_msg.wrench.force.y, lcm_msg.wrench.force.z], + torque=[lcm_msg.wrench.torque.x, lcm_msg.wrench.torque.y, lcm_msg.wrench.torque.z], + ) + + def __repr__(self) -> str: + return ( + f"WrenchStamped(force={self.force!r}, torque={self.torque!r}, " + f"ts={self.ts}, frame_id={self.frame_id!r})" + ) + + def __str__(self) -> str: + return ( + f"WrenchStamped(force=[{self.force.x:.3f}, {self.force.y:.3f}, {self.force.z:.3f}], " + f"torque=[{self.torque.x:.3f}, {self.torque.y:.3f}, {self.torque.z:.3f}], " + f"frame_id={self.frame_id!r})" + ) diff --git a/dimos/msgs/manipulation_msgs/GraspCandidate.py b/dimos/msgs/manipulation_msgs/GraspCandidate.py new file mode 100644 index 00000000000..f83db6016f4 --- /dev/null +++ b/dimos/msgs/manipulation_msgs/GraspCandidate.py @@ -0,0 +1,40 @@ +# Copyright 2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import math +import pickle + +from dimos.msgs.geometry_msgs.Pose import Pose + + +class GraspCandidate: + """A robot TCP pose and its generator-local ranking score.""" + + msg_name = "manipulation_msgs.GraspCandidate" + + def __init__(self, pose: Pose | None = None, score: float = 0.0) -> None: + self.pose = pose if pose is not None else Pose(0.0, 0.0, 0.0) + self.score = float(score) + if not math.isfinite(self.score): + raise ValueError("GraspCandidate.score must be finite") + + def encode(self) -> bytes: + return pickle.dumps({"pose": self.pose, "score": self.score}) + + @classmethod + def decode(cls, data: bytes) -> GraspCandidate: + value = pickle.loads(data) + return cls(value["pose"], value["score"]) diff --git a/dimos/msgs/manipulation_msgs/GraspCandidateArray.py b/dimos/msgs/manipulation_msgs/GraspCandidateArray.py new file mode 100644 index 00000000000..5144d0b5b91 --- /dev/null +++ b/dimos/msgs/manipulation_msgs/GraspCandidateArray.py @@ -0,0 +1,48 @@ +# Copyright 2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from collections.abc import Iterator +import pickle + +from dimos.msgs.manipulation_msgs.GraspCandidate import GraspCandidate +from dimos.msgs.std_msgs.Header import Header + + +class GraspCandidateArray: + """Ordered grasp proposals sharing one input-cloud header.""" + + msg_name = "manipulation_msgs.GraspCandidateArray" + + def __init__( + self, header: Header | None = None, candidates: list[GraspCandidate] | None = None + ) -> None: + self.header = header if header is not None else Header(0.0) + self.candidates = candidates if candidates is not None else [] + + def __len__(self) -> int: + return len(self.candidates) + + def __iter__(self) -> Iterator[GraspCandidate]: + return iter(self.candidates) + + def encode(self) -> bytes: + """Encode using the repository's pickle transport convention.""" + return pickle.dumps({"header": self.header, "candidates": self.candidates}) + + @classmethod + def decode(cls, data: bytes) -> GraspCandidateArray: + value = pickle.loads(data) + return cls(value["header"], value["candidates"]) diff --git a/dimos/msgs/nav_msgs/OccupancyGrid.py b/dimos/msgs/nav_msgs/OccupancyGrid.py new file mode 100644 index 00000000000..7370cd6bf70 --- /dev/null +++ b/dimos/msgs/nav_msgs/OccupancyGrid.py @@ -0,0 +1,598 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from enum import IntEnum +from functools import lru_cache +import time +from typing import TYPE_CHECKING, BinaryIO + +from dimos_lcm.nav_msgs import ( + MapMetaData, + OccupancyGrid as LCMOccupancyGrid, +) +from dimos_lcm.std_msgs import Time as LCMTime +import numpy as np + +from dimos.msgs.geometry_msgs.Pose import Pose +from dimos.msgs.geometry_msgs.Vector3 import Vector3, VectorLike +from dimos.types.timestamped import Timestamped + + +@lru_cache(maxsize=16) +def _get_matplotlib_cmap(name: str): # type: ignore[no-untyped-def] + """Get a matplotlib colormap by name (cached for performance).""" + # Lazy import to save time. + import matplotlib.pyplot as plt + + return plt.get_cmap(name) + + +@lru_cache(maxsize=16) +def _build_occupancy_lut( + colormap: str | None, + opacity: float, + background: str | None, +) -> np.ndarray: + """Build a 102-entry RGBA LUT for grid values -1..100. One-time cost per config.""" + bg_rgb = np.array([0, 0, 0], dtype=np.float32) + if background is not None: + bg = background.lstrip("#") + bg_rgb = np.array([int(bg[i : i + 2], 16) for i in (0, 2, 4)], dtype=np.float32) + + # LUT: index 0 = grid value -1 (unknown), index 1 = grid value 0 (free), index 2..101 = grid values 1..100 + lut = np.zeros((102, 4), dtype=np.uint8) + + # Unknown (-1) → index 0: black + lut[0] = [0, 0, 0, 255] + + if colormap is not None: + cmap = _get_matplotlib_cmap(colormap) + # Free (0) → index 1 + fg = np.array(cmap(0.0)[:3]) * 255 + blended = fg * opacity + bg_rgb * (1 - opacity) + lut[1, :3] = blended.astype(np.uint8) + lut[1, 3] = 255 + + # Occupied (1..100) → index 2..101 + for cost in range(1, 101): + cost_norm = 0.5 + (cost / 100) * 0.5 + fg = np.array(cmap(cost_norm)[:3]) * 255 + blended = fg * opacity + bg_rgb * (1 - opacity) + lut[cost + 1, :3] = blended.astype(np.uint8) + lut[cost + 1, 3] = 255 + else: + # Foxglove-style: free = #484981, occupied = gradient to black + fg_free = np.array([72, 73, 129], dtype=np.float32) + blended_free = fg_free * opacity + bg_rgb * (1 - opacity) + lut[1, :3] = blended_free.astype(np.uint8) + lut[1, 3] = 255 + + for cost in range(1, 101): + factor = 1 - cost / 100 + fg = np.array([72 * factor, 73 * factor, 129 * factor], dtype=np.float32) + blended = fg * opacity + bg_rgb * (1 - opacity) + lut[cost + 1, :3] = blended.astype(np.uint8) + lut[cost + 1, 3] = 255 + + return lut + + +if TYPE_CHECKING: + from pathlib import Path + + from numpy.typing import NDArray + from rerun._baseclasses import Archetype + + +def block_max_reduce(cells: NDArray[np.int8], factor: int) -> NDArray[np.int8]: + """Coarsen an occupancy grid by taking the max of factor x factor blocks. + + Block maximum (not mean) so coarsening never erases an obstacle; a block + is unknown (-1) only when every cell in it is unknown. Trailing remainder + rows/cols are trimmed, keeping row 0/col 0 - the origin corner - so the + grid origin stays valid. Grids thinner than `factor` pass through. + """ + h, w = cells.shape[:2] + new_h, new_w = h // factor, w // factor + if new_h == 0 or new_w == 0: + return cells + trimmed = cells[: new_h * factor, : new_w * factor] + blocks = trimmed.reshape(new_h, factor, new_w, factor) + # Sink unknown below every known value for the max, then map it back. + as_int = blocks.astype(np.int16) + known = np.where(as_int < 0, -1000, as_int) + reduced = known.max(axis=(1, 3)) + reduced[reduced == -1000] = -1 + result: NDArray[np.int8] = reduced.astype(np.int8) + return result + + +class CostValues(IntEnum): + """Standard cost values for occupancy grid cells. + + These values follow the ROS nav_msgs/OccupancyGrid convention: + - 0: Free space + - 1-99: Occupied space with varying cost levels + - 100: Lethal obstacle (definitely occupied) + - -1: Unknown space + """ + + UNKNOWN = -1 # Unknown space + FREE = 0 # Free space + OCCUPIED = 100 # Occupied/lethal space + + +class OccupancyGrid(Timestamped): + """ + Convenience wrapper for nav_msgs/OccupancyGrid with numpy array support. + """ + + msg_name = "nav_msgs.OccupancyGrid" + + # Attributes + ts: float + frame_id: str + info: MapMetaData + grid: NDArray[np.int8] + + def __init__( + self, + grid: NDArray[np.int8] | None = None, + width: int | None = None, + height: int | None = None, + resolution: float = 0.05, + origin: Pose | None = None, + frame_id: str = "world", + ts: float | None = None, + ) -> None: + """Initialize OccupancyGrid. + + Args: + grid: 2D numpy array of int8 values (height x width) + width: Width in cells (used if grid is None) + height: Height in cells (used if grid is None) + resolution: Grid resolution in meters/cell + origin: Origin pose of the grid + frame_id: Reference frame + ts: Timestamp (defaults to current time if 0) + """ + + self.frame_id = frame_id + self.ts = time.time() if ts is None else ts + + if grid is not None: + # Initialize from numpy array + if grid.ndim != 2: + raise ValueError("Grid must be a 2D array") + height, width = grid.shape + self.info = MapMetaData( + map_load_time=self._to_lcm_time(), # type: ignore[no-untyped-call] + resolution=resolution, + width=width, + height=height, + origin=origin or Pose(), + ) + self.grid = grid.astype(np.int8) + elif width is not None and height is not None: + # Initialize with dimensions + self.info = MapMetaData( + map_load_time=self._to_lcm_time(), # type: ignore[no-untyped-call] + resolution=resolution, + width=width, + height=height, + origin=origin or Pose(), + ) + self.grid = np.full((height, width), -1, dtype=np.int8) + else: + # Initialize empty + self.info = MapMetaData(map_load_time=self._to_lcm_time()) # type: ignore[no-untyped-call] + self.grid = np.array([], dtype=np.int8) + + def _to_lcm_time(self): # type: ignore[no-untyped-def] + """Convert timestamp to LCM Time.""" + + s = int(self.ts) + return LCMTime(sec=s, nsec=int((self.ts - s) * 1_000_000_000)) + + @property + def width(self) -> int: + """Width of the grid in cells.""" + return self.info.width # type: ignore[no-any-return] + + @property + def height(self) -> int: + """Height of the grid in cells.""" + return self.info.height # type: ignore[no-any-return] + + @property + def resolution(self) -> float: + """Grid resolution in meters/cell.""" + return self.info.resolution # type: ignore[no-any-return] + + @property + def origin(self) -> Pose: + """Origin pose of the grid.""" + return self.info.origin # type: ignore[no-any-return] + + @property + def total_cells(self) -> int: + """Total number of cells in the grid.""" + return self.width * self.height + + @property + def occupied_cells(self) -> int: + """Number of occupied cells (value >= 1).""" + return int(np.sum(self.grid >= 1)) + + @property + def free_cells(self) -> int: + """Number of free cells (value == 0).""" + return int(np.sum(self.grid == 0)) + + @property + def unknown_cells(self) -> int: + """Number of unknown cells (value == -1).""" + return int(np.sum(self.grid == -1)) + + @property + def occupied_percent(self) -> float: + """Percentage of cells that are occupied.""" + return (self.occupied_cells / self.total_cells * 100) if self.total_cells > 0 else 0.0 + + @property + def free_percent(self) -> float: + """Percentage of cells that are free.""" + return (self.free_cells / self.total_cells * 100) if self.total_cells > 0 else 0.0 + + @property + def unknown_percent(self) -> float: + """Percentage of cells that are unknown.""" + return (self.unknown_cells / self.total_cells * 100) if self.total_cells > 0 else 0.0 + + @classmethod + def from_path(cls, path: Path) -> OccupancyGrid: + match path.suffix.lower(): + case ".npy": + return cls(grid=np.load(path)) + case ".png": + # Lazy import: Pillow serves only this file loader; message + # transport must not depend on it. + from PIL import Image + + img = Image.open(path).convert("L") + return cls(grid=np.array(img).astype(np.int8)) + case _: + raise NotImplementedError(f"Unsupported file format: {path.suffix}") + + def world_to_grid(self, point: VectorLike) -> Vector3: + """Convert world coordinates to grid coordinates. + + Args: + point: A vector-like object containing X,Y coordinates + + Returns: + Vector3 with grid coordinates + """ + positionVector = Vector3(point) + # Get origin position + ox = self.origin.position.x + oy = self.origin.position.y + + # Convert to grid coordinates (simplified, assuming no rotation) + grid_x = (positionVector.x - ox) / self.resolution + grid_y = (positionVector.y - oy) / self.resolution + + return Vector3(grid_x, grid_y, 0.0) + + def grid_to_world(self, grid_point: VectorLike) -> Vector3: + """Convert grid coordinates to world coordinates. + + Args: + grid_point: Vector-like object containing grid coordinates + + Returns: + World position as Vector3 + """ + gridVector = Vector3(grid_point) + # Get origin position + ox = self.origin.position.x + oy = self.origin.position.y + + # Convert to world (simplified, no rotation) + x = ox + gridVector.x * self.resolution + y = oy + gridVector.y * self.resolution + + return Vector3(x, y, 0.0) + + def __str__(self) -> str: + """Create a concise string representation.""" + origin_pos = self.origin.position + + parts = [ + f"▦ OccupancyGrid[{self.frame_id}]", + f"{self.width}x{self.height}", + f"({self.width * self.resolution:.1f}x{self.height * self.resolution:.1f}m @", + f"{1 / self.resolution:.0f}cm res)", + f"Origin: ({origin_pos.x:.2f}, {origin_pos.y:.2f})", + f"▣ {self.occupied_percent:.1f}%", + f"□ {self.free_percent:.1f}%", + f"◌ {self.unknown_percent:.1f}%", + ] + + return " ".join(parts) + + def __repr__(self) -> str: + """Create a detailed representation.""" + return ( + f"OccupancyGrid(width={self.width}, height={self.height}, " + f"resolution={self.resolution}, frame_id='{self.frame_id}', " + f"occupied={self.occupied_cells}, free={self.free_cells}, " + f"unknown={self.unknown_cells})" + ) + + def lcm_encode(self) -> bytes: + """Encode OccupancyGrid to LCM bytes.""" + # Create LCM message + lcm_msg = LCMOccupancyGrid() + + # Build header on demand + s = int(self.ts) + lcm_msg.header.stamp.sec = s + lcm_msg.header.stamp.nsec = int((self.ts - s) * 1_000_000_000) + lcm_msg.header.frame_id = self.frame_id + + # Copy map metadata + lcm_msg.info = self.info + + # Convert numpy array to flat data list + if self.grid.size > 0: + flat_data = self.grid.flatten() + lcm_msg.data_length = len(flat_data) + lcm_msg.data = flat_data.tolist() + else: + lcm_msg.data_length = 0 + lcm_msg.data = [] + + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes | BinaryIO) -> OccupancyGrid: + """Decode LCM bytes to OccupancyGrid.""" + lcm_msg = LCMOccupancyGrid.lcm_decode(data) + + # Extract timestamp and frame_id from header + ts = lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000) + frame_id = lcm_msg.header.frame_id + + # Extract grid data; empty stays 2-D so the constructor accepts it. + if lcm_msg.data and lcm_msg.info.width > 0 and lcm_msg.info.height > 0: + grid = np.array(lcm_msg.data, dtype=np.int8).reshape( + (lcm_msg.info.height, lcm_msg.info.width) + ) + else: + grid = np.zeros((0, 0), dtype=np.int8) + + # The wire origin decodes as a plain generated pose without the dimos + # Pose surface (.yaw etc.); rebuild it field by field so the origin + # property honors its declared type. + o = lcm_msg.info.origin + lcm_msg.info.origin = Pose( + position=[o.position.x, o.position.y, o.position.z], + orientation=[o.orientation.x, o.orientation.y, o.orientation.z, o.orientation.w], + ) + + # Create new instance + instance = cls( + grid=grid, + resolution=lcm_msg.info.resolution, + origin=lcm_msg.info.origin, + frame_id=frame_id, + ts=ts, + ) + instance.info = lcm_msg.info + return instance + + def filter_above(self, threshold: int) -> OccupancyGrid: + """Create a new OccupancyGrid with only values above threshold. + + Args: + threshold: Keep cells with values > threshold + + Returns: + New OccupancyGrid where: + - Cells > threshold: kept as-is + - Cells <= threshold: set to -1 (unknown) + - Unknown cells (-1): preserved + """ + new_grid = self.grid.copy() + + # Create mask for cells to filter (not unknown and <= threshold) + filter_mask = (new_grid != -1) & (new_grid <= threshold) + + # Set filtered cells to unknown + new_grid[filter_mask] = -1 + + # Create new OccupancyGrid + filtered = OccupancyGrid( + new_grid, + resolution=self.resolution, + origin=self.origin, + frame_id=self.frame_id, + ts=self.ts, + ) + + return filtered + + def filter_below(self, threshold: int) -> OccupancyGrid: + """Create a new OccupancyGrid with only values below threshold. + + Args: + threshold: Keep cells with values < threshold + + Returns: + New OccupancyGrid where: + - Cells < threshold: kept as-is + - Cells >= threshold: set to -1 (unknown) + - Unknown cells (-1): preserved + """ + new_grid = self.grid.copy() + + # Create mask for cells to filter (not unknown and >= threshold) + filter_mask = (new_grid != -1) & (new_grid >= threshold) + + # Set filtered cells to unknown + new_grid[filter_mask] = -1 + + # Create new OccupancyGrid + filtered = OccupancyGrid( + new_grid, + resolution=self.resolution, + origin=self.origin, + frame_id=self.frame_id, + ts=self.ts, + ) + + return filtered + + def max(self) -> OccupancyGrid: + """Create a new OccupancyGrid with all non-unknown cells set to maximum value. + + Returns: + New OccupancyGrid where: + - All non-unknown cells: set to CostValues.OCCUPIED (100) + - Unknown cells: preserved as CostValues.UNKNOWN (-1) + """ + new_grid = self.grid.copy() + + # Set all non-unknown cells to max + new_grid[new_grid != CostValues.UNKNOWN] = CostValues.OCCUPIED + + # Create new OccupancyGrid + maxed = OccupancyGrid( + new_grid, + resolution=self.resolution, + origin=self.origin, + frame_id=self.frame_id, + ts=self.ts, + ) + + return maxed + + def copy(self) -> OccupancyGrid: + """Create a deep copy of the OccupancyGrid. + + Returns: + A new OccupancyGrid instance with copied data. + """ + return OccupancyGrid( + grid=self.grid.copy(), + resolution=self.resolution, + origin=self.origin, + frame_id=self.frame_id, + ts=self.ts, + ) + + def cell_value(self, world_position: Vector3) -> int: + grid_position = self.world_to_grid(world_position) + x = int(grid_position.x) + y = int(grid_position.y) + + if not (0 <= x < self.width and 0 <= y < self.height): + return CostValues.UNKNOWN + + return int(self.grid[y, x]) + + def to_rerun( + self, + colormap: str | None = None, + z_offset: float = 0, + opacity: float = 1.0, + cost_range: tuple[int, int] | None = None, + background: str | None = None, + color_lookup_table: np.ndarray | None = None, + ) -> Archetype: + """Convert to 3D textured mesh overlay on floor plane. + + Uses a single quad with the occupancy grid as a texture. + Much more efficient than per-cell quads (4 vertices vs n_cells*4). + """ + import rerun as rr + + if self.grid.size == 0: + return rr.Mesh3D(vertex_positions=[]) + + # Downsample grid before LUT to avoid allocating huge RGBA array + max_tex = 256 + grid = self.grid[::-1] # flip for world coords (view, no copy) + if grid.shape[0] > max_tex or grid.shape[1] > max_tex: + step_h = max(1, grid.shape[0] // max_tex) + step_w = max(1, grid.shape[1] // max_tex) + grid = grid[::step_h, ::step_w] + + if color_lookup_table is None: + color_lookup_table = _build_occupancy_lut(colormap, opacity, background) + rgba = np.ascontiguousarray(color_lookup_table[np.clip(grid + 1, 0, 101)]) + + # Apply cost_range filter on downsampled grid + if cost_range is not None: + out_of_range = ((grid < cost_range[0]) | (grid > cost_range[1])) & (grid != -1) + if np.any(out_of_range): + bg_rgb = [0, 0, 0] + if background is not None: + bg = background.lstrip("#") + bg_rgb = [int(bg[i : i + 2], 16) for i in (0, 2, 4)] + rgba[out_of_range, :3] = bg_rgb + rgba[out_of_range, 3] = 255 + + # Single quad covering entire grid + ox = self.origin.position.x + oy = self.origin.position.y + w = self.width * self.resolution + h = self.height * self.resolution + + vertices = np.array( + [ + [ox, oy, z_offset], # 0: bottom-left (world) + [ox + w, oy, z_offset], # 1: bottom-right + [ox + w, oy + h, z_offset], # 2: top-right + [ox, oy + h, z_offset], # 3: top-left + ], + dtype=np.float32, + ) + + indices = np.array([[0, 1, 2], [0, 2, 3]], dtype=np.uint32) + + # UV coords: Rerun uses top-left origin for textures + # Grid row 0 is at world y=oy (bottom), row H-1 at y=oy+h (top) + # Texture row 0 = grid row 0, so: + # world bottom (v0,v1) -> texture v=1 (bottom of texture) + # world top (v2,v3) -> texture v=0 (top of texture) + texcoords = np.array( + [ + [0.0, 1.0], # v0: bottom-left world -> bottom-left tex + [1.0, 1.0], # v1: bottom-right world -> bottom-right tex + [1.0, 0.0], # v2: top-right world -> top-right tex + [0.0, 0.0], # v3: top-left world -> top-left tex + ], + dtype=np.float32, + ) + + return rr.Mesh3D( + vertex_positions=vertices, + triangle_indices=indices, + vertex_texcoords=texcoords, + albedo_texture=rgba, + ) diff --git a/dimos/msgs/nav_msgs/Odometry.py b/dimos/msgs/nav_msgs/Odometry.py new file mode 100644 index 00000000000..5e986672ea9 --- /dev/null +++ b/dimos/msgs/nav_msgs/Odometry.py @@ -0,0 +1,249 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import time +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from rerun._baseclasses import Archetype + +from dimos_lcm.nav_msgs import Odometry as LCMOdometry +import numpy as np + +from dimos.msgs.geometry_msgs.Pose import Pose +from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped +from dimos.msgs.geometry_msgs.PoseWithCovariance import PoseWithCovariance +from dimos.msgs.geometry_msgs.Twist import Twist +from dimos.msgs.geometry_msgs.TwistWithCovariance import TwistWithCovariance +from dimos.types.timestamped import Timestamped + +if TYPE_CHECKING: + from dimos.msgs.geometry_msgs.Quaternion import Quaternion + from dimos.msgs.geometry_msgs.Vector3 import Vector3 + + +class Odometry(Timestamped): + """Odometry message with pose, twist, and frame information.""" + + msg_name = "nav_msgs.Odometry" + + def __init__( + self, + ts: float | None = None, + frame_id: str = "", + child_frame_id: str = "", + pose: PoseWithCovariance | Pose | None = None, + twist: TwistWithCovariance | Twist | None = None, + ) -> None: + self.ts = time.time() if ts is None else ts + self.frame_id = frame_id + self.child_frame_id = child_frame_id + + if pose is None: + self.pose = PoseWithCovariance() + elif isinstance(pose, Pose): + self.pose = PoseWithCovariance(pose) + else: + self.pose = pose + + if twist is None: + self.twist = TwistWithCovariance() + elif isinstance(twist, Twist): + self.twist = TwistWithCovariance(twist) + else: + self.twist = twist + + # -- Convenience properties -- + + @property + def position(self) -> Vector3: + return self.pose.position + + @property + def orientation(self) -> Quaternion: + return self.pose.orientation + + @property + def linear_velocity(self) -> Vector3: + return self.twist.linear + + @property + def angular_velocity(self) -> Vector3: + return self.twist.angular + + @property + def x(self) -> float: + return self.pose.x + + @property + def y(self) -> float: + return self.pose.y + + @property + def z(self) -> float: + return self.pose.z + + @property + def vx(self) -> float: + return self.twist.linear.x + + @property + def vy(self) -> float: + return self.twist.linear.y + + @property + def vz(self) -> float: + return self.twist.linear.z + + @property + def wx(self) -> float: + return self.twist.angular.x + + @property + def wy(self) -> float: + return self.twist.angular.y + + @property + def wz(self) -> float: + return self.twist.angular.z + + @property + def roll(self) -> float: + return self.pose.roll + + @property + def pitch(self) -> float: + return self.pose.pitch + + @property + def yaw(self) -> float: + return self.pose.yaw + + def to_pose_stamped(self) -> PoseStamped: + return PoseStamped( + ts=self.ts, + frame_id=self.frame_id, + position=[self.position.x, self.position.y, self.position.z], + orientation=[ + self.orientation.x, + self.orientation.y, + self.orientation.z, + self.orientation.w, + ], + ) + + # -- Serialization -- + + def lcm_encode(self) -> bytes: + lcm_msg = LCMOdometry() + + lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec = self.ros_timestamp() + lcm_msg.header.frame_id = self.frame_id + lcm_msg.child_frame_id = self.child_frame_id + + lcm_msg.pose.pose = self.pose.pose + lcm_msg.pose.covariance = list(np.asarray(self.pose.covariance)) + + lcm_msg.twist.twist = self.twist.twist + lcm_msg.twist.covariance = list(np.asarray(self.twist.covariance)) + + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes) -> Odometry: + lcm_msg = LCMOdometry.lcm_decode(data) + + ts = lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000) + + pose = Pose( + position=[ + lcm_msg.pose.pose.position.x, + lcm_msg.pose.pose.position.y, + lcm_msg.pose.pose.position.z, + ], + orientation=[ + lcm_msg.pose.pose.orientation.x, + lcm_msg.pose.pose.orientation.y, + lcm_msg.pose.pose.orientation.z, + lcm_msg.pose.pose.orientation.w, + ], + ) + twist = Twist( + linear=[ + lcm_msg.twist.twist.linear.x, + lcm_msg.twist.twist.linear.y, + lcm_msg.twist.twist.linear.z, + ], + angular=[ + lcm_msg.twist.twist.angular.x, + lcm_msg.twist.twist.angular.y, + lcm_msg.twist.twist.angular.z, + ], + ) + + return cls( + ts=ts, + frame_id=lcm_msg.header.frame_id, + child_frame_id=lcm_msg.child_frame_id, + pose=PoseWithCovariance(pose, lcm_msg.pose.covariance), + twist=TwistWithCovariance(twist, lcm_msg.twist.covariance), + ) + + # -- Comparison / display -- + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Odometry): + return False + return ( + abs(self.ts - other.ts) < 1e-6 + and self.frame_id == other.frame_id + and self.child_frame_id == other.child_frame_id + and self.pose == other.pose + and self.twist == other.twist + ) + + def __repr__(self) -> str: + return ( + f"Odometry(ts={self.ts:.6f}, frame_id='{self.frame_id}', " + f"child_frame_id='{self.child_frame_id}', pose={self.pose!r}, twist={self.twist!r})" + ) + + def __str__(self) -> str: + return ( + f"Odometry:\n" + f" Timestamp: {self.ts:.6f}\n" + f" Frame: {self.frame_id} -> {self.child_frame_id}\n" + f" Position: [{self.x:.3f}, {self.y:.3f}, {self.z:.3f}]\n" + f" Orientation: [roll={self.roll:.3f}, pitch={self.pitch:.3f}, yaw={self.yaw:.3f}]\n" + f" Linear Velocity: [{self.vx:.3f}, {self.vy:.3f}, {self.vz:.3f}]\n" + f" Angular Velocity: [{self.wx:.3f}, {self.wy:.3f}, {self.wz:.3f}]" + ) + + def to_rerun(self) -> Archetype: + """Convert to rerun Transform3D for visualizing the pose.""" + import rerun as rr + + return rr.Transform3D( + translation=[self.x, self.y, self.z], + rotation=rr.Quaternion( + xyzw=[ + self.orientation.x, + self.orientation.y, + self.orientation.z, + self.orientation.w, + ] + ), + ) diff --git a/dimos/msgs/nav_msgs/Path.py b/dimos/msgs/nav_msgs/Path.py new file mode 100644 index 00000000000..cd901f2a06f --- /dev/null +++ b/dimos/msgs/nav_msgs/Path.py @@ -0,0 +1,214 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import time +from typing import TYPE_CHECKING, BinaryIO + +from dimos_lcm.geometry_msgs import ( + Point as LCMPoint, + Pose as LCMPose, + PoseStamped as LCMPoseStamped, + Quaternion as LCMQuaternion, +) +from dimos_lcm.nav_msgs import Path as LCMPath +from dimos_lcm.std_msgs import Header as LCMHeader, Time as LCMTime + +from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped +from dimos.types.timestamped import Timestamped + +if TYPE_CHECKING: + from collections.abc import Iterator + + from rerun._baseclasses import Archetype + + +def sec_nsec(ts): # type: ignore[no-untyped-def] + s = int(ts) + return [s, int((ts - s) * 1_000_000_000)] + + +class Path(Timestamped): + msg_name = "nav_msgs.Path" + ts: float + frame_id: str + poses: list[PoseStamped] + + def __init__( # type: ignore[no-untyped-def] + self, + ts: float | None = None, + frame_id: str = "world", + poses: list[PoseStamped] | None = None, + **kwargs, + ) -> None: + self.frame_id = frame_id + self.ts = time.time() if ts is None else ts + self.poses = poses if poses is not None else [] + + def __len__(self) -> int: + """Return the number of poses in the path.""" + return len(self.poses) + + def __bool__(self) -> bool: + """Return True if path has poses.""" + return len(self.poses) > 0 + + def head(self) -> PoseStamped | None: + """Return the first pose in the path, or None if empty.""" + return self.poses[0] if self.poses else None + + def last(self) -> PoseStamped | None: + """Return the last pose in the path, or None if empty.""" + return self.poses[-1] if self.poses else None + + def tail(self) -> Path: + """Return a new Path with all poses except the first.""" + return Path(ts=self.ts, frame_id=self.frame_id, poses=self.poses[1:] if self.poses else []) + + def push(self, pose: PoseStamped) -> Path: + """Return a new Path with the pose appended (immutable).""" + return Path(ts=self.ts, frame_id=self.frame_id, poses=[*self.poses, pose]) + + def push_mut(self, pose: PoseStamped) -> None: + """Append a pose to this path (mutable).""" + self.poses.append(pose) + + def lcm_encode(self) -> bytes: + """Encode Path to LCM bytes.""" + lcm_msg = LCMPath() + + # Set poses + lcm_msg.poses_length = len(self.poses) + lcm_poses = [] # Build list separately to avoid LCM library reuse issues + for pose in self.poses: + lcm_pose = LCMPoseStamped() + # Create new pose objects to avoid LCM library reuse bug + lcm_pose.pose = LCMPose() + lcm_pose.pose.position = LCMPoint() + lcm_pose.pose.orientation = LCMQuaternion() + + # Set the pose geometry data + lcm_pose.pose.position.x = pose.x + lcm_pose.pose.position.y = pose.y + lcm_pose.pose.position.z = pose.z + lcm_pose.pose.orientation.x = pose.orientation.x + lcm_pose.pose.orientation.y = pose.orientation.y + lcm_pose.pose.orientation.z = pose.orientation.z + lcm_pose.pose.orientation.w = pose.orientation.w + + # Create new header to avoid reuse + lcm_pose.header = LCMHeader() + lcm_pose.header.stamp = LCMTime() + + # Set the header with pose timestamp but path's frame_id + [lcm_pose.header.stamp.sec, lcm_pose.header.stamp.nsec] = sec_nsec(pose.ts) # type: ignore[no-untyped-call] + lcm_pose.header.frame_id = self.frame_id # All poses use path's frame_id + lcm_poses.append(lcm_pose) + lcm_msg.poses = lcm_poses + + # Set header with path's own timestamp + [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] + lcm_msg.header.frame_id = self.frame_id + + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes | BinaryIO) -> Path: + """Decode LCM bytes to Path.""" + lcm_msg = LCMPath.lcm_decode(data) + + # Decode header + header_ts = lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000) + frame_id = lcm_msg.header.frame_id + + # Decode poses - all use the path's frame_id + poses = [] + for lcm_pose in lcm_msg.poses: + pose = PoseStamped( + ts=lcm_pose.header.stamp.sec + (lcm_pose.header.stamp.nsec / 1_000_000_000), + frame_id=frame_id, # Use path's frame_id for all poses + position=[ + lcm_pose.pose.position.x, + lcm_pose.pose.position.y, + lcm_pose.pose.position.z, + ], + orientation=[ + lcm_pose.pose.orientation.x, + lcm_pose.pose.orientation.y, + lcm_pose.pose.orientation.z, + lcm_pose.pose.orientation.w, + ], + ) + poses.append(pose) + + # Use header timestamp for the path + return cls(ts=header_ts, frame_id=frame_id, poses=poses) + + def __str__(self) -> str: + """String representation of Path.""" + return f"Path(frame_id='{self.frame_id}', poses={len(self.poses)})" + + def __getitem__(self, index: int | slice) -> PoseStamped | list[PoseStamped]: + """Allow indexing and slicing of poses.""" + return self.poses[index] + + def __iter__(self) -> Iterator: # type: ignore[type-arg] + """Allow iteration over poses.""" + return iter(self.poses) + + def slice(self, start: int, end: int | None = None) -> Path: + """Return a new Path with a slice of poses.""" + return Path(ts=self.ts, frame_id=self.frame_id, poses=self.poses[start:end]) + + def extend(self, other: Path) -> Path: + """Return a new Path with poses from both paths (immutable).""" + return Path(ts=self.ts, frame_id=self.frame_id, poses=self.poses + other.poses) + + def extend_mut(self, other: Path) -> None: + """Extend this path with poses from another path (mutable).""" + self.poses.extend(other.poses) + + def reverse(self) -> Path: + """Return a new Path with poses in reverse order.""" + return Path(ts=self.ts, frame_id=self.frame_id, poses=list(reversed(self.poses))) + + def clear(self) -> None: + """Clear all poses from this path (mutable).""" + self.poses.clear() + + def to_rerun( + self, + color: tuple[int, int, int] = (0, 255, 128), + z_offset: float = 0.5, + radii: float = 0.05, + ) -> Archetype: + """Convert to rerun LineStrips3D format. + + Args: + color: RGB color tuple for the path line + z_offset: Height above floor to render path (default 0.2m to avoid costmap occlusion) + radii: Thickness of the path line (default 0.05m = 5cm) + + Returns: + rr.LineStrips3D archetype for logging to rerun + """ + import rerun as rr + + if not self.poses: + return rr.LineStrips3D([]) + + # Lift path above floor so it's visible over costmap + points = [[p.x, p.y, p.z + z_offset] for p in self.poses] + return rr.LineStrips3D([points], colors=[color], radii=radii) diff --git a/dimos/msgs/sensor_msgs/CompressedImage.py b/dimos/msgs/sensor_msgs/CompressedImage.py new file mode 100644 index 00000000000..f1853986fc5 --- /dev/null +++ b/dimos/msgs/sensor_msgs/CompressedImage.py @@ -0,0 +1,175 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from dataclasses import dataclass, field +import time +from typing import TYPE_CHECKING, Any, Literal + +from dimos_lcm.sensor_msgs.CompressedImage import CompressedImage as LCMCompressedImage +from dimos_lcm.std_msgs.Header import Header + +from dimos.types.timestamped import Timestamped, to_human_readable + +# cv2/turbojpeg/Image are imported lazily so this module stays cheap for +# byte-level consumers that never encode or decode pixels. +if TYPE_CHECKING: + from dimos.msgs.sensor_msgs.Image import Image + +CompressionFormat = Literal["jpeg", "png", "jxl"] + + +@dataclass +class CompressedImage(Timestamped): + """Compressed image bytes (JPEG/PNG/JPEG-XL) — ROS sensor_msgs/CompressedImage.""" + + msg_name = "sensor_msgs.CompressedImage" + + data: bytes = b"" + format: str = "jpeg" + frame_id: str = "" + ts: float = field(default_factory=time.time) + + def __str__(self) -> str: + return ( + f"CompressedImage(format={self.format}, bytes={len(self.data)}, " + f"ts={to_human_readable(self.ts)})" + ) + + @classmethod + def from_image( + cls, + image: Image, + format: CompressionFormat = "jpeg", + quality: int = 75, + max_width: int | None = None, + effort: int | None = None, + ) -> CompressedImage: + """Encode a raw Image. + + JPEG rejects 16-bit/depth formats; PNG rejects float depth. JXL takes + everything: lossless for 16-bit/float data (depth must survive the wire + exactly), `quality` for uint8. `effort` (jxl only, 1-9) trades encode + cpu for size; defaults are pinned for camera-rate streaming. + """ + from dimos.msgs.sensor_msgs.Image import Image, ImageFormat + + if not isinstance(image, Image): + raise TypeError(f"from_image expects Image, got {type(image).__name__}") + if max_width is not None: + image, _ = image.resize_to_fit(max_width, max_width) + if format == "jpeg": + if image.format in (ImageFormat.GRAY16, ImageFormat.DEPTH, ImageFormat.DEPTH16): + raise ValueError(f"JPEG cannot encode {image.format.value}; use format='png'") + data = image.to_jpeg_bytes(quality=quality) + elif format == "png": + import cv2 + + if image.format in (ImageFormat.DEPTH, ImageFormat.DEPTH16): + raise ValueError(f"PNG cannot encode {image.format.value}") + arr = image.data if image.channels == 1 else image.to_bgr().data + ok, buf = cv2.imencode(".png", arr) + if not ok: + raise ValueError("PNG encoding failed") + data = buf.tobytes() + elif format == "jxl": + import imagecodecs + import numpy as np + + # zero-copy passthrough unless channel order actually needs fixing + if image.channels == 1 or image.format is ImageFormat.RGB: + arr = image.data + else: + arr = image.to_rgb().data + if arr.dtype not in (np.uint8, np.uint16, np.float32): + raise ValueError(f"JXL cannot encode dtype {arr.dtype}") + arr = np.ascontiguousarray(arr) + # libjxl's default effort=7 costs 83-300ms per 720p frame; these + # pins keep camera-rate (13ms lossy / 3ms lossless) for ~5% size + if arr.dtype == np.uint8: + data = bytes(imagecodecs.jpegxl_encode(arr, level=quality, effort=effort or 3)) + else: + data = bytes(imagecodecs.jpegxl_encode(arr, lossless=True, effort=effort or 1)) + else: + raise ValueError(f"unsupported format {format!r}") + return cls(data=data, format=format, frame_id=image.frame_id, ts=image.ts) + + def decode(self) -> Image: + """Decompress to a raw Image; ts/frame_id preserved.""" + from dimos.msgs.sensor_msgs.Image import Image, ImageFormat + + if self.format.startswith("jpeg"): + from turbojpeg import TJPF_RGB, TurboJPEG + + arr = TurboJPEG().decode(self.data, pixel_format=TJPF_RGB) + fmt = ImageFormat.RGB + elif self.format.startswith("png"): + import cv2 + import numpy as np + + arr = cv2.imdecode(np.frombuffer(self.data, dtype=np.uint8), cv2.IMREAD_UNCHANGED) + if arr is None: + raise ValueError("PNG decoding failed") + if arr.ndim == 2: + fmt = ImageFormat.GRAY16 if arr.dtype == np.uint16 else ImageFormat.GRAY + elif arr.shape[2] == 4: + fmt = ImageFormat.BGRA + else: + fmt = ImageFormat.BGR + elif self.format.startswith("jxl"): + import imagecodecs + import numpy as np + + arr = imagecodecs.jpegxl_decode(self.data) + if arr.ndim == 2: + fmt = {np.float32: ImageFormat.DEPTH, np.uint16: ImageFormat.GRAY16}.get( + arr.dtype.type, ImageFormat.GRAY + ) + else: + fmt = ImageFormat.RGBA if arr.shape[2] == 4 else ImageFormat.RGB + else: + raise ValueError(f"unsupported format {self.format!r}") + return Image(data=arr, format=fmt, frame_id=self.frame_id, ts=self.ts) + + def lcm_encode(self, frame_id: str | None = None) -> bytes: + msg = LCMCompressedImage() + msg.header = Header() + msg.header.seq = 0 + msg.header.frame_id = frame_id or self.frame_id + msg.header.stamp.sec = int(self.ts) + msg.header.stamp.nsec = int((self.ts - int(self.ts)) * 1e9) + msg.format = self.format + msg.data = self.data + msg.data_length = len(self.data) + return msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes, **kwargs: Any) -> CompressedImage: + msg = LCMCompressedImage.lcm_decode(data) + return cls( + data=bytes(msg.data), + format=msg.format, + frame_id=msg.header.frame_id, + ts=msg.header.stamp.sec + msg.header.stamp.nsec / 1e9, + ) + + def to_rerun(self) -> Any: + import rerun as rr + + if self.format.startswith(("jpeg", "png")): + media_type = "image/jpeg" if self.format.startswith("jpeg") else "image/png" + return rr.EncodedImage(contents=self.data, media_type=media_type) + # formats rerun's EncodedImage can't decode: send pixels instead + return self.decode().to_rerun() diff --git a/dimos/msgs/sensor_msgs/Image.py b/dimos/msgs/sensor_msgs/Image.py new file mode 100644 index 00000000000..05b05225757 --- /dev/null +++ b/dimos/msgs/sensor_msgs/Image.py @@ -0,0 +1,700 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import base64 +from dataclasses import dataclass, field +from enum import Enum +import time +from typing import TYPE_CHECKING, Any, Literal, TypedDict +import warnings + +from dimos_lcm.sensor_msgs.Image import Image as LCMImage +from dimos_lcm.std_msgs.Header import Header +import numpy as np +import reactivex as rx +from reactivex import operators as ops +from turbojpeg import TJPF_RGB + +from dimos.types.timestamped import Timestamped, TimestampedBufferCollection, to_human_readable +from dimos.utils.reactive import quality_barrier +from dimos.utils.turbojpeg import get_turbojpeg + +if TYPE_CHECKING: + from collections.abc import Callable + import os + + from reactivex.abc import SchedulerBase + from reactivex.observable import Observable + + +class ImageFormat(Enum): + BGR = "BGR" + RGB = "RGB" + RGBA = "RGBA" + BGRA = "BGRA" + GRAY = "GRAY" + GRAY16 = "GRAY16" + DEPTH = "DEPTH" + DEPTH16 = "DEPTH16" + + +class AgentImageMessage(TypedDict): + """Type definition for agent-compatible image representation.""" + + type: Literal["image"] + source_type: Literal["base64"] + mime_type: Literal["image/jpeg", "image/png"] + data: str # Base64 encoded image data + + +@dataclass +class Image(Timestamped): + """Simple NumPy-based image container.""" + + msg_name = "sensor_msgs.Image" + + data: np.ndarray[Any, np.dtype[Any]] = field( + default_factory=lambda: np.zeros((1, 1, 3), dtype=np.uint8) + ) + format: ImageFormat = field(default=ImageFormat.BGR) + frame_id: str = field(default="") + ts: float = field(default_factory=time.time) + + def __post_init__(self) -> None: + if not isinstance(self.data, np.ndarray): + self.data = np.asarray(self.data) + if self.data.ndim < 2: + raise ValueError("Image requires a 2D/3D NumPy array") + + def __str__(self) -> str: + return ( + f"Image(shape={self.shape}, format={self.format.value}, dtype={self.dtype}, " + f"ts={to_human_readable(self.ts)})" + ) + + def __repr__(self) -> str: + return f"Image(shape={self.shape}, format={self.format.value}, dtype={self.dtype}, frame_id='{self.frame_id}', ts={self.ts})" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Image): + return False + return ( + np.array_equal(self.data, other.data) + and self.format == other.format + and self.frame_id == other.frame_id + and abs(self.ts - other.ts) < 1e-6 + ) + + def __len__(self) -> int: + return int(self.height * self.width) + + def __getstate__(self) -> dict[str, Any]: + return {"data": self.data, "format": self.format, "frame_id": self.frame_id, "ts": self.ts} + + def __setstate__(self, state: dict[str, Any]) -> None: + self.data = state.get("data", np.zeros((1, 1, 3), dtype=np.uint8)) + self.format = state.get("format", ImageFormat.BGR) + self.frame_id = state.get("frame_id", "") + self.ts = state.get("ts", time.time()) + + @property + def height(self) -> int: + return int(self.data.shape[0]) + + @property + def width(self) -> int: + return int(self.data.shape[1]) + + @property + def channels(self) -> int: + if self.data.ndim == 2: + return 1 + if self.data.ndim == 3: + return int(self.data.shape[2]) + raise ValueError("Invalid image dimensions") + + @property + def shape(self) -> tuple[int, ...]: + return tuple(self.data.shape) + + @property + def dtype(self) -> np.dtype[Any]: + return self.data.dtype + + def copy(self) -> Image: + return Image(data=self.data.copy(), format=self.format, frame_id=self.frame_id, ts=self.ts) + + @classmethod + def from_numpy( + cls, + np_image: np.ndarray, + format: ImageFormat = ImageFormat.BGR, + frame_id: str = "", + ts: float | None = None, + ) -> Image: + return cls( + data=np.asarray(np_image), + format=format, + frame_id=frame_id, + ts=ts if ts is not None else time.time(), + ) + + @classmethod + def from_file( + cls, + filepath: str | os.PathLike[str], + format: ImageFormat = ImageFormat.RGB, + ) -> Image: + import cv2 + + arr = cv2.imread(str(filepath), cv2.IMREAD_UNCHANGED) + if arr is None: + raise ValueError(f"Could not load image from {filepath}") + if arr.ndim == 2: + detected = ImageFormat.GRAY16 if arr.dtype == np.uint16 else ImageFormat.GRAY + elif arr.shape[2] == 3: + detected = ImageFormat.BGR # OpenCV default + elif arr.shape[2] == 4: + detected = ImageFormat.BGRA # OpenCV default + else: + detected = format + return cls(data=arr, format=detected) + + @classmethod + def from_opencv( + cls, + cv_image: np.ndarray, + format: ImageFormat = ImageFormat.BGR, + frame_id: str = "", + ts: float | None = None, + ) -> Image: + """Construct from an OpenCV image (NumPy array).""" + return cls( + data=cv_image, + format=format, + frame_id=frame_id, + ts=ts if ts is not None else time.time(), + ) + + def to_opencv(self) -> np.ndarray: + """Convert to OpenCV BGR format.""" + import cv2 + + arr = self.data + if self.format == ImageFormat.BGR: + return arr + if self.format == ImageFormat.RGB: + return cv2.cvtColor(arr, cv2.COLOR_RGB2BGR) + if self.format == ImageFormat.RGBA: + return cv2.cvtColor(arr, cv2.COLOR_RGBA2BGR) + if self.format == ImageFormat.BGRA: + return cv2.cvtColor(arr, cv2.COLOR_BGRA2BGR) + if self.format in ( + ImageFormat.GRAY, + ImageFormat.GRAY16, + ImageFormat.DEPTH, + ImageFormat.DEPTH16, + ): + return arr + raise ValueError(f"Unsupported format: {self.format}") + + def as_numpy(self) -> np.ndarray: + """Get image data as numpy array.""" + return self.data + + def to_rgb(self) -> Image: + import cv2 + + if self.format == ImageFormat.RGB: + return self.copy() + arr = self.data + if self.format == ImageFormat.BGR: + return Image( + data=cv2.cvtColor(arr, cv2.COLOR_BGR2RGB), + format=ImageFormat.RGB, + frame_id=self.frame_id, + ts=self.ts, + ) + if self.format == ImageFormat.RGBA: + warnings.warn("to_rgb() drops alpha channel from RGBA image", stacklevel=2) + return Image( + data=cv2.cvtColor(arr, cv2.COLOR_RGBA2RGB), + format=ImageFormat.RGB, + frame_id=self.frame_id, + ts=self.ts, + ) + if self.format == ImageFormat.BGRA: + warnings.warn("to_rgb() drops alpha channel from BGRA image", stacklevel=2) + return Image( + data=cv2.cvtColor(arr, cv2.COLOR_BGRA2RGB), + format=ImageFormat.RGB, + frame_id=self.frame_id, + ts=self.ts, + ) + if self.format in (ImageFormat.GRAY, ImageFormat.GRAY16, ImageFormat.DEPTH16): + gray8 = (arr / 256).astype(np.uint8) if self.format != ImageFormat.GRAY else arr + rgb = cv2.cvtColor(gray8, cv2.COLOR_GRAY2RGB) + return Image(data=rgb, format=ImageFormat.RGB, frame_id=self.frame_id, ts=self.ts) + return self.copy() + + def to_bgr(self) -> Image: + import cv2 + + if self.format == ImageFormat.BGR: + return self.copy() + arr = self.data + if self.format == ImageFormat.RGB: + return Image( + data=cv2.cvtColor(arr, cv2.COLOR_RGB2BGR), + format=ImageFormat.BGR, + frame_id=self.frame_id, + ts=self.ts, + ) + if self.format == ImageFormat.RGBA: + warnings.warn("to_bgr() drops alpha channel from RGBA image", stacklevel=2) + return Image( + data=cv2.cvtColor(arr, cv2.COLOR_RGBA2BGR), + format=ImageFormat.BGR, + frame_id=self.frame_id, + ts=self.ts, + ) + if self.format == ImageFormat.BGRA: + warnings.warn("to_bgr() drops alpha channel from BGRA image", stacklevel=2) + return Image( + data=cv2.cvtColor(arr, cv2.COLOR_BGRA2BGR), + format=ImageFormat.BGR, + frame_id=self.frame_id, + ts=self.ts, + ) + if self.format in (ImageFormat.GRAY, ImageFormat.GRAY16, ImageFormat.DEPTH16): + gray8 = (arr / 256).astype(np.uint8) if self.format != ImageFormat.GRAY else arr + return Image( + data=cv2.cvtColor(gray8, cv2.COLOR_GRAY2BGR), + format=ImageFormat.BGR, + frame_id=self.frame_id, + ts=self.ts, + ) + return self.copy() + + def to_grayscale(self) -> Image: + import cv2 + + if self.format in (ImageFormat.GRAY, ImageFormat.GRAY16, ImageFormat.DEPTH): + return self.copy() + if self.format == ImageFormat.BGR: + return Image( + data=cv2.cvtColor(self.data, cv2.COLOR_BGR2GRAY), + format=ImageFormat.GRAY, + frame_id=self.frame_id, + ts=self.ts, + ) + if self.format == ImageFormat.RGB: + return Image( + data=cv2.cvtColor(self.data, cv2.COLOR_RGB2GRAY), + format=ImageFormat.GRAY, + frame_id=self.frame_id, + ts=self.ts, + ) + if self.format in (ImageFormat.RGBA, ImageFormat.BGRA): + code = cv2.COLOR_RGBA2GRAY if self.format == ImageFormat.RGBA else cv2.COLOR_BGRA2GRAY + return Image( + data=cv2.cvtColor(self.data, code), + format=ImageFormat.GRAY, + frame_id=self.frame_id, + ts=self.ts, + ) + raise ValueError(f"Unsupported format: {self.format}") + + def to_rerun(self) -> Any: + """Convert to a Rerun archetype: JPEG-encoded for color images, raw for depth.""" + import rerun as rr + + match self.format: + case ImageFormat.DEPTH | ImageFormat.DEPTH16: + return rr.DepthImage(self.data) + case ImageFormat.GRAY16: + return rr.Image(self.data, color_model="L") + case _: + return rr.EncodedImage(contents=self.to_jpeg_bytes(), media_type="image/jpeg") + + def resize(self, width: int, height: int, interpolation: int | None = None) -> Image: + import cv2 + + if interpolation is None: + interpolation = cv2.INTER_LINEAR + return Image( + data=cv2.resize(self.data, (width, height), interpolation=interpolation), + format=self.format, + frame_id=self.frame_id, + ts=self.ts, + ) + + def resize_to_fit( + self, max_width: int, max_height: int, interpolation: int | None = None + ) -> tuple[Image, float]: + """Resize image to fit within max dimensions while preserving aspect ratio. + + Only scales down if image exceeds max dimensions. Returns self if already fits. + + Returns: + Tuple of (resized_image, scale_factor). Scale factor is 1.0 if no resize needed. + """ + if self.width <= max_width and self.height <= max_height: + return self, 1.0 + + scale = min(max_width / self.width, max_height / self.height) + new_width = int(self.width * scale) + new_height = int(self.height * scale) + return self.resize(new_width, new_height, interpolation), scale + + def crop(self, x: int, y: int, width: int, height: int) -> Image: + """Crop the image to the specified region. + + Args: + x: Starting x coordinate (left edge) + y: Starting y coordinate (top edge) + width: Width of the cropped region + height: Height of the cropped region + + Returns: + A new Image containing the cropped region + """ + img_height, img_width = self.data.shape[:2] + + # Clamp the crop region to image bounds + x = max(0, min(x, img_width)) + y = max(0, min(y, img_height)) + x_end = min(x + width, img_width) + y_end = min(y + height, img_height) + + # Perform the crop using array slicing + if self.data.ndim == 2: + cropped_data = self.data[y:y_end, x:x_end] + else: + cropped_data = self.data[y:y_end, x:x_end, :] + + return Image(data=cropped_data, format=self.format, frame_id=self.frame_id, ts=self.ts) + + @property + def brightness(self) -> float: + """Return mean brightness in [0, 1]. + + Strides to ~256px on the long edge first — ~O(N/step²) cheaper than + reading every pixel, and the mean converges quickly (CLT). + """ + max_val = 65535.0 if self.format in (ImageFormat.GRAY16, ImageFormat.DEPTH16) else 255.0 + step = max(1, max(self.data.shape[:2]) // 256) + return float(self.data[::step, ::step].mean() / max_val) + + @property + def sharpness(self) -> float: + """Return sharpness score. + + Downsamples to ~160px wide before computing Laplacian variance + for fast evaluation (~10-20x cheaper than full-res Sobel). + """ + import cv2 + + gray = self.to_grayscale().data + # Downsample to ~160px wide for cheap evaluation + h, w = gray.shape[:2] + if w > 160: + scale = 160.0 / w + gray = cv2.resize(gray, (160, int(h * scale)), interpolation=cv2.INTER_AREA) + lap_var = cv2.Laplacian(gray, cv2.CV_32F).var() + if lap_var <= 0: + return 0.0 + return float(np.clip((np.log10(lap_var + 1) - 1.0) / 3.0, 0.0, 1.0)) + + def save(self, filepath: str) -> bool: + import cv2 + + arr = self.to_opencv() + return cv2.imwrite(filepath, arr) + + def to_base64( + self, + quality: int = 80, + *, + max_width: int | None = None, + max_height: int | None = None, + ) -> str: + """Encode the image as a base64 JPEG string. + + Args: + quality: JPEG quality (0-100). + max_width: Optional maximum width to constrain the encoded image. + max_height: Optional maximum height to constrain the encoded image. + + Returns: + Base64-encoded JPEG representation of the image. + """ + import cv2 + + bgr_image = self.to_bgr().to_opencv() + height, width = bgr_image.shape[:2] + + scale = 1.0 + if max_width is not None and width > max_width: + scale = min(scale, max_width / width) + if max_height is not None and height > max_height: + scale = min(scale, max_height / height) + + if scale < 1.0: + new_width = max(1, round(width * scale)) + new_height = max(1, round(height * scale)) + bgr_image = cv2.resize(bgr_image, (new_width, new_height), interpolation=cv2.INTER_AREA) + + encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), int(np.clip(quality, 0, 100))] + success, buffer = cv2.imencode(".jpg", bgr_image, encode_param) + if not success: + raise ValueError("Failed to encode image as JPEG") + + return base64.b64encode(buffer.tobytes()).decode("utf-8") + + def agent_encode(self) -> AgentImageMessage: + return [ # type: ignore[return-value] + { + "type": "image_url", + "image_url": {"url": f"data:image/jpeg;base64,{self.to_base64()}"}, + } + ] + + # LCM encode/decode + def lcm_encode(self, frame_id: str | None = None) -> bytes: + """Convert to LCM Image message.""" + msg = LCMImage() + + # Header + msg.header = Header() + msg.header.seq = 0 + msg.header.frame_id = frame_id or self.frame_id + + # Set timestamp + if self.ts is not None: + msg.header.stamp.sec = int(self.ts) + msg.header.stamp.nsec = int((self.ts - int(self.ts)) * 1e9) + else: + now = time.time() + msg.header.stamp.sec = int(now) + msg.header.stamp.nsec = int((now - int(now)) * 1e9) + + # Image properties + msg.height = self.height + msg.width = self.width + msg.encoding = _get_lcm_encoding(self.format, self.dtype) + msg.is_bigendian = False + + # Calculate step (bytes per row) + channels = 1 if self.data.ndim == 2 else self.data.shape[2] + msg.step = self.width * self.dtype.itemsize * channels + + view = memoryview(np.ascontiguousarray(self.data)).cast("B") # type: ignore[arg-type] + msg.data_length = len(view) + msg.data = view + + return msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes, **kwargs: Any) -> Image: + msg = LCMImage.lcm_decode(data) + + # JPEG-compressed images use a different decode path. + if msg.encoding == "jpeg": + return cls.lcm_jpeg_decode(data, **kwargs) + + fmt, dtype, channels = _parse_lcm_encoding(msg.encoding) + arr: np.ndarray[Any, Any] = np.frombuffer(msg.data, dtype=dtype) + if channels == 1: + arr = arr.reshape((msg.height, msg.width)) + else: + arr = arr.reshape((msg.height, msg.width, channels)) + return cls( + data=arr, + format=fmt, + frame_id=msg.header.frame_id if hasattr(msg, "header") else "", + ts=( + msg.header.stamp.sec + msg.header.stamp.nsec / 1e9 + if hasattr(msg, "header") + and hasattr(msg.header, "stamp") + and msg.header.stamp.sec > 0 + else time.time() + ), + ) + + def to_jpeg_bytes(self, quality: int = 75) -> bytes: + """Encode this image as JPEG bytes using TurboJPEG. + + Args: + quality: JPEG compression quality (0-100, default 75). + + Returns: + Raw JPEG bytes. + """ + # Canonicalize to RGB so JPEG bytes are deterministic regardless of input format. + rgb_array = self.to_rgb().data + return get_turbojpeg().encode(rgb_array, quality=quality, pixel_format=TJPF_RGB) # type: ignore[no-any-return] + + def lcm_jpeg_encode(self, quality: int = 75, frame_id: str | None = None) -> bytes: + """Convert to LCM Image message with JPEG-compressed data. + + Args: + quality: JPEG compression quality (0-100, default 75) + frame_id: Optional frame ID override + + Returns: + LCM-encoded bytes with JPEG-compressed image data + """ + msg = LCMImage() + + # Header + msg.header = Header() + msg.header.seq = 0 + msg.header.frame_id = frame_id or self.frame_id + + # Set timestamp + if self.ts is not None: + msg.header.stamp.sec = int(self.ts) + msg.header.stamp.nsec = int((self.ts - int(self.ts)) * 1e9) + else: + now = time.time() + msg.header.stamp.sec = int(now) + msg.header.stamp.nsec = int((now - int(now)) * 1e9) + + jpeg_data = self.to_jpeg_bytes(quality=quality) + + # Store JPEG data and metadata + msg.height = self.height + msg.width = self.width + msg.encoding = "jpeg" + msg.is_bigendian = False + msg.step = 0 # Not applicable for compressed format + + msg.data_length = len(jpeg_data) + msg.data = jpeg_data + + return msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_jpeg_decode(cls, data: bytes, **kwargs: Any) -> Image: + """Decode an LCM Image message with JPEG-compressed data. + + Args: + data: LCM-encoded bytes containing JPEG-compressed image + + Returns: + Image instance + """ + msg = LCMImage.lcm_decode(data) + + if msg.encoding != "jpeg": + raise ValueError(f"Expected JPEG encoding, got {msg.encoding}") + + rgb_array = get_turbojpeg().decode(msg.data, pixel_format=TJPF_RGB) + + return cls( + data=rgb_array, + format=ImageFormat.RGB, + frame_id=msg.header.frame_id if hasattr(msg, "header") else "", + ts=( + msg.header.stamp.sec + msg.header.stamp.nsec / 1e9 + if hasattr(msg, "header") + and hasattr(msg.header, "stamp") + and msg.header.stamp.sec > 0 + else time.time() + ), + ) + + +def sharpness_window(target_frequency: float, source: Observable[Image]) -> Observable[Image]: + """Emit the sharpest Image seen within each sliding time window.""" + from reactivex.scheduler import ThreadPoolScheduler + + if target_frequency <= 0: + raise ValueError("target_frequency must be positive") + + window = TimestampedBufferCollection(1.0 / target_frequency) # type: ignore[var-annotated] + source.subscribe(window.add) + + thread_scheduler = ThreadPoolScheduler(max_workers=1) + + def find_best(*_args: Any) -> Image | None: + if len(window) == 0: + return None + return max(window, key=lambda img: img.sharpness) # type: ignore[no-any-return] + + return rx.interval(1.0 / target_frequency).pipe( # type: ignore[misc] + ops.observe_on(thread_scheduler), + ops.map(find_best), + ops.filter(lambda img: img is not None), + ) + + +def sharpness_barrier( + target_frequency: float, scheduler: SchedulerBase | None = None +) -> Callable[[Observable[Image]], Observable[Image]]: + """Select the sharpest Image within each time window.""" + if target_frequency <= 0: + raise ValueError("target_frequency must be positive") + return quality_barrier(lambda image: image.sharpness, target_frequency, scheduler) + + +def _get_lcm_encoding(fmt: ImageFormat, dtype: np.dtype) -> str: + if fmt == ImageFormat.GRAY: + if dtype == np.uint8: + return "mono8" + if dtype == np.uint16: + return "mono16" + if fmt == ImageFormat.GRAY16: + return "mono16" + if fmt == ImageFormat.RGB: + return "rgb8" + if fmt == ImageFormat.RGBA: + return "rgba8" + if fmt == ImageFormat.BGR: + return "bgr8" + if fmt == ImageFormat.BGRA: + return "bgra8" + if fmt == ImageFormat.DEPTH: + if dtype == np.float32: + return "32FC1" + if dtype == np.float64: + return "64FC1" + if fmt == ImageFormat.DEPTH16: + if dtype == np.uint16: + return "16UC1" + if dtype == np.int16: + return "16SC1" + raise ValueError(f"Unsupported LCM encoding for fmt={fmt}, dtype={dtype}") + + +def _parse_lcm_encoding(enc: str) -> tuple[ImageFormat, type, int]: + m = { + "mono8": (ImageFormat.GRAY, np.uint8, 1), + "mono16": (ImageFormat.GRAY16, np.uint16, 1), + "rgb8": (ImageFormat.RGB, np.uint8, 3), + "rgba8": (ImageFormat.RGBA, np.uint8, 4), + "bgr8": (ImageFormat.BGR, np.uint8, 3), + "bgra8": (ImageFormat.BGRA, np.uint8, 4), + "32FC1": (ImageFormat.DEPTH, np.float32, 1), + "32FC3": (ImageFormat.RGB, np.float32, 3), + "64FC1": (ImageFormat.DEPTH, np.float64, 1), + "16UC1": (ImageFormat.DEPTH16, np.uint16, 1), + "16SC1": (ImageFormat.DEPTH16, np.int16, 1), + } + if enc not in m: + raise ValueError(f"Unsupported encoding: {enc}") + return m[enc] diff --git a/dimos/msgs/sensor_msgs/Imu.py b/dimos/msgs/sensor_msgs/Imu.py new file mode 100644 index 00000000000..e1cd1f6b621 --- /dev/null +++ b/dimos/msgs/sensor_msgs/Imu.py @@ -0,0 +1,125 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import time + +from dimos_lcm.sensor_msgs.Imu import Imu as LCMImu + +from dimos.msgs.geometry_msgs.Quaternion import Quaternion +from dimos.msgs.geometry_msgs.Vector3 import Vector3 +from dimos.types.timestamped import Timestamped + + +class Imu(Timestamped): + """IMU sensor message mirroring ROS sensor_msgs/Imu. + + Contains orientation, angular velocity, and linear acceleration + with optional covariance matrices (3x3 row-major as flat 9-element lists). + """ + + msg_name = "sensor_msgs.Imu" + + def __init__( + self, + angular_velocity: Vector3 | None = None, + linear_acceleration: Vector3 | None = None, + orientation: Quaternion | None = None, + orientation_covariance: list[float] | None = None, + angular_velocity_covariance: list[float] | None = None, + linear_acceleration_covariance: list[float] | None = None, + frame_id: str = "imu_link", + ts: float | None = None, + ) -> None: + self.ts = ts if ts is not None else time.time() + self.frame_id = frame_id + self.angular_velocity = angular_velocity or Vector3(0.0, 0.0, 0.0) + self.linear_acceleration = linear_acceleration or Vector3(0.0, 0.0, 0.0) + self.orientation = orientation or Quaternion(0.0, 0.0, 0.0, 1.0) + self.orientation_covariance = orientation_covariance or [0.0] * 9 + self.angular_velocity_covariance = angular_velocity_covariance or [0.0] * 9 + self.linear_acceleration_covariance = linear_acceleration_covariance or [0.0] * 9 + + def lcm_encode(self) -> bytes: + msg = LCMImu() + [msg.header.stamp.sec, msg.header.stamp.nsec] = self.ros_timestamp() + msg.header.frame_id = self.frame_id + + msg.orientation.x = self.orientation.x + msg.orientation.y = self.orientation.y + msg.orientation.z = self.orientation.z + msg.orientation.w = self.orientation.w + msg.orientation_covariance = self.orientation_covariance + + msg.angular_velocity.x = self.angular_velocity.x + msg.angular_velocity.y = self.angular_velocity.y + msg.angular_velocity.z = self.angular_velocity.z + msg.angular_velocity_covariance = self.angular_velocity_covariance + + msg.linear_acceleration.x = self.linear_acceleration.x + msg.linear_acceleration.y = self.linear_acceleration.y + msg.linear_acceleration.z = self.linear_acceleration.z + msg.linear_acceleration_covariance = self.linear_acceleration_covariance + + return msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes) -> Imu: + msg = LCMImu.lcm_decode(data) + ts = msg.header.stamp.sec + (msg.header.stamp.nsec / 1_000_000_000) + return cls( + angular_velocity=Vector3( + msg.angular_velocity.x, + msg.angular_velocity.y, + msg.angular_velocity.z, + ), + linear_acceleration=Vector3( + msg.linear_acceleration.x, + msg.linear_acceleration.y, + msg.linear_acceleration.z, + ), + orientation=Quaternion( + msg.orientation.x, + msg.orientation.y, + msg.orientation.z, + msg.orientation.w, + ), + orientation_covariance=list(msg.orientation_covariance), + angular_velocity_covariance=list(msg.angular_velocity_covariance), + linear_acceleration_covariance=list(msg.linear_acceleration_covariance), + frame_id=msg.header.frame_id, + ts=ts, + ) + + def __str__(self) -> str: + return ( + f"Imu(frame_id='{self.frame_id}', " + f"gyro=({self.angular_velocity.x:.3f}, {self.angular_velocity.y:.3f}, {self.angular_velocity.z:.3f}), " + f"accel=({self.linear_acceleration.x:.3f}, {self.linear_acceleration.y:.3f}, {self.linear_acceleration.z:.3f}))" + ) + + def __repr__(self) -> str: + return ( + f"Imu(ts={self.ts}, frame_id='{self.frame_id}', " + f"angular_velocity={self.angular_velocity}, " + f"linear_acceleration={self.linear_acceleration}, " + f"orientation={self.orientation})" + ) + + def to_rerun(self, axis_length: float = 0.2): # type: ignore[no-untyped-def] + """Orientation axes for rerun.""" + import rerun as rr + + return rr.TransformAxes3D(axis_length=axis_length) diff --git a/dimos/msgs/sensor_msgs/ImuInfo.py b/dimos/msgs/sensor_msgs/ImuInfo.py new file mode 100644 index 00000000000..216d7e42a58 --- /dev/null +++ b/dimos/msgs/sensor_msgs/ImuInfo.py @@ -0,0 +1,158 @@ +# Copyright 2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""IMU noise-model information, the inertial sibling of ``CameraInfo``. + +Where the IMU sits comes from tf (``header.frame_id`` names the frame), just as +camera extrinsics do; this message carries what tf cannot: the continuous-time +noise model consumers such as VIO preintegration need. The values are +Allan-variance constants, measured once per model (or per unit); IMUs do not +report them at runtime, so a driver publishes them from its config the same way +``camera_info`` is published alongside images. + +LCM schema (fingerprint-compatible bindings must be generated from this):: + + package sensor_msgs; + + struct ImuInfo { + std_msgs.Header header; + double gyro_noise_density; + double gyro_random_walk; + double accel_noise_density; + double accel_random_walk; + double frequency; + } +""" + +from __future__ import annotations + +from io import BytesIO +import struct + +from dimos_lcm.std_msgs.Header import Header + +from dimos.types.timestamped import Timestamped + +# lcm-gen's base hash for the struct above; the wire fingerprint mixes in +# Header's recursively, matching the generated C++ in dimSLAM. +_BASE_HASH = 0x437A196CBD6B4E49 + + +def _packed_fingerprint() -> bytes: + tmphash = (_BASE_HASH + Header._get_hash_recursive([ImuInfo])) & 0xFFFFFFFFFFFFFFFF + tmphash = (((tmphash << 1) & 0xFFFFFFFFFFFFFFFF) + (tmphash >> 63)) & 0xFFFFFFFFFFFFFFFF + return struct.pack(">Q", tmphash) + + +class ImuInfo(Timestamped): + """IMU noise model: Allan-variance constants plus the delivered sample rate.""" + + msg_name = "sensor_msgs.ImuInfo" + + def __init__( + self, + gyro_noise_density: float = 0.0, + gyro_random_walk: float = 0.0, + accel_noise_density: float = 0.0, + accel_random_walk: float = 0.0, + frequency: float = 0.0, + frame_id: str = "", + ts: float | None = None, + ) -> None: + """Initialize ImuInfo. + + Args: + gyro_noise_density: Gyroscope white noise, rad/s/sqrt(Hz) + gyro_random_walk: Gyroscope bias random walk, rad/s^2/sqrt(Hz) + accel_noise_density: Accelerometer white noise, m/s^2/sqrt(Hz) + accel_random_walk: Accelerometer bias random walk, m/s^3/sqrt(Hz) + frequency: Rate the samples are actually delivered at, Hz + frame_id: The IMU frame; tf places it against the rest of the rig + ts: Timestamp (defaults to now) + """ + import time + + super().__init__(ts if ts is not None else time.time()) + self.gyro_noise_density = gyro_noise_density + self.gyro_random_walk = gyro_random_walk + self.accel_noise_density = accel_noise_density + self.accel_random_walk = accel_random_walk + self.frequency = frequency + self.frame_id = frame_id + + def with_ts(self, ts: float) -> ImuInfo: + """Return a copy of this ImuInfo with the given timestamp.""" + return ImuInfo( + gyro_noise_density=self.gyro_noise_density, + gyro_random_walk=self.gyro_random_walk, + accel_noise_density=self.accel_noise_density, + accel_random_walk=self.accel_random_walk, + frequency=self.frequency, + frame_id=self.frame_id, + ts=ts, + ) + + def with_frame_id(self, frame_id: str) -> ImuInfo: + """Return a copy of this ImuInfo stamped with the given frame.""" + copy = self.with_ts(self.ts) + copy.frame_id = frame_id + return copy + + def lcm_encode(self) -> bytes: + header = Header() + header.seq = 0 + header.frame_id = self.frame_id + header.stamp.sec = int(self.ts) + header.stamp.nsec = int((self.ts - int(self.ts)) * 1e9) + + buf = BytesIO() + buf.write(_packed_fingerprint()) + header._encode_one(buf) + buf.write( + struct.pack( + ">ddddd", + self.gyro_noise_density, + self.gyro_random_walk, + self.accel_noise_density, + self.accel_random_walk, + self.frequency, + ) + ) + return buf.getvalue() + + @classmethod + def lcm_decode(cls, data: bytes) -> ImuInfo: + buf = BytesIO(data) + if buf.read(8) != _packed_fingerprint(): + raise ValueError("Decode error") + header = Header._decode_one(buf) + values = struct.unpack(">ddddd", buf.read(40)) + return cls( + gyro_noise_density=values[0], + gyro_random_walk=values[1], + accel_noise_density=values[2], + accel_random_walk=values[3], + frequency=values[4], + frame_id=header.frame_id, + ts=header.stamp.sec + header.stamp.nsec / 1e9, + ) + + def __repr__(self) -> str: + return ( + f"ImuInfo(gyro_noise_density={self.gyro_noise_density}, " + f"gyro_random_walk={self.gyro_random_walk}, " + f"accel_noise_density={self.accel_noise_density}, " + f"accel_random_walk={self.accel_random_walk}, " + f"frequency={self.frequency}, frame_id='{self.frame_id}')" + ) diff --git a/dimos/msgs/sensor_msgs/JointCommand.py b/dimos/msgs/sensor_msgs/JointCommand.py new file mode 100644 index 00000000000..78c541c50ec --- /dev/null +++ b/dimos/msgs/sensor_msgs/JointCommand.py @@ -0,0 +1,143 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""LCM type definitions +This file automatically generated by lcm. +DO NOT MODIFY BY HAND!!!! +""" + +from io import BytesIO +import struct +import time + + +class JointCommand: + """ + Joint command message for robotic manipulators. + + Supports variable number of joints (DOF) with float64 values. + Can be used for position commands or velocity commands. + Includes timestamp for synchronization. + """ + + msg_name = "sensor_msgs.JointCommand" + + __slots__ = ["num_joints", "positions", "timestamp"] + + __typenames__ = ["double", "int32_t", "double"] + + __dimensions__ = [None, None, ["num_joints"]] + + def __init__( + self, positions: list[float] | None = None, timestamp: float | None = None + ) -> None: + """ + Initialize JointCommand. + + Args: + positions: List of joint values (positions or velocities) + timestamp: Unix timestamp (seconds since epoch). If None, uses current time. + """ + if positions is None: + positions = [] + + if timestamp is None: + timestamp = time.time() + + # LCM Type: double (timestamp) + self.timestamp = timestamp + # LCM Type: int32_t + self.num_joints = len(positions) + # LCM Type: double[num_joints] + self.positions = list(positions) + + def lcm_encode(self): # type: ignore[no-untyped-def] + """Encode for LCM transport (dimos uses lcm_encode method name).""" + return self.encode() # type: ignore[no-untyped-call] + + def encode(self): # type: ignore[no-untyped-def] + buf = BytesIO() + buf.write(JointCommand._get_packed_fingerprint()) # type: ignore[no-untyped-call] + self._encode_one(buf) + return buf.getvalue() + + def _encode_one(self, buf) -> None: # type: ignore[no-untyped-def] + # Encode timestamp + buf.write(struct.pack(">d", self.timestamp)) + + # Encode num_joints + buf.write(struct.pack(">i", self.num_joints)) + + # Encode positions array + for i in range(self.num_joints): + buf.write(struct.pack(">d", self.positions[i])) + + @classmethod + def lcm_decode(cls, data: bytes): # type: ignore[no-untyped-def] + """Decode from LCM transport (dimos uses lcm_decode method name).""" + return cls.decode(data) + + @classmethod + def decode(cls, data: bytes): # type: ignore[no-untyped-def] + if hasattr(data, "read"): + buf = data + else: + buf = BytesIO(data) # type: ignore[assignment] + if buf.read(8) != cls._get_packed_fingerprint(): # type: ignore[no-untyped-call] + raise ValueError("Decode error") + return cls._decode_one(buf) # type: ignore[no-untyped-call] + + @classmethod + def _decode_one(cls, buf): # type: ignore[no-untyped-def] + self = JointCommand.__new__(JointCommand) + + # Decode timestamp + self.timestamp = struct.unpack(">d", buf.read(8))[0] + + # Decode num_joints + self.num_joints = struct.unpack(">i", buf.read(4))[0] + + # Decode positions array + self.positions = [] + for _i in range(self.num_joints): + self.positions.append(struct.unpack(">d", buf.read(8))[0]) + + return self + + @classmethod + def _get_hash_recursive(cls, parents): # type: ignore[no-untyped-def] + if cls in parents: + return 0 + # Hash for variable-length double array message + tmphash = (0x8A3D2E1C5F4B6A9D) & 0xFFFFFFFFFFFFFFFF + tmphash = (((tmphash << 1) & 0xFFFFFFFFFFFFFFFF) + (tmphash >> 63)) & 0xFFFFFFFFFFFFFFFF + return tmphash + + _packed_fingerprint = None + + @classmethod + def _get_packed_fingerprint(cls): # type: ignore[no-untyped-def] + if cls._packed_fingerprint is None: + cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) # type: ignore[no-untyped-call] + return cls._packed_fingerprint + + def get_hash(self): # type: ignore[no-untyped-def] + """Get the LCM hash of the struct""" + return struct.unpack(">Q", JointCommand._get_packed_fingerprint())[0] # type: ignore[no-untyped-call] + + def __str__(self) -> str: + return f"JointCommand(timestamp={self.timestamp:.6f}, num_joints={self.num_joints}, positions={self.positions})" + + def __repr__(self) -> str: + return f"JointCommand(positions={self.positions}, timestamp={self.timestamp})" diff --git a/dimos/msgs/sensor_msgs/JointState.py b/dimos/msgs/sensor_msgs/JointState.py new file mode 100644 index 00000000000..3cbb74e0338 --- /dev/null +++ b/dimos/msgs/sensor_msgs/JointState.py @@ -0,0 +1,144 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import time +from typing import Any, TypeAlias + +from dimos_lcm.sensor_msgs import JointState as LCMJointState + +from dimos.types.timestamped import Timestamped + +# Types that can be converted to/from JointState +JointStateConvertable: TypeAlias = dict[str, list[str] | list[float]] | LCMJointState + +_FIELDS = ("ts", "frame_id", "name", "position", "velocity", "effort") + + +def sec_nsec(ts): # type: ignore[no-untyped-def] + s = int(ts) + return [s, int((ts - s) * 1_000_000_000)] + + +def _fields_of(source: Any) -> tuple[Any, ...]: + """Pull the six JointState fields out of a dict, a JointState or an LCM message.""" + if isinstance(source, dict): + return ( + source.get("ts"), + source.get("frame_id", ""), + source.get("name"), + source.get("position"), + source.get("velocity"), + source.get("effort"), + ) + if isinstance(source, JointState): + return (source.ts, source.frame_id, *(list(getattr(source, f)) for f in _FIELDS[2:])) + return ( + source.header.stamp.sec + (source.header.stamp.nsec / 1_000_000_000), + source.header.frame_id, + *(list(getattr(source, f) or []) for f in _FIELDS[2:]), + ) + + +class JointState(Timestamped): + msg_name = "sensor_msgs.JointState" + ts: float + frame_id: str + name: list[str] + position: list[float] + velocity: list[float] + effort: list[float] + + def __init__( + self, + ts: float | JointStateConvertable | JointState | None = None, + frame_id: str = "", + name: list[str] | None = None, + position: list[float] | None = None, + velocity: list[float] | None = None, + effort: list[float] | None = None, + ) -> None: + """Initialize a JointState message. + + The first argument doubles as the source for the copy/dict/LCM forms: + ``JointState(other)``, ``JointState({...})``, ``JointState(lcm_msg)``. + + Args: + ts: Timestamp in seconds + frame_id: Frame ID for the message + name: List of joint names + position: List of joint positions (rad or m); gripper joints use + the unit their adapter declares + velocity: List of joint velocities (rad/s or m/s) + effort: List of joint efforts (Nm or N) + """ + stamp: Any = ts + if isinstance(stamp, dict | JointState | LCMJointState): + stamp, frame_id, name, position, velocity, effort = _fields_of(stamp) + + self.ts = time.time() if stamp is None else stamp + self.frame_id = frame_id + self.name = name if name is not None else [] + self.position = position if position is not None else [] + self.velocity = velocity if velocity is not None else [] + self.effort = effort if effort is not None else [] + + def lcm_encode(self) -> bytes: + lcm_msg = LCMJointState() + [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] + lcm_msg.header.frame_id = self.frame_id + lcm_msg.name_length = len(self.name) + lcm_msg.name = self.name + lcm_msg.position_length = len(self.position) + lcm_msg.position = self.position + lcm_msg.velocity_length = len(self.velocity) + lcm_msg.velocity = self.velocity + lcm_msg.effort_length = len(self.effort) + lcm_msg.effort = self.effort + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes) -> JointState: + lcm_msg = LCMJointState.lcm_decode(data) + return cls( + ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), + frame_id=lcm_msg.header.frame_id, + name=list(lcm_msg.name) if lcm_msg.name else [], + position=list(lcm_msg.position) if lcm_msg.position else [], + velocity=list(lcm_msg.velocity) if lcm_msg.velocity else [], + effort=list(lcm_msg.effort) if lcm_msg.effort else [], + ) + + def __str__(self) -> str: + return f"JointState({len(self.name)} joints, frame_id='{self.frame_id}')" + + def __repr__(self) -> str: + return ( + f"JointState(ts={self.ts}, frame_id='{self.frame_id}', " + f"name={self.name}, position={self.position}, " + f"velocity={self.velocity}, effort={self.effort})" + ) + + def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] + """Check if two JointState messages are equal.""" + if not isinstance(other, JointState): + return False + return ( + self.name == other.name + and self.position == other.position + and self.velocity == other.velocity + and self.effort == other.effort + and self.frame_id == other.frame_id + ) diff --git a/dimos/msgs/sensor_msgs/Joy.py b/dimos/msgs/sensor_msgs/Joy.py new file mode 100644 index 00000000000..9443770b67e --- /dev/null +++ b/dimos/msgs/sensor_msgs/Joy.py @@ -0,0 +1,130 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import time +from typing import Any, TypeAlias + +from dimos_lcm.sensor_msgs import Joy as LCMJoy + +from dimos.types.timestamped import Timestamped + +# Types that can be converted to/from Joy +JoyConvertable: TypeAlias = ( + tuple[list[float], list[int]] | dict[str, list[float] | list[int]] | LCMJoy +) + + +def sec_nsec(ts): # type: ignore[no-untyped-def] + s = int(ts) + return [s, int((ts - s) * 1_000_000_000)] + + +def _fields_of(source: Any) -> tuple[Any, ...]: + """Pull the four Joy fields out of a dict, an (axes, buttons) pair, a Joy or an LCM message.""" + if isinstance(source, dict): + return ( + source.get("ts"), + source.get("frame_id", ""), + source.get("axes"), + source.get("buttons"), + ) + if isinstance(source, tuple | list): + return (None, "", list(source[0]), list(source[1])) + if isinstance(source, Joy): + return (source.ts, source.frame_id, list(source.axes), list(source.buttons)) + return ( + source.header.stamp.sec + (source.header.stamp.nsec / 1_000_000_000), + source.header.frame_id, + list(source.axes), + list(source.buttons), + ) + + +class Joy(Timestamped): + msg_name = "sensor_msgs.Joy" + ts: float + frame_id: str + axes: list[float] + buttons: list[int] + + def __init__( + self, + ts: float | JoyConvertable | Joy | None = None, + frame_id: str = "", + axes: list[float] | None = None, + buttons: list[int] | None = None, + ) -> None: + """Initialize a Joy message. + + The first argument doubles as the source for the copy/dict/pair/LCM forms: + ``Joy(other)``, ``Joy({...})``, ``Joy((axes, buttons))``, ``Joy(lcm_msg)``. + + Args: + ts: Timestamp in seconds + frame_id: Frame ID for the message + axes: List of axis values (typically -1.0 to 1.0) + buttons: List of button states (0 or 1) + """ + stamp: Any = ts + if isinstance(stamp, dict | tuple | list | Joy | LCMJoy): + stamp, frame_id, axes, buttons = _fields_of(stamp) + + self.ts = time.time() if stamp is None else stamp + self.frame_id = frame_id + self.axes = axes if axes is not None else [] + self.buttons = buttons if buttons is not None else [] + + def lcm_encode(self) -> bytes: + lcm_msg = LCMJoy() + [lcm_msg.header.stamp.sec, lcm_msg.header.stamp.nsec] = sec_nsec(self.ts) # type: ignore[no-untyped-call] + lcm_msg.header.frame_id = self.frame_id + lcm_msg.axes_length = len(self.axes) + lcm_msg.axes = self.axes + lcm_msg.buttons_length = len(self.buttons) + lcm_msg.buttons = self.buttons + return lcm_msg.lcm_encode() # type: ignore[no-any-return] + + @classmethod + def lcm_decode(cls, data: bytes) -> Joy: + lcm_msg = LCMJoy.lcm_decode(data) + return cls( + ts=lcm_msg.header.stamp.sec + (lcm_msg.header.stamp.nsec / 1_000_000_000), + frame_id=lcm_msg.header.frame_id, + axes=list(lcm_msg.axes) if lcm_msg.axes else [], + buttons=list(lcm_msg.buttons) if lcm_msg.buttons else [], + ) + + def __str__(self) -> str: + return ( + f"Joy(axes={len(self.axes)} values, buttons={len(self.buttons)} values, " + f"frame_id='{self.frame_id}')" + ) + + def __repr__(self) -> str: + return ( + f"Joy(ts={self.ts}, frame_id='{self.frame_id}', " + f"axes={self.axes}, buttons={self.buttons})" + ) + + def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] + """Check if two Joy messages are equal.""" + if not isinstance(other, Joy): + return False + return ( + self.axes == other.axes + and self.buttons == other.buttons + and self.frame_id == other.frame_id + ) diff --git a/dimos/msgs/sensor_msgs/MotorCommandArray.py b/dimos/msgs/sensor_msgs/MotorCommandArray.py new file mode 100644 index 00000000000..577b03c7655 --- /dev/null +++ b/dimos/msgs/sensor_msgs/MotorCommandArray.py @@ -0,0 +1,133 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""LCM type for low-level motor commands: q, dq, kp, kd, tau per motor.""" + +from io import BytesIO +import struct +import time + + +class MotorCommandArray: + """Per-motor q/dq/kp/kd/tau. Joint order is implicit (caller-defined).""" + + msg_name = "sensor_msgs.MotorCommandArray" + + __slots__ = ["dq", "kd", "kp", "num_joints", "q", "tau", "timestamp"] + + def __init__( + self, + q: list[float] | None = None, + dq: list[float] | None = None, + kp: list[float] | None = None, + kd: list[float] | None = None, + tau: list[float] | None = None, + timestamp: float | None = None, + ) -> None: + if q is None: + q = [] + if timestamp is None: + timestamp = time.time() + + n = len(q) + if dq is None: + dq = [0.0] * n + if kp is None: + kp = [0.0] * n + if kd is None: + kd = [0.0] * n + if tau is None: + tau = [0.0] * n + + if not (len(dq) == len(kp) == len(kd) == len(tau) == n): + raise ValueError( + f"All arrays must have length {n}; got " + f"dq={len(dq)} kp={len(kp)} kd={len(kd)} tau={len(tau)}" + ) + + self.timestamp = timestamp + self.num_joints = n + self.q = list(q) + self.dq = list(dq) + self.kp = list(kp) + self.kd = list(kd) + self.tau = list(tau) + + def lcm_encode(self) -> bytes: + return self.encode() + + def encode(self) -> bytes: + buf = BytesIO() + buf.write(MotorCommandArray._get_packed_fingerprint()) + self._encode_one(buf) + return buf.getvalue() + + def _encode_one(self, buf: BytesIO) -> None: + buf.write(struct.pack(">d", self.timestamp)) + buf.write(struct.pack(">i", self.num_joints)) + for arr in (self.q, self.dq, self.kp, self.kd, self.tau): + for v in arr: + buf.write(struct.pack(">d", v)) + + @classmethod + def lcm_decode(cls, data: bytes) -> "MotorCommandArray": + return cls.decode(data) + + @classmethod + def decode(cls, data: bytes | BytesIO) -> "MotorCommandArray": + buf: BytesIO = data if isinstance(data, BytesIO) else BytesIO(data) + if buf.read(8) != cls._get_packed_fingerprint(): + raise ValueError("Decode error") + return cls._decode_one(buf) + + @classmethod + def _decode_one(cls, buf: BytesIO) -> "MotorCommandArray": + self = MotorCommandArray.__new__(MotorCommandArray) + self.timestamp = struct.unpack(">d", buf.read(8))[0] + self.num_joints = struct.unpack(">i", buf.read(4))[0] + n = self.num_joints + arrays = [] + for _ in range(5): + arrays.append([struct.unpack(">d", buf.read(8))[0] for _ in range(n)]) + self.q, self.dq, self.kp, self.kd, self.tau = arrays + return self + + @classmethod + def _get_hash_recursive(cls, parents: list[type]) -> int: + if cls in parents: + return 0 + # Distinct fingerprint from JointCommand (0x8A3D2E1C5F4B6A9D) + tmphash = (0x9B4E3F2D6A5C7B8E) & 0xFFFFFFFFFFFFFFFF + tmphash = (((tmphash << 1) & 0xFFFFFFFFFFFFFFFF) + (tmphash >> 63)) & 0xFFFFFFFFFFFFFFFF + return tmphash + + _packed_fingerprint: bytes | None = None + + @classmethod + def _get_packed_fingerprint(cls) -> bytes: + if cls._packed_fingerprint is None: + cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) + return cls._packed_fingerprint + + def get_hash(self) -> int: + return int(struct.unpack(">Q", MotorCommandArray._get_packed_fingerprint())[0]) + + def __str__(self) -> str: + return f"MotorCommandArray(timestamp={self.timestamp:.6f}, num_joints={self.num_joints})" + + def __repr__(self) -> str: + return ( + f"MotorCommandArray(q={self.q}, dq={self.dq}, kp={self.kp}, " + f"kd={self.kd}, tau={self.tau}, timestamp={self.timestamp})" + ) diff --git a/dimos/msgs/sensor_msgs/RobotState.py b/dimos/msgs/sensor_msgs/RobotState.py new file mode 100644 index 00000000000..20e41e7d248 --- /dev/null +++ b/dimos/msgs/sensor_msgs/RobotState.py @@ -0,0 +1,188 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""LCM type definitions +This file automatically generated by lcm. +DO NOT MODIFY BY HAND!!!! +""" + +from io import BytesIO +import struct + + +class RobotState: + msg_name = "sensor_msgs.RobotState" + + __slots__ = [ + "cmdnum", + "error_code", + "joints", + "mode", + "mt_able", + "mt_brake", + "state", + "tcp_offset", + "tcp_pose", + "warn_code", + ] + + __typenames__ = [ + "int32_t", + "int32_t", + "int32_t", + "int32_t", + "int32_t", + "int32_t", + "int32_t", + "float", + "float", + "float", + ] + + __dimensions__ = [None, None, None, None, None, None, None, None, None, None] + + def __init__( # type: ignore[no-untyped-def] + self, + state: int = 0, + mode: int = 0, + error_code: int = 0, + warn_code: int = 0, + cmdnum: int = 0, + mt_brake: int = 0, + mt_able: int = 0, + tcp_pose=None, + tcp_offset=None, + joints=None, + ) -> None: + # LCM Type: int32_t + self.state = state + # LCM Type: int32_t + self.mode = mode + # LCM Type: int32_t + self.error_code = error_code + # LCM Type: int32_t + self.warn_code = warn_code + # LCM Type: int32_t + self.cmdnum = cmdnum + # LCM Type: int32_t + self.mt_brake = mt_brake + # LCM Type: int32_t + self.mt_able = mt_able + # LCM Type: float[] - TCP pose [x, y, z, roll, pitch, yaw] + self.tcp_pose = tcp_pose if tcp_pose is not None else [] + # LCM Type: float[] - TCP offset [x, y, z, roll, pitch, yaw] + self.tcp_offset = tcp_offset if tcp_offset is not None else [] + # LCM Type: float[] - Joint positions (variable length based on robot DOF) + self.joints = joints if joints is not None else [] + + def lcm_encode(self): # type: ignore[no-untyped-def] + """Encode for LCM transport (dimos uses lcm_encode method name).""" + return self.encode() # type: ignore[no-untyped-call] + + def encode(self): # type: ignore[no-untyped-def] + buf = BytesIO() + buf.write(RobotState._get_packed_fingerprint()) # type: ignore[no-untyped-call] + self._encode_one(buf) + return buf.getvalue() + + def _encode_one(self, buf) -> None: # type: ignore[no-untyped-def] + buf.write( + struct.pack( + ">iiiiiii", + self.state, + self.mode, + self.error_code, + self.warn_code, + self.cmdnum, + self.mt_brake, + self.mt_able, + ) + ) + # Encode tcp_pose array + buf.write(struct.pack(">i", len(self.tcp_pose))) + for val in self.tcp_pose: + buf.write(struct.pack(">f", val)) + # Encode tcp_offset array + buf.write(struct.pack(">i", len(self.tcp_offset))) + for val in self.tcp_offset: + buf.write(struct.pack(">f", val)) + # Encode joints array + buf.write(struct.pack(">i", len(self.joints))) + for val in self.joints: + buf.write(struct.pack(">f", val)) + + @classmethod + def lcm_decode(cls, data: bytes): # type: ignore[no-untyped-def] + """Decode from LCM transport (dimos uses lcm_decode method name).""" + return cls.decode(data) + + @classmethod + def decode(cls, data: bytes): # type: ignore[no-untyped-def] + if hasattr(data, "read"): + buf = data + else: + buf = BytesIO(data) # type: ignore[assignment] + if buf.read(8) != cls._get_packed_fingerprint(): # type: ignore[no-untyped-call] + raise ValueError("Decode error") + return cls._decode_one(buf) # type: ignore[no-untyped-call] + + @classmethod + def _decode_one(cls, buf): # type: ignore[no-untyped-def] + self = RobotState() + ( + self.state, + self.mode, + self.error_code, + self.warn_code, + self.cmdnum, + self.mt_brake, + self.mt_able, + ) = struct.unpack(">iiiiiii", buf.read(28)) + # Decode tcp_pose array + tcp_pose_len = struct.unpack(">i", buf.read(4))[0] + self.tcp_pose = [] + for _ in range(tcp_pose_len): + self.tcp_pose.append(struct.unpack(">f", buf.read(4))[0]) + # Decode tcp_offset array + tcp_offset_len = struct.unpack(">i", buf.read(4))[0] + self.tcp_offset = [] + for _ in range(tcp_offset_len): + self.tcp_offset.append(struct.unpack(">f", buf.read(4))[0]) + # Decode joints array + joints_len = struct.unpack(">i", buf.read(4))[0] + self.joints = [] + for _ in range(joints_len): + self.joints.append(struct.unpack(">f", buf.read(4))[0]) + return self + + @classmethod + def _get_hash_recursive(cls, parents): # type: ignore[no-untyped-def] + if cls in parents: + return 0 + # Updated hash to reflect new fields: tcp_pose, tcp_offset, joints + tmphash = (0x8C3B9A1FE7D24E6A) & 0xFFFFFFFFFFFFFFFF + tmphash = (((tmphash << 1) & 0xFFFFFFFFFFFFFFFF) + (tmphash >> 63)) & 0xFFFFFFFFFFFFFFFF + return tmphash + + _packed_fingerprint = None + + @classmethod + def _get_packed_fingerprint(cls): # type: ignore[no-untyped-def] + if cls._packed_fingerprint is None: + cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) # type: ignore[no-untyped-call] + return cls._packed_fingerprint + + def get_hash(self): # type: ignore[no-untyped-def] + """Get the LCM hash of the struct""" + return struct.unpack(">Q", RobotState._get_packed_fingerprint())[0] # type: ignore[no-untyped-call] diff --git a/dimos/msgs/sensor_msgs/image_impls/AbstractImage.py b/dimos/msgs/sensor_msgs/image_impls/AbstractImage.py new file mode 100644 index 00000000000..3b901b874b8 --- /dev/null +++ b/dimos/msgs/sensor_msgs/image_impls/AbstractImage.py @@ -0,0 +1,17 @@ +# Copyright 2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Backwards compatibility stub for unpickling old data. +# AbstractImage and ImageFormat were moved to Image. +from dimos.msgs.sensor_msgs.Image import Image as AbstractImage, ImageFormat # noqa: F401 diff --git a/dimos/msgs/std_msgs/Bool.py b/dimos/msgs/std_msgs/Bool.py new file mode 100644 index 00000000000..4421447edfc --- /dev/null +++ b/dimos/msgs/std_msgs/Bool.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Bool message type.""" + +from dimos_lcm.std_msgs import Bool as LCMBool + + +class Bool(LCMBool): # type: ignore[misc] + """Bool message.""" + + msg_name = "std_msgs.Bool" + + def __init__(self, data: bool = False) -> None: + """Initialize Bool with data value.""" + self.data = data diff --git a/dimos/msgs/std_msgs/Float32.py b/dimos/msgs/std_msgs/Float32.py new file mode 100644 index 00000000000..f5a508d21c0 --- /dev/null +++ b/dimos/msgs/std_msgs/Float32.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Float32 message type.""" + +from typing import ClassVar + +from dimos_lcm.std_msgs import Float32 as LCMFloat32 + + +class Float32(LCMFloat32): # type: ignore[misc] + """Float32 message.""" + + msg_name: ClassVar[str] = "std_msgs.Float32" + + def __init__(self, data: float = 0.0) -> None: + """Initialize Float32 with data value.""" + self.data = data diff --git a/dimos/msgs/std_msgs/Header.py b/dimos/msgs/std_msgs/Header.py new file mode 100644 index 00000000000..5c542004972 --- /dev/null +++ b/dimos/msgs/std_msgs/Header.py @@ -0,0 +1,106 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from datetime import datetime +import time + +from dimos_lcm.std_msgs import Header as LCMHeader, Time as LCMTime +from plum import dispatch + +# Import the actual LCM header type that's returned from decoding +try: + from lcm_msgs.std_msgs.Header import ( # type: ignore[import-not-found] + Header as DecodedLCMHeader, + ) +except ImportError: + DecodedLCMHeader = None + + +class Header(LCMHeader): # type: ignore[misc] + msg_name = "std_msgs.Header" + ts: float + + @dispatch + def __init__(self) -> None: + """Initialize a Header with current time and empty frame_id.""" + self.ts = time.time() + sec = int(self.ts) + nsec = int((self.ts - sec) * 1_000_000_000) + super().__init__(seq=0, stamp=LCMTime(sec=sec, nsec=nsec), frame_id="") + + @dispatch # type: ignore[no-redef] + def __init__(self, frame_id: str) -> None: + """Initialize a Header with current time and specified frame_id.""" + self.ts = time.time() + sec = int(self.ts) + nsec = int((self.ts - sec) * 1_000_000_000) + super().__init__(seq=1, stamp=LCMTime(sec=sec, nsec=nsec), frame_id=frame_id) + + @dispatch # type: ignore[no-redef] + def __init__(self, timestamp: float, frame_id: str = "", seq: int = 1) -> None: + """Initialize a Header with Unix timestamp, frame_id, and optional seq.""" + sec = int(timestamp) + nsec = int((timestamp - sec) * 1_000_000_000) + super().__init__(seq=seq, stamp=LCMTime(sec=sec, nsec=nsec), frame_id=frame_id) + + @dispatch # type: ignore[no-redef] + def __init__(self, timestamp: datetime, frame_id: str = "") -> None: + """Initialize a Header with datetime object and frame_id.""" + self.ts = timestamp.timestamp() + sec = int(self.ts) + nsec = int((self.ts - sec) * 1_000_000_000) + super().__init__(seq=1, stamp=LCMTime(sec=sec, nsec=nsec), frame_id=frame_id) + + @dispatch # type: ignore[no-redef] + def __init__(self, seq: int, stamp: LCMTime, frame_id: str) -> None: + """Initialize with explicit seq, stamp, and frame_id (LCM compatibility).""" + super().__init__(seq=seq, stamp=stamp, frame_id=frame_id) + + @dispatch # type: ignore[no-redef] + def __init__(self, header: LCMHeader) -> None: + """Initialize from another Header (copy constructor).""" + super().__init__(seq=header.seq, stamp=header.stamp, frame_id=header.frame_id) + + @dispatch # type: ignore[no-redef] + def __init__(self, header: object) -> None: + """Initialize from a decoded LCM header object.""" + # Handle the case where we get an lcm_msgs.std_msgs.Header.Header object + if hasattr(header, "seq") and hasattr(header, "stamp") and hasattr(header, "frame_id"): + super().__init__(seq=header.seq, stamp=header.stamp, frame_id=header.frame_id) + else: + raise ValueError(f"Cannot create Header from {type(header)}") + + @classmethod + def now(cls, frame_id: str = "", seq: int = 1) -> Header: + """Create a Header with current timestamp.""" + ts = time.time() + return cls(ts, frame_id, seq) + + @property + def timestamp(self) -> float: + """Get timestamp as Unix time (float).""" + return self.stamp.sec + (self.stamp.nsec / 1_000_000_000) # type: ignore[no-any-return] + + @property + def datetime(self) -> datetime: + """Get timestamp as datetime object.""" + return datetime.fromtimestamp(self.timestamp) + + def __str__(self) -> str: + return f"Header(seq={self.seq}, time={self.timestamp:.6f}, frame_id='{self.frame_id}')" + + def __repr__(self) -> str: + return f"Header(seq={self.seq}, stamp=Time(sec={self.stamp.sec}, nsec={self.stamp.nsec}), frame_id='{self.frame_id}')" diff --git a/dimos/msgs/std_msgs/Int32.py b/dimos/msgs/std_msgs/Int32.py new file mode 100644 index 00000000000..ba4906f485d --- /dev/null +++ b/dimos/msgs/std_msgs/Int32.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Copyright 2025-2026 Dimensional Inc. + +"""Int32 message type.""" + +from typing import ClassVar + +from dimos_lcm.std_msgs import Int32 as LCMInt32 + + +class Int32(LCMInt32): # type: ignore[misc] + """ROS-compatible Int32 message.""" + + msg_name: ClassVar[str] = "std_msgs.Int32" + + def __init__(self, data: int = 0) -> None: + """Initialize Int32 with data value.""" + self.data = data diff --git a/dimos/msgs/std_msgs/Int8.py b/dimos/msgs/std_msgs/Int8.py new file mode 100644 index 00000000000..ca871403534 --- /dev/null +++ b/dimos/msgs/std_msgs/Int8.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Copyright 2025-2026 Dimensional Inc. + +"""Int32 message type.""" + +from typing import ClassVar + +from dimos_lcm.std_msgs import Int8 as LCMInt8 + + +class Int8(LCMInt8): # type: ignore[misc] + """Int8 message.""" + + msg_name: ClassVar[str] = "std_msgs.Int8" + + def __init__(self, data: int = 0) -> None: + """Initialize Int8 with data value.""" + self.data = data diff --git a/dimos/msgs/std_msgs/String.py b/dimos/msgs/std_msgs/String.py new file mode 100644 index 00000000000..ef48233dfd3 --- /dev/null +++ b/dimos/msgs/std_msgs/String.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""String message type.""" + +from typing import ClassVar + +from dimos_lcm.std_msgs import String as LCMString + + +class String(LCMString): # type: ignore[misc] + """ROS-compatible String message.""" + + msg_name: ClassVar[str] = "std_msgs.String" + + def __init__(self, data: str = "") -> None: + """Initialize String with data value.""" + self.data = data diff --git a/dimos/msgs/std_msgs/UInt32.py b/dimos/msgs/std_msgs/UInt32.py new file mode 100644 index 00000000000..e617c782fed --- /dev/null +++ b/dimos/msgs/std_msgs/UInt32.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""UInt32 message type.""" + +from typing import ClassVar + +from dimos_lcm.std_msgs import UInt32 as LCMUInt32 + + +class UInt32(LCMUInt32): # type: ignore[misc] + """ROS-compatible UInt32 message.""" + + msg_name: ClassVar[str] = "std_msgs.UInt32" + + def __init__(self, data: int = 0) -> None: + """Initialize UInt32 with data value.""" + self.data = data diff --git a/dimos/msgs/trajectory_msgs/JointTrajectory.py b/dimos/msgs/trajectory_msgs/JointTrajectory.py new file mode 100644 index 00000000000..ae2ad55fd1b --- /dev/null +++ b/dimos/msgs/trajectory_msgs/JointTrajectory.py @@ -0,0 +1,211 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +JointTrajectory message type. + +A sequence of joint trajectory points representing a full trajectory. +Similar to ROS trajectory_msgs/JointTrajectory. +""" + +from io import BytesIO +import struct +import time + +from dimos.msgs.trajectory_msgs.TrajectoryPoint import TrajectoryPoint + + +class JointTrajectory: + """ + A joint-space trajectory consisting of timestamped waypoints. + + Attributes: + timestamp: When trajectory was created (seconds since epoch) + joint_names: Names of joints (optional) + points: Sequence of TrajectoryPoints + duration: Total trajectory duration (seconds) + """ + + msg_name = "trajectory_msgs.JointTrajectory" + + __slots__ = ["duration", "joint_names", "num_joints", "num_points", "points", "timestamp"] + + def __init__( + self, + points: list[TrajectoryPoint] | None = None, + joint_names: list[str] | None = None, + timestamp: float | None = None, + ) -> None: + """ + Initialize JointTrajectory. + + Args: + points: List of TrajectoryPoints + joint_names: Names of joints (optional) + timestamp: Creation timestamp (defaults to now) + """ + self.timestamp = timestamp if timestamp is not None else time.time() + self.points = list(points) if points else [] + self.num_points = len(self.points) + self.joint_names = list(joint_names) if joint_names else [] + self.num_joints = ( + len(self.joint_names) + if self.joint_names + else (self.points[0].num_joints if self.points else 0) + ) + + # Compute duration from last point + if self.points: + self.duration = max(p.time_from_start for p in self.points) + else: + self.duration = 0.0 + + def sample(self, t: float) -> tuple[list[float], list[float]]: + """ + Sample the trajectory at time t using linear interpolation. + + Args: + t: Time from trajectory start (seconds) + + Returns: + Tuple of (positions, velocities) at time t + """ + if not self.points: + return [], [] + + # Clamp t to valid range + t = max(0.0, min(t, self.duration)) + + # Find bracketing points + if t <= self.points[0].time_from_start: + return list(self.points[0].positions), list(self.points[0].velocities) + + if t >= self.points[-1].time_from_start: + return list(self.points[-1].positions), list(self.points[-1].velocities) + + # Find interval + for i in range(len(self.points) - 1): + t0 = self.points[i].time_from_start + t1 = self.points[i + 1].time_from_start + + if t0 <= t <= t1: + # Linear interpolation + alpha = (t - t0) / (t1 - t0) if t1 > t0 else 0.0 + p0 = self.points[i] + p1 = self.points[i + 1] + + positions = [ + p0.positions[j] + alpha * (p1.positions[j] - p0.positions[j]) + for j in range(len(p0.positions)) + ] + velocities = [ + p0.velocities[j] + alpha * (p1.velocities[j] - p0.velocities[j]) + for j in range(len(p0.velocities)) + ] + return positions, velocities + + # Fallback + return list(self.points[-1].positions), list(self.points[-1].velocities) + + def lcm_encode(self) -> bytes: + """Encode for LCM transport.""" + return self.encode() + + def encode(self) -> bytes: + buf = BytesIO() + buf.write(JointTrajectory._get_packed_fingerprint()) + self._encode_one(buf) + return buf.getvalue() + + def _encode_one(self, buf: BytesIO) -> None: + # timestamp (double) + buf.write(struct.pack(">d", self.timestamp)) + # duration (double) + buf.write(struct.pack(">d", self.duration)) + # num_joint_names (int32) - actual count of joint names + buf.write(struct.pack(">i", len(self.joint_names))) + # joint_names (string[num_joint_names]) + for name in self.joint_names: + name_bytes = name.encode("utf-8") + buf.write(struct.pack(">i", len(name_bytes))) + buf.write(name_bytes) + # num_points (int32) + buf.write(struct.pack(">i", self.num_points)) + # points (TrajectoryPoint[num_points]) + for point in self.points: + point._encode_one(buf) + + @classmethod + def lcm_decode(cls, data: bytes) -> "JointTrajectory": + """Decode from LCM transport.""" + return cls.decode(data) + + @classmethod + def decode(cls, data: bytes) -> "JointTrajectory": + buf = BytesIO(data) if not hasattr(data, "read") else data + if buf.read(8) != cls._get_packed_fingerprint(): + raise ValueError("Decode error: fingerprint mismatch") + return cls._decode_one(buf) # type: ignore[arg-type] + + @classmethod + def _decode_one(cls, buf: BytesIO) -> "JointTrajectory": + self = cls.__new__(cls) + self.timestamp = struct.unpack(">d", buf.read(8))[0] + self.duration = struct.unpack(">d", buf.read(8))[0] + + # Read joint names + num_joint_names = struct.unpack(">i", buf.read(4))[0] + self.joint_names = [] + for _ in range(num_joint_names): + name_len = struct.unpack(">i", buf.read(4))[0] + self.joint_names.append(buf.read(name_len).decode("utf-8")) + + # Read points + self.num_points = struct.unpack(">i", buf.read(4))[0] + self.points = [TrajectoryPoint._decode_one(buf) for _ in range(self.num_points)] + + # Set num_joints from joint_names or points + self.num_joints = ( + len(self.joint_names) + if self.joint_names + else (self.points[0].num_joints if self.points else 0) + ) + + return self + + _packed_fingerprint = None + + @classmethod + def _get_hash_recursive(cls, parents): # type: ignore[no-untyped-def] + if cls in parents: + return 0 + return 0x2B3C4D5E6F708192 & 0xFFFFFFFFFFFFFFFF + + @classmethod + def _get_packed_fingerprint(cls) -> bytes: + if cls._packed_fingerprint is None: + cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) # type: ignore[no-untyped-call] + return cls._packed_fingerprint + + def __str__(self) -> str: + return f"JointTrajectory({self.num_points} points, duration={self.duration:.3f}s)" + + def __repr__(self) -> str: + return ( + f"JointTrajectory(points={self.points}, joint_names={self.joint_names}, " + f"timestamp={self.timestamp})" + ) + + def __len__(self) -> int: + return self.num_points diff --git a/dimos/msgs/trajectory_msgs/TrajectoryPoint.py b/dimos/msgs/trajectory_msgs/TrajectoryPoint.py new file mode 100644 index 00000000000..b2b9ab8406c --- /dev/null +++ b/dimos/msgs/trajectory_msgs/TrajectoryPoint.py @@ -0,0 +1,136 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +TrajectoryPoint message type. + +A single point in a joint trajectory with positions, velocities, and time. +Similar to ROS trajectory_msgs/JointTrajectoryPoint. +""" + +from io import BytesIO +import struct + + +class TrajectoryPoint: + """ + A single point in a joint trajectory. + + Attributes: + time_from_start: Time from trajectory start (seconds) + positions: Joint positions (radians) + velocities: Joint velocities (rad/s) + """ + + msg_name = "trajectory_msgs.TrajectoryPoint" + + __slots__ = ["num_joints", "positions", "time_from_start", "velocities"] + + def __init__( + self, + time_from_start: float = 0.0, + positions: list[float] | None = None, + velocities: list[float] | None = None, + ) -> None: + """ + Initialize TrajectoryPoint. + + Args: + time_from_start: Time from trajectory start (seconds) + positions: Joint positions (radians) + velocities: Joint velocities (rad/s), defaults to zeros if None + """ + self.time_from_start = time_from_start + self.positions = list(positions) if positions else [] + self.num_joints = len(self.positions) + + if velocities is not None: + self.velocities = list(velocities) + else: + self.velocities = [0.0] * self.num_joints + + def lcm_encode(self) -> bytes: + """Encode for LCM transport.""" + return self.encode() + + def encode(self) -> bytes: + buf = BytesIO() + buf.write(TrajectoryPoint._get_packed_fingerprint()) + self._encode_one(buf) + return buf.getvalue() + + def _encode_one(self, buf: BytesIO) -> None: + # time_from_start (double) + buf.write(struct.pack(">d", self.time_from_start)) + # num_joints (int32) + buf.write(struct.pack(">i", self.num_joints)) + # positions (double[num_joints]) + for p in self.positions: + buf.write(struct.pack(">d", p)) + # velocities (double[num_joints]) + for v in self.velocities: + buf.write(struct.pack(">d", v)) + + @classmethod + def lcm_decode(cls, data: bytes) -> "TrajectoryPoint": + """Decode from LCM transport.""" + return cls.decode(data) + + @classmethod + def decode(cls, data: bytes) -> "TrajectoryPoint": + buf = BytesIO(data) if not hasattr(data, "read") else data + if buf.read(8) != cls._get_packed_fingerprint(): + raise ValueError("Decode error: fingerprint mismatch") + return cls._decode_one(buf) # type: ignore[arg-type] + + @classmethod + def _decode_one(cls, buf: BytesIO) -> "TrajectoryPoint": + self = cls.__new__(cls) + self.time_from_start = struct.unpack(">d", buf.read(8))[0] + self.num_joints = struct.unpack(">i", buf.read(4))[0] + self.positions = [struct.unpack(">d", buf.read(8))[0] for _ in range(self.num_joints)] + self.velocities = [struct.unpack(">d", buf.read(8))[0] for _ in range(self.num_joints)] + return self + + _packed_fingerprint = None + + @classmethod + def _get_hash_recursive(cls, parents): # type: ignore[no-untyped-def] + if cls in parents: + return 0 + return 0x1A2B3C4D5E6F7081 & 0xFFFFFFFFFFFFFFFF + + @classmethod + def _get_packed_fingerprint(cls) -> bytes: + if cls._packed_fingerprint is None: + cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) # type: ignore[no-untyped-call] + return cls._packed_fingerprint + + def __str__(self) -> str: + return f"TrajectoryPoint(t={self.time_from_start:.3f}s, {self.num_joints} joints)" + + def __repr__(self) -> str: + return ( + f"TrajectoryPoint(time_from_start={self.time_from_start}, " + f"positions={self.positions}, velocities={self.velocities})" + ) + + def __eq__(self, other) -> bool: # type: ignore[no-untyped-def] + if not isinstance(other, TrajectoryPoint): + return False + return ( + self.time_from_start == other.time_from_start + and self.positions == other.positions + and self.velocities == other.velocities + ) diff --git a/dimos/msgs/trajectory_msgs/TrajectoryStatus.py b/dimos/msgs/trajectory_msgs/TrajectoryStatus.py new file mode 100644 index 00000000000..0a3c117e685 --- /dev/null +++ b/dimos/msgs/trajectory_msgs/TrajectoryStatus.py @@ -0,0 +1,170 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +TrajectoryStatus message type. + +Status feedback for trajectory execution. +""" + +from enum import IntEnum +from io import BytesIO +import struct +import time + + +class TrajectoryState(IntEnum): + """States for trajectory execution.""" + + IDLE = 0 # No trajectory, ready to accept + EXECUTING = 1 # Currently executing trajectory + COMPLETED = 2 # Trajectory finished successfully + ABORTED = 3 # Trajectory was cancelled + FAULT = 4 # Error occurred, requires reset() + + +class TrajectoryStatus: + """ + Status of trajectory execution. + + Attributes: + timestamp: When status was generated + state: Current TrajectoryState + progress: Progress 0.0 to 1.0 + time_elapsed: Seconds since trajectory start + time_remaining: Estimated seconds remaining + error: Error message if FAULT state (empty string otherwise) + """ + + msg_name = "trajectory_msgs.TrajectoryStatus" + + __slots__ = ["error", "progress", "state", "time_elapsed", "time_remaining", "timestamp"] + + def __init__( + self, + state: TrajectoryState = TrajectoryState.IDLE, + progress: float = 0.0, + time_elapsed: float = 0.0, + time_remaining: float = 0.0, + error: str = "", + timestamp: float | None = None, + ) -> None: + """ + Initialize TrajectoryStatus. + + Args: + state: Current execution state + progress: Progress through trajectory (0.0 to 1.0) + time_elapsed: Time since trajectory start (seconds) + time_remaining: Estimated time remaining (seconds) + error: Error message if in FAULT state + timestamp: When status was generated (defaults to now) + """ + self.timestamp = timestamp if timestamp is not None else time.time() + self.state = state + self.progress = progress + self.time_elapsed = time_elapsed + self.time_remaining = time_remaining + self.error = error + + @property + def state_name(self) -> str: + """Get human-readable state name.""" + return self.state.name + + def is_done(self) -> bool: + """Check if trajectory execution is finished (completed, aborted, or fault).""" + return self.state in ( + TrajectoryState.COMPLETED, + TrajectoryState.ABORTED, + TrajectoryState.FAULT, + ) + + def is_active(self) -> bool: + """Check if trajectory is currently executing.""" + return self.state == TrajectoryState.EXECUTING + + def lcm_encode(self) -> bytes: + """Encode for LCM transport.""" + return self.encode() + + def encode(self) -> bytes: + buf = BytesIO() + buf.write(TrajectoryStatus._get_packed_fingerprint()) + self._encode_one(buf) + return buf.getvalue() + + def _encode_one(self, buf: BytesIO) -> None: + # timestamp (double) + buf.write(struct.pack(">d", self.timestamp)) + # state (int32) + buf.write(struct.pack(">i", int(self.state))) + # progress (double) + buf.write(struct.pack(">d", self.progress)) + # time_elapsed (double) + buf.write(struct.pack(">d", self.time_elapsed)) + # time_remaining (double) + buf.write(struct.pack(">d", self.time_remaining)) + # error (string) + error_bytes = self.error.encode("utf-8") + buf.write(struct.pack(">i", len(error_bytes))) + buf.write(error_bytes) + + @classmethod + def lcm_decode(cls, data: bytes) -> "TrajectoryStatus": + """Decode from LCM transport.""" + return cls.decode(data) + + @classmethod + def decode(cls, data: bytes) -> "TrajectoryStatus": + buf = BytesIO(data) if not hasattr(data, "read") else data + if buf.read(8) != cls._get_packed_fingerprint(): + raise ValueError("Decode error: fingerprint mismatch") + return cls._decode_one(buf) # type: ignore[arg-type] + + @classmethod + def _decode_one(cls, buf: BytesIO) -> "TrajectoryStatus": + self = cls.__new__(cls) + self.timestamp = struct.unpack(">d", buf.read(8))[0] + self.state = TrajectoryState(struct.unpack(">i", buf.read(4))[0]) + self.progress = struct.unpack(">d", buf.read(8))[0] + self.time_elapsed = struct.unpack(">d", buf.read(8))[0] + self.time_remaining = struct.unpack(">d", buf.read(8))[0] + error_len = struct.unpack(">i", buf.read(4))[0] + self.error = buf.read(error_len).decode("utf-8") + return self + + _packed_fingerprint = None + + @classmethod + def _get_hash_recursive(cls, parents): # type: ignore[no-untyped-def] + if cls in parents: + return 0 + return 0x3C4D5E6F708192A3 & 0xFFFFFFFFFFFFFFFF + + @classmethod + def _get_packed_fingerprint(cls) -> bytes: + if cls._packed_fingerprint is None: + cls._packed_fingerprint = struct.pack(">Q", cls._get_hash_recursive([])) # type: ignore[no-untyped-call] + return cls._packed_fingerprint + + def __str__(self) -> str: + return f"TrajectoryStatus({self.state_name}, progress={self.progress:.1%})" + + def __repr__(self) -> str: + return ( + f"TrajectoryStatus(state={self.state_name}, progress={self.progress}, " + f"time_elapsed={self.time_elapsed}, time_remaining={self.time_remaining}, " + f"error='{self.error}')" + ) diff --git a/dimos/msgs/vision_msgs/BoundingBox2DArray.py b/dimos/msgs/vision_msgs/BoundingBox2DArray.py new file mode 100644 index 00000000000..f376de6372a --- /dev/null +++ b/dimos/msgs/vision_msgs/BoundingBox2DArray.py @@ -0,0 +1,21 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dimos_lcm.vision_msgs.BoundingBox2DArray import ( + BoundingBox2DArray as LCMBoundingBox2DArray, +) + + +class BoundingBox2DArray(LCMBoundingBox2DArray): # type: ignore[misc] + msg_name = "vision_msgs.BoundingBox2DArray" diff --git a/dimos/msgs/vision_msgs/BoundingBox3DArray.py b/dimos/msgs/vision_msgs/BoundingBox3DArray.py new file mode 100644 index 00000000000..d8d7775f919 --- /dev/null +++ b/dimos/msgs/vision_msgs/BoundingBox3DArray.py @@ -0,0 +1,21 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dimos_lcm.vision_msgs.BoundingBox3DArray import ( + BoundingBox3DArray as LCMBoundingBox3DArray, +) + + +class BoundingBox3DArray(LCMBoundingBox3DArray): # type: ignore[misc] + msg_name = "vision_msgs.BoundingBox3DArray" diff --git a/dimos/msgs/vision_msgs/Detection2D.py b/dimos/msgs/vision_msgs/Detection2D.py new file mode 100644 index 00000000000..aa957f80614 --- /dev/null +++ b/dimos/msgs/vision_msgs/Detection2D.py @@ -0,0 +1,27 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from dimos_lcm.vision_msgs.Detection2D import Detection2D as LCMDetection2D + +from dimos.types.timestamped import to_timestamp + + +class Detection2D(LCMDetection2D): # type: ignore[misc] + msg_name = "vision_msgs.Detection2D" + + # for _get_field_type() to work when decoding in _decode_one() + __annotations__ = LCMDetection2D.__annotations__ + + @property + def ts(self) -> float: + return to_timestamp(self.header.stamp) diff --git a/dimos/msgs/vision_msgs/Detection3D.py b/dimos/msgs/vision_msgs/Detection3D.py new file mode 100644 index 00000000000..76a838041a4 --- /dev/null +++ b/dimos/msgs/vision_msgs/Detection3D.py @@ -0,0 +1,31 @@ +# Copyright 2025-2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from dimos_lcm.vision_msgs.Detection3D import Detection3D as LCMDetection3D + +from dimos.types.timestamped import to_timestamp + + +class Detection3D(LCMDetection3D): # type: ignore[misc] + msg_name = "vision_msgs.Detection3D" + + # for _get_field_type() to work when decoding in _decode_one() + __annotations__ = LCMDetection3D.__annotations__ + + @property + def ts(self) -> float: + return to_timestamp(self.header.stamp) + + @property + def frame_id(self) -> str: + return str(self.header.frame_id) diff --git a/dimos/msgs/visualization_msgs/EntityMarkers.py b/dimos/msgs/visualization_msgs/EntityMarkers.py new file mode 100644 index 00000000000..86ba74d72e9 --- /dev/null +++ b/dimos/msgs/visualization_msgs/EntityMarkers.py @@ -0,0 +1,145 @@ +# Copyright 2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Labeled 3D entity markers for Rerun visualization. + +Published by modules that track entities in world coordinates. +The Rerun bridge picks these up via ``to_rerun()`` and renders them +as labeled colored points overlaid on the 3D scene. +""" + +from __future__ import annotations + +from dataclasses import dataclass +from io import BytesIO +import json +import struct +import time +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from rerun._baseclasses import Archetype + +from dimos.types.timestamped import Timestamped + +# Entity type → RGBA color +TYPE_COLORS: dict[str, tuple[int, int, int, int]] = { + "person": (255, 100, 100, 255), + "object": (100, 255, 100, 255), + "location": (100, 100, 255, 255), +} +DEFAULT_COLOR = (200, 200, 200, 255) + + +@dataclass +class Marker: + """A single entity marker in world coordinates.""" + + entity_id: str + label: str + entity_type: str # person | object | location + x: float + y: float + z: float + + +class EntityMarkers(Timestamped): + """A batch of labeled 3D entity markers. + + Wire format: JSON-encoded list of markers over LCM string channel. + Rerun: ``rr.Points3D`` with per-point labels and colors. + """ + + msg_name = "visualization_msgs.EntityMarkers" + + def __init__( + self, + markers: list[Marker] | None = None, + ts: float | None = None, + ) -> None: + self.markers: list[Marker] = markers or [] + self.ts: float = ts or time.time() + + # -- LCM serialization (JSON payload) -- + + def _encode_one(self, buf: BytesIO) -> None: + payload = json.dumps( + [ + { + "id": m.entity_id, + "label": m.label, + "type": m.entity_type, + "x": m.x, + "y": m.y, + "z": m.z, + } + for m in self.markers + ] + ).encode() + buf.write(struct.pack(">I", len(payload))) + buf.write(payload) + + def encode(self) -> bytes: + buf = BytesIO() + self._encode_one(buf) + return buf.getvalue() + + @classmethod + def _decode_one(cls, buf: BytesIO) -> EntityMarkers: + (length,) = struct.unpack(">I", buf.read(4)) + payload = json.loads(buf.read(length).decode()) + markers = [ + Marker( + entity_id=m["id"], + label=m["label"], + entity_type=m["type"], + x=m["x"], + y=m["y"], + z=m["z"], + ) + for m in payload + ] + return cls(markers=markers) + + @classmethod + def decode(cls, data: bytes) -> EntityMarkers: + return cls._decode_one(BytesIO(data)) + + # -- Rerun conversion -- + + def to_rerun(self) -> Archetype: + import rerun as rr + + if not self.markers: + return rr.Points3D([]) + + positions = [[m.x, m.y, m.z] for m in self.markers] + labels = [f"{m.entity_id}: {m.label[:40]}" for m in self.markers] + colors = [TYPE_COLORS.get(m.entity_type, DEFAULT_COLOR) for m in self.markers] + + return rr.Points3D( + positions=positions, + labels=labels, + colors=colors, + radii=[0.15] * len(self.markers), + ) + + # -- LCM compat (so autoconnect assigns LCMTransport, not pLCM) -- + + def lcm_encode(self) -> bytes: + return self.encode() + + @classmethod + def lcm_decode(cls, data: bytes, **kwargs: object) -> EntityMarkers: + return cls.decode(data) From 62eb1602621959b318dbb341b0f94aaa3100801d Mon Sep 17 00:00:00 2001 From: cc Date: Fri, 9 Oct 2026 11:43:45 -0700 Subject: [PATCH 03/11] refactor: use native message libraries and source builds --- dimos/message_codegen/native_sources.json | 281 ++ dimos/message_codegen/py.typed | 0 .../templates/native-support.cmake | 61 + .../message_codegen/test_native_libraries.py | 259 ++ .../src/dimos_generated/_types.pyi | 3141 +++++++++++++++++ .../builtin_interfaces/msg/__init__.pyi | 3 + .../dimos_msgs/msg/__init__.pyi | 15 + .../foxglove_msgs/msg/__init__.pyi | 2 + .../geometry_msgs/msg/__init__.pyi | 34 + .../dimos_generated/nav_msgs/msg/__init__.pyi | 9 + .../sensor_msgs/msg/__init__.pyi | 28 + .../shape_msgs/msg/__init__.pyi | 5 + .../dimos_generated/std_msgs/msg/__init__.pyi | 31 + .../dimos_generated/tf2_msgs/msg/__init__.pyi | 3 + .../trajectory_msgs/msg/__init__.pyi | 5 + .../vision_msgs/msg/__init__.pyi | 17 + .../visualization_msgs/msg/__init__.pyi | 13 + .../cpp/builtin_interfaces/CMakeLists.txt | 12 + .../cpp/builtin_interfaces/package.xml | 1 + .../package/cpp/dimos_msgs/CMakeLists.txt | 16 + .../package/cpp/dimos_msgs/package.xml | 1 + .../package/cpp/foxglove_msgs/CMakeLists.txt | 13 + .../package/cpp/foxglove_msgs/package.xml | 1 + .../package/cpp/geometry_msgs/CMakeLists.txt | 13 + .../package/cpp/geometry_msgs/package.xml | 1 + .../package/cpp/nav_msgs/CMakeLists.txt | 15 + .../package/cpp/nav_msgs/package.xml | 1 + .../package/cpp/packages.json | 1 + .../package/cpp/sensor_msgs/CMakeLists.txt | 15 + .../package/cpp/sensor_msgs/package.xml | 1 + .../package/cpp/shape_msgs/CMakeLists.txt | 13 + .../package/cpp/shape_msgs/package.xml | 1 + .../package/cpp/std_msgs/CMakeLists.txt | 13 + .../package/cpp/std_msgs/msg/Empty.msg | 0 .../package/cpp/std_msgs/package.xml | 1 + .../package/cpp/tf2_msgs/CMakeLists.txt | 13 + .../package/cpp/tf2_msgs/package.xml | 1 + .../cpp/trajectory_msgs/CMakeLists.txt | 15 + .../package/cpp/trajectory_msgs/package.xml | 1 + .../package/cpp/vision_msgs/CMakeLists.txt | 14 + .../package/cpp/vision_msgs/package.xml | 1 + .../cpp/visualization_msgs/CMakeLists.txt | 16 + .../cpp/visualization_msgs/package.xml | 1 + setup.py | 16 + 44 files changed, 4104 insertions(+) create mode 100644 dimos/message_codegen/native_sources.json create mode 100644 dimos/message_codegen/py.typed create mode 100644 dimos/message_codegen/templates/native-support.cmake create mode 100644 dimos/message_codegen/test_native_libraries.py create mode 100644 packages/dimos-generated/src/dimos_generated/_types.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/package.xml create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/package.xml create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/package.xml create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/package.xml create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/package.xml create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/package.xml create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/package.xml create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/msg/Empty.msg create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/package.xml create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/package.xml create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/package.xml create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/package.xml create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/CMakeLists.txt create mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/package.xml diff --git a/dimos/message_codegen/native_sources.json b/dimos/message_codegen/native_sources.json new file mode 100644 index 00000000000..5f8f498f348 --- /dev/null +++ b/dimos/message_codegen/native_sources.json @@ -0,0 +1,281 @@ +{ + "repositories": { + "ament_package": { + "url": "https://github.com/ament/ament_package.git", + "revision": "ee3c5eda4fbc4df2c7a135d0ac1385e4a53fa0ee" + }, + "ament_cmake": { + "url": "https://github.com/ament/ament_cmake.git", + "revision": "5741cff5b9f83253bf3521bd8f44108fde3504ad" + }, + "ament_cmake_ros": { + "url": "https://github.com/ros2/ament_cmake_ros.git", + "revision": "5b77a227b940a25be5224d78d37591c8baccd756" + }, + "rcutils": { + "url": "https://github.com/ros2/rcutils.git", + "revision": "26413034bab69688475f230ea7723e534ec3f8cd" + }, + "rmw": { + "url": "https://github.com/ros2/rmw.git", + "revision": "8cb94a87cf3f4049abe2d563af893517bf336930" + }, + "rosidl_dynamic_typesupport": { + "url": "https://github.com/ros2/rosidl_dynamic_typesupport.git", + "revision": "cb8c54d12c678daa70410bb0626ed8626f561e45" + }, + "ament_index": { + "url": "https://github.com/ament/ament_index.git", + "revision": "2ccdcb8fd19a364fc793273b5793459207a440b9" + }, + "rosidl": { + "url": "https://github.com/ros2/rosidl.git", + "revision": "85fa592b698b0f665e3120f48fac0d35e2f7d8a4" + }, + "rosidl_typesupport_fastrtps": { + "url": "https://github.com/ros2/rosidl_typesupport_fastrtps.git", + "revision": "b883555055cce17982a22172a42ef557ef40bac5" + } + }, + "packages": [ + { + "name": "ament_package", + "repository": "ament_package", + "directory": ".", + "python": true + }, + { + "name": "ament_cmake_core", + "repository": "ament_cmake", + "directory": "ament_cmake_core", + "python": false + }, + { + "name": "ament_cmake_libraries", + "repository": "ament_cmake", + "directory": "ament_cmake_libraries", + "python": false + }, + { + "name": "ament_cmake_export_dependencies", + "repository": "ament_cmake", + "directory": "ament_cmake_export_dependencies", + "python": false + }, + { + "name": "ament_cmake_export_definitions", + "repository": "ament_cmake", + "directory": "ament_cmake_export_definitions", + "python": false + }, + { + "name": "ament_cmake_export_include_directories", + "repository": "ament_cmake", + "directory": "ament_cmake_export_include_directories", + "python": false + }, + { + "name": "ament_cmake_export_libraries", + "repository": "ament_cmake", + "directory": "ament_cmake_export_libraries", + "python": false + }, + { + "name": "ament_cmake_export_interfaces", + "repository": "ament_cmake", + "directory": "ament_cmake_export_interfaces", + "python": false + }, + { + "name": "ament_cmake_export_link_flags", + "repository": "ament_cmake", + "directory": "ament_cmake_export_link_flags", + "python": false + }, + { + "name": "ament_cmake_export_targets", + "repository": "ament_cmake", + "directory": "ament_cmake_export_targets", + "python": false + }, + { + "name": "ament_cmake_gen_version_h", + "repository": "ament_cmake", + "directory": "ament_cmake_gen_version_h", + "python": false + }, + { + "name": "ament_cmake_python", + "repository": "ament_cmake", + "directory": "ament_cmake_python", + "python": false + }, + { + "name": "ament_cmake_include_directories", + "repository": "ament_cmake", + "directory": "ament_cmake_include_directories", + "python": false + }, + { + "name": "ament_cmake_target_dependencies", + "repository": "ament_cmake", + "directory": "ament_cmake_target_dependencies", + "python": false + }, + { + "name": "ament_cmake_test", + "repository": "ament_cmake", + "directory": "ament_cmake_test", + "python": false + }, + { + "name": "ament_cmake_version", + "repository": "ament_cmake", + "directory": "ament_cmake_version", + "python": false + }, + { + "name": "ament_cmake", + "repository": "ament_cmake", + "directory": "ament_cmake", + "python": false + }, + { + "name": "rosidl_cli", + "repository": "rosidl", + "directory": "rosidl_cli", + "python": true + }, + { + "name": "rosidl_adapter", + "repository": "rosidl", + "directory": "rosidl_adapter", + "python": false + }, + { + "name": "rosidl_parser", + "repository": "rosidl", + "directory": "rosidl_parser", + "python": false + }, + { + "name": "rosidl_pycommon", + "repository": "rosidl", + "directory": "rosidl_pycommon", + "python": true + }, + { + "name": "rosidl_cmake", + "repository": "rosidl", + "directory": "rosidl_cmake", + "python": false + }, + { + "name": "ament_cmake_gtest", + "repository": "ament_cmake", + "directory": "ament_cmake_gtest", + "python": false + }, + { + "name": "ament_cmake_gmock", + "repository": "ament_cmake", + "directory": "ament_cmake_gmock", + "python": false + }, + { + "name": "ament_cmake_pytest", + "repository": "ament_cmake", + "directory": "ament_cmake_pytest", + "python": false + }, + { + "name": "domain_coordinator", + "repository": "ament_cmake_ros", + "directory": "domain_coordinator", + "python": true + }, + { + "name": "ament_cmake_ros", + "repository": "ament_cmake_ros", + "directory": "ament_cmake_ros", + "python": false + }, + { + "name": "ament_index_python", + "repository": "ament_index", + "directory": "ament_index_python", + "python": true + }, + { + "name": "rosidl_generator_type_description", + "repository": "rosidl", + "directory": "rosidl_generator_type_description", + "python": false + }, + { + "name": "rosidl_typesupport_interface", + "repository": "rosidl", + "directory": "rosidl_typesupport_interface", + "python": false + }, + { + "name": "rcutils", + "repository": "rcutils", + "directory": ".", + "python": false + }, + { + "name": "rosidl_generator_c", + "repository": "rosidl", + "directory": "rosidl_generator_c", + "python": false + }, + { + "name": "rosidl_runtime_c", + "repository": "rosidl", + "directory": "rosidl_runtime_c", + "python": false + }, + { + "name": "rosidl_runtime_cpp", + "repository": "rosidl", + "directory": "rosidl_runtime_cpp", + "python": false + }, + { + "name": "rosidl_generator_cpp", + "repository": "rosidl", + "directory": "rosidl_generator_cpp", + "python": false + }, + { + "name": "fastrtps_cmake_module", + "repository": "rosidl_typesupport_fastrtps", + "directory": "fastrtps_cmake_module", + "python": false + }, + { + "name": "rosidl_dynamic_typesupport", + "repository": "rosidl_dynamic_typesupport", + "directory": ".", + "python": false + }, + { + "name": "rmw", + "repository": "rmw", + "directory": "rmw", + "python": false + }, + { + "name": "rosidl_typesupport_fastrtps_cpp", + "repository": "rosidl_typesupport_fastrtps", + "directory": "rosidl_typesupport_fastrtps_cpp", + "python": false + } + ], + "fastcdr": { + "url": "https://github.com/eProsima/Fast-CDR/archive/refs/tags/v2.4.0.tar.gz", + "sha256": "79d8466107dd6b7d1defe961c4aa31735038937cf9dd1175cf6b0da0df2209ab", + "version": "2.4.0" + } +} diff --git a/dimos/message_codegen/py.typed b/dimos/message_codegen/py.typed new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dimos/message_codegen/templates/native-support.cmake b/dimos/message_codegen/templates/native-support.cmake new file mode 100644 index 00000000000..c507cd6e37d --- /dev/null +++ b/dimos/message_codegen/templates/native-support.cmake @@ -0,0 +1,61 @@ +# Copyright 2026 Dimensional Inc. +# SPDX-License-Identifier: Apache-2.0 +cmake_minimum_required(VERSION 3.20) +project(dimos_native_dependencies NONE) +include(FetchContent) +include(ExternalProject) +find_package(Python3 REQUIRED COMPONENTS Interpreter) +if(NOT DIMOS_SUPPORT_PREFIX) + set(DIMOS_SUPPORT_PREFIX "${CMAKE_BINARY_DIR}/install") +endif() +set(_python_path "${DIMOS_SUPPORT_PREFIX}/lib/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}/site-packages") +set(_environment "PYTHONPATH=${_python_path}" "AMENT_PREFIX_PATH=${DIMOS_SUPPORT_PREFIX}" "CMAKE_PREFIX_PATH=${DIMOS_SUPPORT_PREFIX}") +file(READ "${CMAKE_CURRENT_LIST_DIR}/native_sources.json" _lock) +string(JSON _count LENGTH "${_lock}" repositories) +math(EXPR _last "${_count}-1") +foreach(_i RANGE ${_last}) + string(JSON _name MEMBER "${_lock}" repositories ${_i}) + string(JSON _url GET "${_lock}" repositories ${_name} url) + string(JSON _revision GET "${_lock}" repositories ${_name} revision) + FetchContent_Declare(${_name} GIT_REPOSITORY "${_url}" GIT_TAG "${_revision}" + SOURCE_SUBDIR _dimos_fetch_sources_only) + FetchContent_MakeAvailable(${_name}) +endforeach() +string(JSON _url GET "${_lock}" fastcdr url) +string(JSON _hash GET "${_lock}" fastcdr sha256) +FetchContent_Declare(fastcdr URL "${_url}" URL_HASH "SHA256=${_hash}" SOURCE_SUBDIR _dimos_fetch_sources_only) +FetchContent_MakeAvailable(fastcdr) +ExternalProject_Add(support_fastcdr SOURCE_DIR "${fastcdr_SOURCE_DIR}" DOWNLOAD_COMMAND "" + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${DIMOS_SUPPORT_PREFIX} -DBUILD_TESTING=OFF + -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_RPATH=$ORIGIN) +set(_previous support_fastcdr) +string(JSON _count LENGTH "${_lock}" packages) +math(EXPR _last "${_count}-1") +foreach(_i RANGE ${_last}) + string(JSON _name GET "${_lock}" packages ${_i} name) + string(JSON _repository GET "${_lock}" packages ${_i} repository) + string(JSON _directory GET "${_lock}" packages ${_i} directory) + string(JSON _python GET "${_lock}" packages ${_i} python) + set(_source "${${_repository}_SOURCE_DIR}/${_directory}") + if(_python) + ExternalProject_Add(support_${_name} SOURCE_DIR "${_source}" DOWNLOAD_COMMAND "" + CONFIGURE_COMMAND "" BUILD_COMMAND "" + INSTALL_COMMAND "${CMAKE_COMMAND}" -E env ${_environment} + "${Python3_EXECUTABLE}" -m pip install --no-deps --no-build-isolation + --prefix "${DIMOS_SUPPORT_PREFIX}" "" + DEPENDS ${_previous}) + else() + ExternalProject_Add(support_${_name} SOURCE_DIR "${_source}" DOWNLOAD_COMMAND "" + CONFIGURE_COMMAND "${CMAKE_COMMAND}" -E env ${_environment} + "${CMAKE_COMMAND}" -S "" -B "" + -DCMAKE_INSTALL_PREFIX=${DIMOS_SUPPORT_PREFIX} + -DCMAKE_PREFIX_PATH=${DIMOS_SUPPORT_PREFIX} + -DPython3_EXECUTABLE=${Python3_EXECUTABLE} + -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release + -DCMAKE_INSTALL_RPATH=$ORIGIN + BUILD_COMMAND "${CMAKE_COMMAND}" -E env ${_environment} "${CMAKE_COMMAND}" --build "" --parallel 2 + INSTALL_COMMAND "${CMAKE_COMMAND}" -E env ${_environment} "${CMAKE_COMMAND}" --install "" + DEPENDS ${_previous}) + endif() + set(_previous support_${_name}) +endforeach() diff --git a/dimos/message_codegen/test_native_libraries.py b/dimos/message_codegen/test_native_libraries.py new file mode 100644 index 00000000000..9771af35936 --- /dev/null +++ b/dimos/message_codegen/test_native_libraries.py @@ -0,0 +1,259 @@ +# Copyright 2026 Dimensional Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Acceptance of native library identities and explicit unsupported semantics.""" + +import json +from pathlib import Path +import pickle +import subprocess +import sys + +import numpy as np +import pytest + +from dimos.message_codegen import native_build, registry +from dimos.message_codegen.generate import generate +from dimos.message_codegen.native_build import complete, save_complete, source_digest, stage_module +from dimos.message_codegen.project import Project, prepare + + +@pytest.fixture +def frozen_registry(monkeypatch): + previous = sys.modules.get("rosbags.usertypes") + monkeypatch.setattr(registry, "_store", None) + monkeypatch.setattr(registry, "_packages", {}) + monkeypatch.setattr(registry, "_unsupported", set()) + monkeypatch.setattr(registry, "_schemas", {}) + monkeypatch.setattr(registry, "providers", lambda: ()) + try: + yield + finally: + if previous is None: + sys.modules.pop("rosbags.usertypes", None) + else: + sys.modules["rosbags.usertypes"] = previous + + +def package(tmp_path, name, definition): + source = tmp_path / "interfaces" / "accept_msgs" / "msg" / f"{name}.msg" + source.parent.mkdir(parents=True, exist_ok=True) + source.write_text(definition) + output = tmp_path / "output" + generate( + [tmp_path / "interfaces"], + output, + [f"accept_msgs/msg/{name}"], + module="accept_messages", + shared=True, + languages=("python",), + ) + return output + + +def test_frozen_native_classes_roundtrip_and_pickle(tmp_path, frozen_registry): + root = package(tmp_path, "Reading", "std_msgs/Header header\nfloat64 value\n") + store = registry.initialize((root,)) + header = store.types["std_msgs/msg/Header"]( + store.types["builtin_interfaces/msg/Time"](1, 2), "map" + ) + cls = store.types["accept_msgs/msg/Reading"] + value = cls(header, 1.5) + assert not hasattr(value, "encode") + assert type(pickle.loads(pickle.dumps(value)).header) is type(header) + assert type(registry.decode(registry.encode(value), value.__msgtype__).header) is type(header) + assert registry.initialize((root,)).types[header.__msgtype__] is type(header) + + +def test_late_registration_fails_without_replacing_existing_classes(tmp_path, frozen_registry): + root = package(tmp_path / "one", "Reading", "float64 value\n") + store = registry.initialize((root,)) + value = store.types["accept_msgs/msg/Reading"](1.5) + newer = package(tmp_path / "two", "Other", "int32 value\n") + with pytest.raises(RuntimeError, match="frozen"): + registry.initialize((newer,)) + assert type(pickle.loads(pickle.dumps(value))) is type(value) + + +def test_schema_tampering_fails_before_registration(tmp_path, frozen_registry): + root = package(tmp_path, "Reading", "float64 value\n") + (root / "schemas.json").write_text(json.dumps({"accept_msgs/msg/Reading": "int32 value\n"})) + with pytest.raises(ValueError, match="digest"): + registry.initialize((root,)) + assert registry._store is None + + +def test_unsupported_native_python_bounds_are_not_silently_accepted(tmp_path, frozen_registry): + root = package(tmp_path, "Limited", "float64[<=3] values\n") + store = registry.initialize((root,)) + value = store.types["accept_msgs/msg/Limited"](np.array([1.0, 2.0, 3.0, 4.0])) + with pytest.raises(NotImplementedError, match="bounds"): + registry.encode(value) + wire = bytes(store.serialize_cdr(value, value.__msgtype__)) + with pytest.raises(NotImplementedError, match="bounds"): + registry.decode(wire, value.__msgtype__) + + +def test_native_python_defaults_are_explicit_not_rewritten(tmp_path, frozen_registry): + root = package(tmp_path, "Reading", "float64 value 1.5\n") + cls = registry.initialize((root,)).types["accept_msgs/msg/Reading"] + with pytest.raises(TypeError): + cls() + assert cls(1.5).value == 1.5 + assert json.loads((root / "message-package.json").read_text())[ + "types_with_declared_defaults" + ] == ["accept_msgs/msg/Reading"] + + +def test_selected_language_cache_invalidates_on_selection_edit_delete_and_rename( + tmp_path, monkeypatch +): + (tmp_path / "pyproject.toml").write_text( + '[project]\nname="accept-messages"\nversion="0.1.0"\n[tool.dimos.messages]\ndependencies={}\n' + ) + source = tmp_path / "interfaces/accept_msgs/msg/Reading.msg" + source.parent.mkdir(parents=True) + source.write_text("float64 value\n") + config = Project.load(tmp_path) + + def no_tools(*args, **kwargs): + raise AssertionError("Source packaging invoked an external build") + + monkeypatch.setattr(subprocess, "run", no_tools) + output = prepare(config) + stamp = (output / "generation.json").stat().st_mtime_ns + assert prepare(config) == output + assert (output / "generation.json").stat().st_mtime_ns == stamp + assert not (output / "cpp").exists() + assert not (output / "rust").exists() + prepare(config, ("rust",)) + assert (output / "rust/build.rs").is_file() + assert not (output / "python").exists() + source.rename(source.with_name("Renamed.msg")) + source.with_name("Renamed.msg").write_text("int32 other\n") + prepare(config) + assert not (output / "schemas/accept_msgs/msg/Reading.msg").exists() + assert (output / "schemas/accept_msgs/msg/Renamed.msg").read_text() == "int32 other\n" + source.with_name("Renamed.msg").unlink() + with pytest.raises(ValueError, match="No messages"): + prepare(config) + assert (output / "schemas/accept_msgs/msg/Renamed.msg").is_file() + + +def test_cpp_and_rust_bounded_strings_fail_explicitly(tmp_path): + source = tmp_path / "interfaces/accept_msgs/msg/Limited.msg" + source.parent.mkdir(parents=True) + source.write_text("string<=3 value\n") + for language in ["cpp", "rust"]: + with pytest.raises(NotImplementedError, match="Unsupported native"): + generate( + [tmp_path / "interfaces"], + tmp_path / language, + ["accept_msgs/msg/Limited"], + languages=(language,), + ) + + +def test_source_cache_tracks_edits_renames_and_deletions_without_build_outputs(tmp_path): + source = tmp_path / "module" + source.mkdir() + file = source / "main.cpp" + file.write_text("int main() { return 0; }\n") + digest = source_digest(source) + staged, executable = stage_module(source, source / "build/app", tmp_path / "cache") + assert (staged / "main.cpp").read_bytes() == file.read_bytes() + assert executable == staged / "build/app" + (source / "build").mkdir() + (source / "build/app").write_text("built executable") + assert source_digest(source) == digest + assert stage_module(source, source / "build/app", tmp_path / "cache")[0] == staged + file.rename(file.with_name("renamed.cpp")) + renamed = source_digest(source) + assert renamed != digest + file.with_name("renamed.cpp").write_text("int main() { return 1; }\n") + assert source_digest(source) != renamed + file.with_name("renamed.cpp").unlink() + assert source_digest(source) != digest + + +def test_native_cache_rejects_deleted_or_modified_artifacts(tmp_path): + prefix = tmp_path / "install" + prefix.mkdir() + library = prefix / "library.so" + library.write_bytes(b"original library") + marker = tmp_path / "complete.json" + save_complete(prefix, marker) + assert complete(prefix, marker) + library.write_bytes(b"changed library") + assert not complete(prefix, marker) + library.unlink() + assert not complete(prefix, marker) + + +def test_native_build_rejects_changed_schema_before_preparing_support(tmp_path, monkeypatch): + root = package(tmp_path, "Reading", "float64 value\n") + (root / "schemas/accept_msgs/msg/Reading.msg").write_text("int32 value\n") + + def no_build(*args, **kwargs): + raise AssertionError("Invalid schema started native preparation") + + monkeypatch.setattr(native_build, "prepare_support", no_build) + with pytest.raises(ValueError, match="schema mismatch"): + native_build.prepare_cpp(root, cache=tmp_path / "cache") + assert not (tmp_path / "cache").exists() + + +def test_cache_identity_tracks_selected_compilers_and_cmake(monkeypatch): + monkeypatch.setenv("CXX", "selected-cxx --target=test") + monkeypatch.setenv("CC", "selected-cc") + monkeypatch.setattr(native_build.shutil, "which", lambda name: "/tools/" + name) + monkeypatch.setattr(native_build, "find_spec", lambda name: True) + monkeypatch.setattr(native_build.metadata, "version", lambda name: "1.0") + versions = {"selected-cxx": "CXX 1", "selected-cc": "CC 1", "cmake": "CMake 1"} + commands = [] + + def compiler_output(command, **kwargs): + commands.append(command) + return "test-target" if command[-1] == "-dumpmachine" else versions[command[0]] + + monkeypatch.setattr(native_build.subprocess, "check_output", compiler_output) + first = native_build._toolchain_key() + assert ["selected-cxx", "--target=test", "--version"] in commands + assert ["selected-cc", "--version"] in commands + versions["selected-cxx"] = "CXX 2" + second = native_build._toolchain_key() + assert second != first + versions["selected-cc"] = "CC 2" + third = native_build._toolchain_key() + assert third != second + versions["cmake"] = "CMake 2" + assert native_build._toolchain_key() != third + + +@pytest.mark.parametrize("language", ["cpp", "rust"]) +@pytest.mark.xfail( + strict=True, + raises=NotImplementedError, + reason="CDR-L09: docs/development/message-limitations.md#cdr-l09", +) +def test_original_bounded_telemetry_fixture_generates_native_sources(tmp_path, language): + root = Path(__file__).resolve().parents[2] + names = generate( + [root / "examples/message-codegen"], + tmp_path / language, + ["demo_msgs/msg/Telemetry"], + "legacy_telemetry", + languages=(language,), + ) + assert "demo_msgs/msg/Telemetry" in names diff --git a/packages/dimos-generated/src/dimos_generated/_types.pyi b/packages/dimos-generated/src/dimos_generated/_types.pyi new file mode 100644 index 00000000000..4298c0abf5f --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/_types.pyi @@ -0,0 +1,3141 @@ +# Copyright 2020 - 2025 Ternaris +# SPDX-License-Identifier: Apache-2.0 +# +# THIS FILE IS GENERATED, DO NOT EDIT +"""Message type definitions.""" + +# ruff: noqa: N801,N816,RUF100,TC004 + +from __future__ import annotations + +from dataclasses import dataclass +from typing import TYPE_CHECKING + +from rosbags.interfaces import Nodetype as T + +if TYPE_CHECKING: + from typing import ClassVar + + import numpy as np + + from rosbags.interfaces.typing import Typesdict + + +@dataclass +class builtin_interfaces__msg__Duration: + """Class for builtin_interfaces/msg/Duration.""" + + sec: int + nanosec: int + __msgtype__: ClassVar[str] = 'builtin_interfaces/msg/Duration' + + +@dataclass +class builtin_interfaces__msg__Time: + """Class for builtin_interfaces/msg/Time.""" + + sec: int + nanosec: int + __msgtype__: ClassVar[str] = 'builtin_interfaces/msg/Time' + + +@dataclass +class std_msgs__msg__Header: + """Class for std_msgs/msg/Header.""" + + stamp: builtin_interfaces__msg__Time + frame_id: str + __msgtype__: ClassVar[str] = 'std_msgs/msg/Header' + + +@dataclass +class vision_msgs__msg__Point2D: + """Class for vision_msgs/msg/Point2D.""" + + x: float + y: float + __msgtype__: ClassVar[str] = 'vision_msgs/msg/Point2D' + + +@dataclass +class vision_msgs__msg__Pose2D: + """Class for vision_msgs/msg/Pose2D.""" + + position: vision_msgs__msg__Point2D + theta: float + __msgtype__: ClassVar[str] = 'vision_msgs/msg/Pose2D' + + +@dataclass +class vision_msgs__msg__BoundingBox2D: + """Class for vision_msgs/msg/BoundingBox2D.""" + + center: vision_msgs__msg__Pose2D + size_x: float + size_y: float + __msgtype__: ClassVar[str] = 'vision_msgs/msg/BoundingBox2D' + + +@dataclass +class dimos_msgs__msg__BoundingBox2DArray: + """Class for dimos_msgs/msg/BoundingBox2DArray.""" + + header: std_msgs__msg__Header + boxes: list[vision_msgs__msg__BoundingBox2D] + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/BoundingBox2DArray' + + +@dataclass +class geometry_msgs__msg__Point: + """Class for geometry_msgs/msg/Point.""" + + x: float + y: float + z: float + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Point' + + +@dataclass +class geometry_msgs__msg__Quaternion: + """Class for geometry_msgs/msg/Quaternion.""" + + x: float + y: float + z: float + w: float + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Quaternion' + + +@dataclass +class geometry_msgs__msg__Pose: + """Class for geometry_msgs/msg/Pose.""" + + position: geometry_msgs__msg__Point + orientation: geometry_msgs__msg__Quaternion + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Pose' + + +@dataclass +class geometry_msgs__msg__Vector3: + """Class for geometry_msgs/msg/Vector3.""" + + x: float + y: float + z: float + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Vector3' + + +@dataclass +class vision_msgs__msg__BoundingBox3D: + """Class for vision_msgs/msg/BoundingBox3D.""" + + center: geometry_msgs__msg__Pose + size: geometry_msgs__msg__Vector3 + __msgtype__: ClassVar[str] = 'vision_msgs/msg/BoundingBox3D' + + +@dataclass +class dimos_msgs__msg__BoundingBox3DArray: + """Class for dimos_msgs/msg/BoundingBox3DArray.""" + + header: std_msgs__msg__Header + boxes: list[vision_msgs__msg__BoundingBox3D] + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/BoundingBox3DArray' + + +@dataclass +class dimos_msgs__msg__EntityMarker: + """Class for dimos_msgs/msg/EntityMarker.""" + + entity_id: str + label: str + entity_type: str + position: geometry_msgs__msg__Point + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/EntityMarker' + + +@dataclass +class dimos_msgs__msg__EntityMarkers: + """Class for dimos_msgs/msg/EntityMarkers.""" + + header: std_msgs__msg__Header + markers: list[dimos_msgs__msg__EntityMarker] + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/EntityMarkers' + + +@dataclass +class dimos_msgs__msg__GraspCandidate: + """Class for dimos_msgs/msg/GraspCandidate.""" + + pose: geometry_msgs__msg__Pose + score: float + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/GraspCandidate' + + +@dataclass +class dimos_msgs__msg__GraspCandidateArray: + """Class for dimos_msgs/msg/GraspCandidateArray.""" + + header: std_msgs__msg__Header + candidates: list[dimos_msgs__msg__GraspCandidate] + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/GraspCandidateArray' + + +@dataclass +class dimos_msgs__msg__ImuInfo: + """Class for dimos_msgs/msg/ImuInfo.""" + + header: std_msgs__msg__Header + gyro_noise_density: float + gyro_random_walk: float + accel_noise_density: float + accel_random_walk: float + frequency: float + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/ImuInfo' + + +@dataclass +class dimos_msgs__msg__JointCommand: + """Class for dimos_msgs/msg/JointCommand.""" + + header: std_msgs__msg__Header + positions: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/JointCommand' + + +@dataclass +class dimos_msgs__msg__LineSegment3D: + """Class for dimos_msgs/msg/LineSegment3D.""" + + start: geometry_msgs__msg__Point + end: geometry_msgs__msg__Point + weight: float + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/LineSegment3D' + + +@dataclass +class dimos_msgs__msg__LineSegments3D: + """Class for dimos_msgs/msg/LineSegments3D.""" + + header: std_msgs__msg__Header + segments: list[dimos_msgs__msg__LineSegment3D] + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/LineSegments3D' + + +@dataclass +class dimos_msgs__msg__MotorCommandArray: + """Class for dimos_msgs/msg/MotorCommandArray.""" + + header: std_msgs__msg__Header + q: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + dq: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + kp: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + kd: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + tau: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/MotorCommandArray' + + +@dataclass +class dimos_msgs__msg__RobotState: + """Class for dimos_msgs/msg/RobotState.""" + + header: std_msgs__msg__Header + state: int + mode: int + error_code: int + warn_code: int + cmdnum: int + mt_brake: int + mt_able: int + tcp_pose: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + tcp_offset: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + joints: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/RobotState' + + +@dataclass +class dimos_msgs__msg__TrajectoryStatus: + """Class for dimos_msgs/msg/TrajectoryStatus.""" + + header: std_msgs__msg__Header + state: int + progress: float + time_elapsed: builtin_interfaces__msg__Duration + time_remaining: builtin_interfaces__msg__Duration + error: str + IDLE: ClassVar[int] = 0 + EXECUTING: ClassVar[int] = 1 + COMPLETED: ClassVar[int] = 2 + ABORTED: ClassVar[int] = 3 + FAULT: ClassVar[int] = 4 + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/TrajectoryStatus' + + +@dataclass +class dimos_msgs__msg__VideoStats: + """Class for dimos_msgs/msg/VideoStats.""" + + header: std_msgs__msg__Header + fps: float + kbps: float + width: int + height: int + loss_pct: float + jitter_buffer_ms: float + decode_ms: float + frames_dropped: int + freezes: int + e2e_latency_ms: float + __msgtype__: ClassVar[str] = 'dimos_msgs/msg/VideoStats' + + +@dataclass +class foxglove_msgs__msg__CompressedVideo: + """Class for foxglove_msgs/msg/CompressedVideo.""" + + timestamp: builtin_interfaces__msg__Time + frame_id: str + data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] + format: str + __msgtype__: ClassVar[str] = 'foxglove_msgs/msg/CompressedVideo' + + +@dataclass +class geometry_msgs__msg__Accel: + """Class for geometry_msgs/msg/Accel.""" + + linear: geometry_msgs__msg__Vector3 + angular: geometry_msgs__msg__Vector3 + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Accel' + + +@dataclass +class geometry_msgs__msg__AccelStamped: + """Class for geometry_msgs/msg/AccelStamped.""" + + header: std_msgs__msg__Header + accel: geometry_msgs__msg__Accel + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/AccelStamped' + + +@dataclass +class geometry_msgs__msg__AccelWithCovariance: + """Class for geometry_msgs/msg/AccelWithCovariance.""" + + accel: geometry_msgs__msg__Accel + covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/AccelWithCovariance' + + +@dataclass +class geometry_msgs__msg__AccelWithCovarianceStamped: + """Class for geometry_msgs/msg/AccelWithCovarianceStamped.""" + + header: std_msgs__msg__Header + accel: geometry_msgs__msg__AccelWithCovariance + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/AccelWithCovarianceStamped' + + +@dataclass +class geometry_msgs__msg__Inertia: + """Class for geometry_msgs/msg/Inertia.""" + + m: float + com: geometry_msgs__msg__Vector3 + ixx: float + ixy: float + ixz: float + iyy: float + iyz: float + izz: float + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Inertia' + + +@dataclass +class geometry_msgs__msg__InertiaStamped: + """Class for geometry_msgs/msg/InertiaStamped.""" + + header: std_msgs__msg__Header + inertia: geometry_msgs__msg__Inertia + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/InertiaStamped' + + +@dataclass +class geometry_msgs__msg__Point32: + """Class for geometry_msgs/msg/Point32.""" + + x: float + y: float + z: float + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Point32' + + +@dataclass +class geometry_msgs__msg__PointStamped: + """Class for geometry_msgs/msg/PointStamped.""" + + header: std_msgs__msg__Header + point: geometry_msgs__msg__Point + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PointStamped' + + +@dataclass +class geometry_msgs__msg__Polygon: + """Class for geometry_msgs/msg/Polygon.""" + + points: list[geometry_msgs__msg__Point32] + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Polygon' + + +@dataclass +class geometry_msgs__msg__PolygonInstance: + """Class for geometry_msgs/msg/PolygonInstance.""" + + polygon: geometry_msgs__msg__Polygon + id: int + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PolygonInstance' + + +@dataclass +class geometry_msgs__msg__PolygonInstanceStamped: + """Class for geometry_msgs/msg/PolygonInstanceStamped.""" + + header: std_msgs__msg__Header + polygon: geometry_msgs__msg__PolygonInstance + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PolygonInstanceStamped' + + +@dataclass +class geometry_msgs__msg__PolygonStamped: + """Class for geometry_msgs/msg/PolygonStamped.""" + + header: std_msgs__msg__Header + polygon: geometry_msgs__msg__Polygon + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PolygonStamped' + + +@dataclass +class geometry_msgs__msg__Pose2D: + """Class for geometry_msgs/msg/Pose2D.""" + + x: float + y: float + theta: float + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Pose2D' + + +@dataclass +class geometry_msgs__msg__PoseArray: + """Class for geometry_msgs/msg/PoseArray.""" + + header: std_msgs__msg__Header + poses: list[geometry_msgs__msg__Pose] + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PoseArray' + + +@dataclass +class geometry_msgs__msg__PoseStamped: + """Class for geometry_msgs/msg/PoseStamped.""" + + header: std_msgs__msg__Header + pose: geometry_msgs__msg__Pose + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PoseStamped' + + +@dataclass +class geometry_msgs__msg__PoseWithCovariance: + """Class for geometry_msgs/msg/PoseWithCovariance.""" + + pose: geometry_msgs__msg__Pose + covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PoseWithCovariance' + + +@dataclass +class geometry_msgs__msg__PoseWithCovarianceStamped: + """Class for geometry_msgs/msg/PoseWithCovarianceStamped.""" + + header: std_msgs__msg__Header + pose: geometry_msgs__msg__PoseWithCovariance + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PoseWithCovarianceStamped' + + +@dataclass +class geometry_msgs__msg__QuaternionStamped: + """Class for geometry_msgs/msg/QuaternionStamped.""" + + header: std_msgs__msg__Header + quaternion: geometry_msgs__msg__Quaternion + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/QuaternionStamped' + + +@dataclass +class geometry_msgs__msg__Transform: + """Class for geometry_msgs/msg/Transform.""" + + translation: geometry_msgs__msg__Vector3 + rotation: geometry_msgs__msg__Quaternion + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Transform' + + +@dataclass +class geometry_msgs__msg__TransformStamped: + """Class for geometry_msgs/msg/TransformStamped.""" + + header: std_msgs__msg__Header + child_frame_id: str + transform: geometry_msgs__msg__Transform + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/TransformStamped' + + +@dataclass +class geometry_msgs__msg__Twist: + """Class for geometry_msgs/msg/Twist.""" + + linear: geometry_msgs__msg__Vector3 + angular: geometry_msgs__msg__Vector3 + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Twist' + + +@dataclass +class geometry_msgs__msg__TwistStamped: + """Class for geometry_msgs/msg/TwistStamped.""" + + header: std_msgs__msg__Header + twist: geometry_msgs__msg__Twist + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/TwistStamped' + + +@dataclass +class geometry_msgs__msg__TwistWithCovariance: + """Class for geometry_msgs/msg/TwistWithCovariance.""" + + twist: geometry_msgs__msg__Twist + covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/TwistWithCovariance' + + +@dataclass +class geometry_msgs__msg__TwistWithCovarianceStamped: + """Class for geometry_msgs/msg/TwistWithCovarianceStamped.""" + + header: std_msgs__msg__Header + twist: geometry_msgs__msg__TwistWithCovariance + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/TwistWithCovarianceStamped' + + +@dataclass +class geometry_msgs__msg__Vector3Stamped: + """Class for geometry_msgs/msg/Vector3Stamped.""" + + header: std_msgs__msg__Header + vector: geometry_msgs__msg__Vector3 + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Vector3Stamped' + + +@dataclass +class geometry_msgs__msg__VelocityStamped: + """Class for geometry_msgs/msg/VelocityStamped.""" + + header: std_msgs__msg__Header + body_frame_id: str + reference_frame_id: str + velocity: geometry_msgs__msg__Twist + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/VelocityStamped' + + +@dataclass +class geometry_msgs__msg__VelocityWithCovarianceStamped: + """Class for geometry_msgs/msg/VelocityWithCovarianceStamped.""" + + header: std_msgs__msg__Header + body_frame_id: str + reference_frame_id: str + velocity: geometry_msgs__msg__TwistWithCovariance + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/VelocityWithCovarianceStamped' + + +@dataclass +class geometry_msgs__msg__Wrench: + """Class for geometry_msgs/msg/Wrench.""" + + force: geometry_msgs__msg__Vector3 + torque: geometry_msgs__msg__Vector3 + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Wrench' + + +@dataclass +class geometry_msgs__msg__WrenchStamped: + """Class for geometry_msgs/msg/WrenchStamped.""" + + header: std_msgs__msg__Header + wrench: geometry_msgs__msg__Wrench + __msgtype__: ClassVar[str] = 'geometry_msgs/msg/WrenchStamped' + + +@dataclass +class nav_msgs__msg__Goals: + """Class for nav_msgs/msg/Goals.""" + + header: std_msgs__msg__Header + goals: list[geometry_msgs__msg__PoseStamped] + __msgtype__: ClassVar[str] = 'nav_msgs/msg/Goals' + + +@dataclass +class nav_msgs__msg__GridCells: + """Class for nav_msgs/msg/GridCells.""" + + header: std_msgs__msg__Header + cell_width: float + cell_height: float + cells: list[geometry_msgs__msg__Point] + __msgtype__: ClassVar[str] = 'nav_msgs/msg/GridCells' + + +@dataclass +class nav_msgs__msg__MapMetaData: + """Class for nav_msgs/msg/MapMetaData.""" + + map_load_time: builtin_interfaces__msg__Time + resolution: float + width: int + height: int + origin: geometry_msgs__msg__Pose + __msgtype__: ClassVar[str] = 'nav_msgs/msg/MapMetaData' + + +@dataclass +class nav_msgs__msg__OccupancyGrid: + """Class for nav_msgs/msg/OccupancyGrid.""" + + header: std_msgs__msg__Header + info: nav_msgs__msg__MapMetaData + data: np.ndarray[tuple[int, ...], np.dtype[np.int8]] + __msgtype__: ClassVar[str] = 'nav_msgs/msg/OccupancyGrid' + + +@dataclass +class nav_msgs__msg__Odometry: + """Class for nav_msgs/msg/Odometry.""" + + header: std_msgs__msg__Header + child_frame_id: str + pose: geometry_msgs__msg__PoseWithCovariance + twist: geometry_msgs__msg__TwistWithCovariance + __msgtype__: ClassVar[str] = 'nav_msgs/msg/Odometry' + + +@dataclass +class nav_msgs__msg__Path: + """Class for nav_msgs/msg/Path.""" + + header: std_msgs__msg__Header + poses: list[geometry_msgs__msg__PoseStamped] + __msgtype__: ClassVar[str] = 'nav_msgs/msg/Path' + + +@dataclass +class nav_msgs__msg__TrajectoryPoint: + """Class for nav_msgs/msg/TrajectoryPoint.""" + + header: std_msgs__msg__Header + pose: geometry_msgs__msg__Pose + velocity: geometry_msgs__msg__Twist + acceleration: geometry_msgs__msg__Accel + effort: geometry_msgs__msg__Wrench + __msgtype__: ClassVar[str] = 'nav_msgs/msg/TrajectoryPoint' + + +@dataclass +class nav_msgs__msg__Trajectory: + """Class for nav_msgs/msg/Trajectory.""" + + header: std_msgs__msg__Header + points: list[nav_msgs__msg__TrajectoryPoint] + __msgtype__: ClassVar[str] = 'nav_msgs/msg/Trajectory' + + +@dataclass +class sensor_msgs__msg__BatteryState: + """Class for sensor_msgs/msg/BatteryState.""" + + header: std_msgs__msg__Header + voltage: float + temperature: float + current: float + charge: float + capacity: float + design_capacity: float + percentage: float + power_supply_status: int + power_supply_health: int + power_supply_technology: int + present: bool + cell_voltage: np.ndarray[tuple[int, ...], np.dtype[np.float32]] + cell_temperature: np.ndarray[tuple[int, ...], np.dtype[np.float32]] + location: str + serial_number: str + POWER_SUPPLY_STATUS_UNKNOWN: ClassVar[int] = 0 + POWER_SUPPLY_STATUS_CHARGING: ClassVar[int] = 1 + POWER_SUPPLY_STATUS_DISCHARGING: ClassVar[int] = 2 + POWER_SUPPLY_STATUS_NOT_CHARGING: ClassVar[int] = 3 + POWER_SUPPLY_STATUS_FULL: ClassVar[int] = 4 + POWER_SUPPLY_HEALTH_UNKNOWN: ClassVar[int] = 0 + POWER_SUPPLY_HEALTH_GOOD: ClassVar[int] = 1 + POWER_SUPPLY_HEALTH_OVERHEAT: ClassVar[int] = 2 + POWER_SUPPLY_HEALTH_DEAD: ClassVar[int] = 3 + POWER_SUPPLY_HEALTH_OVERVOLTAGE: ClassVar[int] = 4 + POWER_SUPPLY_HEALTH_UNSPEC_FAILURE: ClassVar[int] = 5 + POWER_SUPPLY_HEALTH_COLD: ClassVar[int] = 6 + POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE: ClassVar[int] = 7 + POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE: ClassVar[int] = 8 + POWER_SUPPLY_TECHNOLOGY_UNKNOWN: ClassVar[int] = 0 + POWER_SUPPLY_TECHNOLOGY_NIMH: ClassVar[int] = 1 + POWER_SUPPLY_TECHNOLOGY_LION: ClassVar[int] = 2 + POWER_SUPPLY_TECHNOLOGY_LIPO: ClassVar[int] = 3 + POWER_SUPPLY_TECHNOLOGY_LIFE: ClassVar[int] = 4 + POWER_SUPPLY_TECHNOLOGY_NICD: ClassVar[int] = 5 + POWER_SUPPLY_TECHNOLOGY_LIMN: ClassVar[int] = 6 + POWER_SUPPLY_TECHNOLOGY_TERNARY: ClassVar[int] = 7 + POWER_SUPPLY_TECHNOLOGY_VRLA: ClassVar[int] = 8 + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/BatteryState' + + +@dataclass +class sensor_msgs__msg__RegionOfInterest: + """Class for sensor_msgs/msg/RegionOfInterest.""" + + x_offset: int + y_offset: int + height: int + width: int + do_rectify: bool + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/RegionOfInterest' + + +@dataclass +class sensor_msgs__msg__CameraInfo: + """Class for sensor_msgs/msg/CameraInfo.""" + + header: std_msgs__msg__Header + height: int + width: int + distortion_model: str + d: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + k: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + r: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + p: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + binning_x: int + binning_y: int + roi: sensor_msgs__msg__RegionOfInterest + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/CameraInfo' + + +@dataclass +class sensor_msgs__msg__ChannelFloat32: + """Class for sensor_msgs/msg/ChannelFloat32.""" + + name: str + values: np.ndarray[tuple[int, ...], np.dtype[np.float32]] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/ChannelFloat32' + + +@dataclass +class sensor_msgs__msg__CompressedImage: + """Class for sensor_msgs/msg/CompressedImage.""" + + header: std_msgs__msg__Header + format: str + data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/CompressedImage' + + +@dataclass +class sensor_msgs__msg__FluidPressure: + """Class for sensor_msgs/msg/FluidPressure.""" + + header: std_msgs__msg__Header + fluid_pressure: float + variance: float + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/FluidPressure' + + +@dataclass +class sensor_msgs__msg__Illuminance: + """Class for sensor_msgs/msg/Illuminance.""" + + header: std_msgs__msg__Header + illuminance: float + variance: float + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Illuminance' + + +@dataclass +class sensor_msgs__msg__Image: + """Class for sensor_msgs/msg/Image.""" + + header: std_msgs__msg__Header + height: int + width: int + encoding: str + is_bigendian: int + step: int + data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Image' + + +@dataclass +class sensor_msgs__msg__Imu: + """Class for sensor_msgs/msg/Imu.""" + + header: std_msgs__msg__Header + orientation: geometry_msgs__msg__Quaternion + orientation_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + angular_velocity: geometry_msgs__msg__Vector3 + angular_velocity_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + linear_acceleration: geometry_msgs__msg__Vector3 + linear_acceleration_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Imu' + + +@dataclass +class sensor_msgs__msg__JointState: + """Class for sensor_msgs/msg/JointState.""" + + header: std_msgs__msg__Header + name: list[str] + position: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + velocity: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + effort: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/JointState' + + +@dataclass +class sensor_msgs__msg__Joy: + """Class for sensor_msgs/msg/Joy.""" + + header: std_msgs__msg__Header + axes: np.ndarray[tuple[int, ...], np.dtype[np.float32]] + buttons: np.ndarray[tuple[int, ...], np.dtype[np.int32]] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Joy' + + +@dataclass +class sensor_msgs__msg__JoyFeedback: + """Class for sensor_msgs/msg/JoyFeedback.""" + + type: int + id: int + intensity: float + TYPE_LED: ClassVar[int] = 0 + TYPE_RUMBLE: ClassVar[int] = 1 + TYPE_BUZZER: ClassVar[int] = 2 + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/JoyFeedback' + + +@dataclass +class sensor_msgs__msg__JoyFeedbackArray: + """Class for sensor_msgs/msg/JoyFeedbackArray.""" + + array: list[sensor_msgs__msg__JoyFeedback] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/JoyFeedbackArray' + + +@dataclass +class sensor_msgs__msg__LaserEcho: + """Class for sensor_msgs/msg/LaserEcho.""" + + echoes: np.ndarray[tuple[int, ...], np.dtype[np.float32]] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/LaserEcho' + + +@dataclass +class sensor_msgs__msg__LaserScan: + """Class for sensor_msgs/msg/LaserScan.""" + + header: std_msgs__msg__Header + angle_min: float + angle_max: float + angle_increment: float + time_increment: float + scan_time: float + range_min: float + range_max: float + ranges: np.ndarray[tuple[int, ...], np.dtype[np.float32]] + intensities: np.ndarray[tuple[int, ...], np.dtype[np.float32]] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/LaserScan' + + +@dataclass +class sensor_msgs__msg__MagneticField: + """Class for sensor_msgs/msg/MagneticField.""" + + header: std_msgs__msg__Header + magnetic_field: geometry_msgs__msg__Vector3 + magnetic_field_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/MagneticField' + + +@dataclass +class sensor_msgs__msg__MultiDOFJointState: + """Class for sensor_msgs/msg/MultiDOFJointState.""" + + header: std_msgs__msg__Header + joint_names: list[str] + transforms: list[geometry_msgs__msg__Transform] + twist: list[geometry_msgs__msg__Twist] + wrench: list[geometry_msgs__msg__Wrench] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/MultiDOFJointState' + + +@dataclass +class sensor_msgs__msg__MultiEchoLaserScan: + """Class for sensor_msgs/msg/MultiEchoLaserScan.""" + + header: std_msgs__msg__Header + angle_min: float + angle_max: float + angle_increment: float + time_increment: float + scan_time: float + range_min: float + range_max: float + ranges: list[sensor_msgs__msg__LaserEcho] + intensities: list[sensor_msgs__msg__LaserEcho] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/MultiEchoLaserScan' + + +@dataclass +class sensor_msgs__msg__NavSatStatus: + """Class for sensor_msgs/msg/NavSatStatus.""" + + status: int + service: int + STATUS_UNKNOWN: ClassVar[int] = -2 + STATUS_NO_FIX: ClassVar[int] = -1 + STATUS_FIX: ClassVar[int] = 0 + STATUS_SBAS_FIX: ClassVar[int] = 1 + STATUS_GBAS_FIX: ClassVar[int] = 2 + SERVICE_UNKNOWN: ClassVar[int] = 0 + SERVICE_GPS: ClassVar[int] = 1 + SERVICE_GLONASS: ClassVar[int] = 2 + SERVICE_COMPASS: ClassVar[int] = 4 + SERVICE_GALILEO: ClassVar[int] = 8 + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/NavSatStatus' + + +@dataclass +class sensor_msgs__msg__NavSatFix: + """Class for sensor_msgs/msg/NavSatFix.""" + + header: std_msgs__msg__Header + status: sensor_msgs__msg__NavSatStatus + latitude: float + longitude: float + altitude: float + position_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + position_covariance_type: int + COVARIANCE_TYPE_UNKNOWN: ClassVar[int] = 0 + COVARIANCE_TYPE_APPROXIMATED: ClassVar[int] = 1 + COVARIANCE_TYPE_DIAGONAL_KNOWN: ClassVar[int] = 2 + COVARIANCE_TYPE_KNOWN: ClassVar[int] = 3 + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/NavSatFix' + + +@dataclass +class sensor_msgs__msg__PointCloud: + """Class for sensor_msgs/msg/PointCloud.""" + + header: std_msgs__msg__Header + points: list[geometry_msgs__msg__Point32] + channels: list[sensor_msgs__msg__ChannelFloat32] + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/PointCloud' + + +@dataclass +class sensor_msgs__msg__PointField: + """Class for sensor_msgs/msg/PointField.""" + + name: str + offset: int + datatype: int + count: int + INT8: ClassVar[int] = 1 + UINT8: ClassVar[int] = 2 + INT16: ClassVar[int] = 3 + UINT16: ClassVar[int] = 4 + INT32: ClassVar[int] = 5 + UINT32: ClassVar[int] = 6 + FLOAT32: ClassVar[int] = 7 + FLOAT64: ClassVar[int] = 8 + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/PointField' + + +@dataclass +class sensor_msgs__msg__PointCloud2: + """Class for sensor_msgs/msg/PointCloud2.""" + + header: std_msgs__msg__Header + height: int + width: int + fields: list[sensor_msgs__msg__PointField] + is_bigendian: bool + point_step: int + row_step: int + data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] + is_dense: bool + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/PointCloud2' + + +@dataclass +class sensor_msgs__msg__Range: + """Class for sensor_msgs/msg/Range.""" + + header: std_msgs__msg__Header + radiation_type: int + field_of_view: float + min_range: float + max_range: float + range: float + variance: float + ULTRASOUND: ClassVar[int] = 0 + INFRARED: ClassVar[int] = 1 + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Range' + + +@dataclass +class sensor_msgs__msg__RelativeHumidity: + """Class for sensor_msgs/msg/RelativeHumidity.""" + + header: std_msgs__msg__Header + relative_humidity: float + variance: float + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/RelativeHumidity' + + +@dataclass +class sensor_msgs__msg__Temperature: + """Class for sensor_msgs/msg/Temperature.""" + + header: std_msgs__msg__Header + temperature: float + variance: float + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Temperature' + + +@dataclass +class sensor_msgs__msg__TimeReference: + """Class for sensor_msgs/msg/TimeReference.""" + + header: std_msgs__msg__Header + time_ref: builtin_interfaces__msg__Time + source: str + __msgtype__: ClassVar[str] = 'sensor_msgs/msg/TimeReference' + + +@dataclass +class shape_msgs__msg__MeshTriangle: + """Class for shape_msgs/msg/MeshTriangle.""" + + vertex_indices: np.ndarray[tuple[int, ...], np.dtype[np.uint32]] + __msgtype__: ClassVar[str] = 'shape_msgs/msg/MeshTriangle' + + +@dataclass +class shape_msgs__msg__Mesh: + """Class for shape_msgs/msg/Mesh.""" + + triangles: list[shape_msgs__msg__MeshTriangle] + vertices: list[geometry_msgs__msg__Point] + __msgtype__: ClassVar[str] = 'shape_msgs/msg/Mesh' + + +@dataclass +class shape_msgs__msg__Plane: + """Class for shape_msgs/msg/Plane.""" + + coef: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + __msgtype__: ClassVar[str] = 'shape_msgs/msg/Plane' + + +@dataclass +class shape_msgs__msg__SolidPrimitive: + """Class for shape_msgs/msg/SolidPrimitive.""" + + type: int + dimensions: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + polygon: geometry_msgs__msg__Polygon + BOX: ClassVar[int] = 1 + SPHERE: ClassVar[int] = 2 + CYLINDER: ClassVar[int] = 3 + CONE: ClassVar[int] = 4 + PRISM: ClassVar[int] = 5 + BOX_X: ClassVar[int] = 0 + BOX_Y: ClassVar[int] = 1 + BOX_Z: ClassVar[int] = 2 + SPHERE_RADIUS: ClassVar[int] = 0 + CYLINDER_HEIGHT: ClassVar[int] = 0 + CYLINDER_RADIUS: ClassVar[int] = 1 + CONE_HEIGHT: ClassVar[int] = 0 + CONE_RADIUS: ClassVar[int] = 1 + PRISM_HEIGHT: ClassVar[int] = 0 + __msgtype__: ClassVar[str] = 'shape_msgs/msg/SolidPrimitive' + + +@dataclass +class std_msgs__msg__Bool: + """Class for std_msgs/msg/Bool.""" + + data: bool + __msgtype__: ClassVar[str] = 'std_msgs/msg/Bool' + + +@dataclass +class std_msgs__msg__Byte: + """Class for std_msgs/msg/Byte.""" + + data: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/Byte' + + +@dataclass +class std_msgs__msg__MultiArrayDimension: + """Class for std_msgs/msg/MultiArrayDimension.""" + + label: str + size: int + stride: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/MultiArrayDimension' + + +@dataclass +class std_msgs__msg__MultiArrayLayout: + """Class for std_msgs/msg/MultiArrayLayout.""" + + dim: list[std_msgs__msg__MultiArrayDimension] + data_offset: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/MultiArrayLayout' + + +@dataclass +class std_msgs__msg__ByteMultiArray: + """Class for std_msgs/msg/ByteMultiArray.""" + + layout: std_msgs__msg__MultiArrayLayout + data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] + __msgtype__: ClassVar[str] = 'std_msgs/msg/ByteMultiArray' + + +@dataclass +class std_msgs__msg__Char: + """Class for std_msgs/msg/Char.""" + + data: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/Char' + + +@dataclass +class std_msgs__msg__ColorRGBA: + """Class for std_msgs/msg/ColorRGBA.""" + + r: float + g: float + b: float + a: float + __msgtype__: ClassVar[str] = 'std_msgs/msg/ColorRGBA' + + +@dataclass +class std_msgs__msg__Empty: + """Class for std_msgs/msg/Empty.""" + + structure_needs_at_least_one_member: int = 0 + __msgtype__: ClassVar[str] = 'std_msgs/msg/Empty' + + +@dataclass +class std_msgs__msg__Float32: + """Class for std_msgs/msg/Float32.""" + + data: float + __msgtype__: ClassVar[str] = 'std_msgs/msg/Float32' + + +@dataclass +class std_msgs__msg__Float32MultiArray: + """Class for std_msgs/msg/Float32MultiArray.""" + + layout: std_msgs__msg__MultiArrayLayout + data: np.ndarray[tuple[int, ...], np.dtype[np.float32]] + __msgtype__: ClassVar[str] = 'std_msgs/msg/Float32MultiArray' + + +@dataclass +class std_msgs__msg__Float64: + """Class for std_msgs/msg/Float64.""" + + data: float + __msgtype__: ClassVar[str] = 'std_msgs/msg/Float64' + + +@dataclass +class std_msgs__msg__Float64MultiArray: + """Class for std_msgs/msg/Float64MultiArray.""" + + layout: std_msgs__msg__MultiArrayLayout + data: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + __msgtype__: ClassVar[str] = 'std_msgs/msg/Float64MultiArray' + + +@dataclass +class std_msgs__msg__Int16: + """Class for std_msgs/msg/Int16.""" + + data: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/Int16' + + +@dataclass +class std_msgs__msg__Int16MultiArray: + """Class for std_msgs/msg/Int16MultiArray.""" + + layout: std_msgs__msg__MultiArrayLayout + data: np.ndarray[tuple[int, ...], np.dtype[np.int16]] + __msgtype__: ClassVar[str] = 'std_msgs/msg/Int16MultiArray' + + +@dataclass +class std_msgs__msg__Int32: + """Class for std_msgs/msg/Int32.""" + + data: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/Int32' + + +@dataclass +class std_msgs__msg__Int32MultiArray: + """Class for std_msgs/msg/Int32MultiArray.""" + + layout: std_msgs__msg__MultiArrayLayout + data: np.ndarray[tuple[int, ...], np.dtype[np.int32]] + __msgtype__: ClassVar[str] = 'std_msgs/msg/Int32MultiArray' + + +@dataclass +class std_msgs__msg__Int64: + """Class for std_msgs/msg/Int64.""" + + data: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/Int64' + + +@dataclass +class std_msgs__msg__Int64MultiArray: + """Class for std_msgs/msg/Int64MultiArray.""" + + layout: std_msgs__msg__MultiArrayLayout + data: np.ndarray[tuple[int, ...], np.dtype[np.int64]] + __msgtype__: ClassVar[str] = 'std_msgs/msg/Int64MultiArray' + + +@dataclass +class std_msgs__msg__Int8: + """Class for std_msgs/msg/Int8.""" + + data: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/Int8' + + +@dataclass +class std_msgs__msg__Int8MultiArray: + """Class for std_msgs/msg/Int8MultiArray.""" + + layout: std_msgs__msg__MultiArrayLayout + data: np.ndarray[tuple[int, ...], np.dtype[np.int8]] + __msgtype__: ClassVar[str] = 'std_msgs/msg/Int8MultiArray' + + +@dataclass +class std_msgs__msg__String: + """Class for std_msgs/msg/String.""" + + data: str + __msgtype__: ClassVar[str] = 'std_msgs/msg/String' + + +@dataclass +class std_msgs__msg__UInt16: + """Class for std_msgs/msg/UInt16.""" + + data: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt16' + + +@dataclass +class std_msgs__msg__UInt16MultiArray: + """Class for std_msgs/msg/UInt16MultiArray.""" + + layout: std_msgs__msg__MultiArrayLayout + data: np.ndarray[tuple[int, ...], np.dtype[np.uint16]] + __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt16MultiArray' + + +@dataclass +class std_msgs__msg__UInt32: + """Class for std_msgs/msg/UInt32.""" + + data: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt32' + + +@dataclass +class std_msgs__msg__UInt32MultiArray: + """Class for std_msgs/msg/UInt32MultiArray.""" + + layout: std_msgs__msg__MultiArrayLayout + data: np.ndarray[tuple[int, ...], np.dtype[np.uint32]] + __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt32MultiArray' + + +@dataclass +class std_msgs__msg__UInt64: + """Class for std_msgs/msg/UInt64.""" + + data: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt64' + + +@dataclass +class std_msgs__msg__UInt64MultiArray: + """Class for std_msgs/msg/UInt64MultiArray.""" + + layout: std_msgs__msg__MultiArrayLayout + data: np.ndarray[tuple[int, ...], np.dtype[np.uint64]] + __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt64MultiArray' + + +@dataclass +class std_msgs__msg__UInt8: + """Class for std_msgs/msg/UInt8.""" + + data: int + __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt8' + + +@dataclass +class std_msgs__msg__UInt8MultiArray: + """Class for std_msgs/msg/UInt8MultiArray.""" + + layout: std_msgs__msg__MultiArrayLayout + data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] + __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt8MultiArray' + + +@dataclass +class tf2_msgs__msg__TF2Error: + """Class for tf2_msgs/msg/TF2Error.""" + + error: int + error_string: str + NO_ERROR: ClassVar[int] = 0 + LOOKUP_ERROR: ClassVar[int] = 1 + CONNECTIVITY_ERROR: ClassVar[int] = 2 + EXTRAPOLATION_ERROR: ClassVar[int] = 3 + INVALID_ARGUMENT_ERROR: ClassVar[int] = 4 + TIMEOUT_ERROR: ClassVar[int] = 5 + TRANSFORM_ERROR: ClassVar[int] = 6 + __msgtype__: ClassVar[str] = 'tf2_msgs/msg/TF2Error' + + +@dataclass +class tf2_msgs__msg__TFMessage: + """Class for tf2_msgs/msg/TFMessage.""" + + transforms: list[geometry_msgs__msg__TransformStamped] + __msgtype__: ClassVar[str] = 'tf2_msgs/msg/TFMessage' + + +@dataclass +class trajectory_msgs__msg__JointTrajectoryPoint: + """Class for trajectory_msgs/msg/JointTrajectoryPoint.""" + + positions: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + velocities: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + accelerations: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + effort: np.ndarray[tuple[int, ...], np.dtype[np.float64]] + time_from_start: builtin_interfaces__msg__Duration + __msgtype__: ClassVar[str] = 'trajectory_msgs/msg/JointTrajectoryPoint' + + +@dataclass +class trajectory_msgs__msg__JointTrajectory: + """Class for trajectory_msgs/msg/JointTrajectory.""" + + header: std_msgs__msg__Header + joint_names: list[str] + points: list[trajectory_msgs__msg__JointTrajectoryPoint] + __msgtype__: ClassVar[str] = 'trajectory_msgs/msg/JointTrajectory' + + +@dataclass +class trajectory_msgs__msg__MultiDOFJointTrajectoryPoint: + """Class for trajectory_msgs/msg/MultiDOFJointTrajectoryPoint.""" + + transforms: list[geometry_msgs__msg__Transform] + velocities: list[geometry_msgs__msg__Twist] + accelerations: list[geometry_msgs__msg__Twist] + time_from_start: builtin_interfaces__msg__Duration + __msgtype__: ClassVar[str] = 'trajectory_msgs/msg/MultiDOFJointTrajectoryPoint' + + +@dataclass +class trajectory_msgs__msg__MultiDOFJointTrajectory: + """Class for trajectory_msgs/msg/MultiDOFJointTrajectory.""" + + header: std_msgs__msg__Header + joint_names: list[str] + points: list[trajectory_msgs__msg__MultiDOFJointTrajectoryPoint] + __msgtype__: ClassVar[str] = 'trajectory_msgs/msg/MultiDOFJointTrajectory' + + +@dataclass +class vision_msgs__msg__BoundingBox2DArray: + """Class for vision_msgs/msg/BoundingBox2DArray.""" + + header: std_msgs__msg__Header + boxes: list[vision_msgs__msg__BoundingBox2D] + __msgtype__: ClassVar[str] = 'vision_msgs/msg/BoundingBox2DArray' + + +@dataclass +class vision_msgs__msg__BoundingBox3DArray: + """Class for vision_msgs/msg/BoundingBox3DArray.""" + + header: std_msgs__msg__Header + boxes: list[vision_msgs__msg__BoundingBox3D] + __msgtype__: ClassVar[str] = 'vision_msgs/msg/BoundingBox3DArray' + + +@dataclass +class vision_msgs__msg__ObjectHypothesis: + """Class for vision_msgs/msg/ObjectHypothesis.""" + + class_id: str + score: float + __msgtype__: ClassVar[str] = 'vision_msgs/msg/ObjectHypothesis' + + +@dataclass +class vision_msgs__msg__Classification: + """Class for vision_msgs/msg/Classification.""" + + header: std_msgs__msg__Header + results: list[vision_msgs__msg__ObjectHypothesis] + __msgtype__: ClassVar[str] = 'vision_msgs/msg/Classification' + + +@dataclass +class vision_msgs__msg__ObjectHypothesisWithPose: + """Class for vision_msgs/msg/ObjectHypothesisWithPose.""" + + hypothesis: vision_msgs__msg__ObjectHypothesis + pose: geometry_msgs__msg__PoseWithCovariance + __msgtype__: ClassVar[str] = 'vision_msgs/msg/ObjectHypothesisWithPose' + + +@dataclass +class vision_msgs__msg__Detection2D: + """Class for vision_msgs/msg/Detection2D.""" + + header: std_msgs__msg__Header + results: list[vision_msgs__msg__ObjectHypothesisWithPose] + bbox: vision_msgs__msg__BoundingBox2D + id: str + __msgtype__: ClassVar[str] = 'vision_msgs/msg/Detection2D' + + +@dataclass +class vision_msgs__msg__Detection2DArray: + """Class for vision_msgs/msg/Detection2DArray.""" + + header: std_msgs__msg__Header + detections: list[vision_msgs__msg__Detection2D] + __msgtype__: ClassVar[str] = 'vision_msgs/msg/Detection2DArray' + + +@dataclass +class vision_msgs__msg__Detection3D: + """Class for vision_msgs/msg/Detection3D.""" + + header: std_msgs__msg__Header + results: list[vision_msgs__msg__ObjectHypothesisWithPose] + bbox: vision_msgs__msg__BoundingBox3D + id: str + __msgtype__: ClassVar[str] = 'vision_msgs/msg/Detection3D' + + +@dataclass +class vision_msgs__msg__Detection3DArray: + """Class for vision_msgs/msg/Detection3DArray.""" + + header: std_msgs__msg__Header + detections: list[vision_msgs__msg__Detection3D] + __msgtype__: ClassVar[str] = 'vision_msgs/msg/Detection3DArray' + + +@dataclass +class vision_msgs__msg__VisionClass: + """Class for vision_msgs/msg/VisionClass.""" + + class_id: int + class_name: str + __msgtype__: ClassVar[str] = 'vision_msgs/msg/VisionClass' + + +@dataclass +class vision_msgs__msg__LabelInfo: + """Class for vision_msgs/msg/LabelInfo.""" + + header: std_msgs__msg__Header + class_map: list[vision_msgs__msg__VisionClass] + threshold: float + __msgtype__: ClassVar[str] = 'vision_msgs/msg/LabelInfo' + + +@dataclass +class vision_msgs__msg__VisionInfo: + """Class for vision_msgs/msg/VisionInfo.""" + + header: std_msgs__msg__Header + method: str + database_location: str + database_version: int + __msgtype__: ClassVar[str] = 'vision_msgs/msg/VisionInfo' + + +@dataclass +class visualization_msgs__msg__ImageMarker: + """Class for visualization_msgs/msg/ImageMarker.""" + + header: std_msgs__msg__Header + ns: str + id: int + type: int + action: int + position: geometry_msgs__msg__Point + scale: float + outline_color: std_msgs__msg__ColorRGBA + filled: int + fill_color: std_msgs__msg__ColorRGBA + lifetime: builtin_interfaces__msg__Duration + points: list[geometry_msgs__msg__Point] + outline_colors: list[std_msgs__msg__ColorRGBA] + CIRCLE: ClassVar[int] = 0 + LINE_STRIP: ClassVar[int] = 1 + LINE_LIST: ClassVar[int] = 2 + POLYGON: ClassVar[int] = 3 + POINTS: ClassVar[int] = 4 + ADD: ClassVar[int] = 0 + REMOVE: ClassVar[int] = 1 + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/ImageMarker' + + +@dataclass +class visualization_msgs__msg__MeshFile: + """Class for visualization_msgs/msg/MeshFile.""" + + filename: str + data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/MeshFile' + + +@dataclass +class visualization_msgs__msg__UVCoordinate: + """Class for visualization_msgs/msg/UVCoordinate.""" + + u: float + v: float + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/UVCoordinate' + + +@dataclass +class visualization_msgs__msg__Marker: + """Class for visualization_msgs/msg/Marker.""" + + header: std_msgs__msg__Header + ns: str + id: int + type: int + action: int + pose: geometry_msgs__msg__Pose + scale: geometry_msgs__msg__Vector3 + color: std_msgs__msg__ColorRGBA + lifetime: builtin_interfaces__msg__Duration + frame_locked: bool + points: list[geometry_msgs__msg__Point] + colors: list[std_msgs__msg__ColorRGBA] + texture_resource: str + texture: sensor_msgs__msg__CompressedImage + uv_coordinates: list[visualization_msgs__msg__UVCoordinate] + text: str + mesh_resource: str + mesh_file: visualization_msgs__msg__MeshFile + mesh_use_embedded_materials: bool + ARROW: ClassVar[int] = 0 + CUBE: ClassVar[int] = 1 + SPHERE: ClassVar[int] = 2 + CYLINDER: ClassVar[int] = 3 + LINE_STRIP: ClassVar[int] = 4 + LINE_LIST: ClassVar[int] = 5 + CUBE_LIST: ClassVar[int] = 6 + SPHERE_LIST: ClassVar[int] = 7 + POINTS: ClassVar[int] = 8 + TEXT_VIEW_FACING: ClassVar[int] = 9 + MESH_RESOURCE: ClassVar[int] = 10 + TRIANGLE_LIST: ClassVar[int] = 11 + ARROW_STRIP: ClassVar[int] = 12 + ADD: ClassVar[int] = 0 + MODIFY: ClassVar[int] = 0 + DELETE: ClassVar[int] = 2 + DELETEALL: ClassVar[int] = 3 + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/Marker' + + +@dataclass +class visualization_msgs__msg__InteractiveMarkerControl: + """Class for visualization_msgs/msg/InteractiveMarkerControl.""" + + name: str + orientation: geometry_msgs__msg__Quaternion + orientation_mode: int + interaction_mode: int + always_visible: bool + markers: list[visualization_msgs__msg__Marker] + independent_marker_orientation: bool + description: str + INHERIT: ClassVar[int] = 0 + FIXED: ClassVar[int] = 1 + VIEW_FACING: ClassVar[int] = 2 + NONE: ClassVar[int] = 0 + MENU: ClassVar[int] = 1 + BUTTON: ClassVar[int] = 2 + MOVE_AXIS: ClassVar[int] = 3 + MOVE_PLANE: ClassVar[int] = 4 + ROTATE_AXIS: ClassVar[int] = 5 + MOVE_ROTATE: ClassVar[int] = 6 + MOVE_3D: ClassVar[int] = 7 + ROTATE_3D: ClassVar[int] = 8 + MOVE_ROTATE_3D: ClassVar[int] = 9 + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarkerControl' + + +@dataclass +class visualization_msgs__msg__MenuEntry: + """Class for visualization_msgs/msg/MenuEntry.""" + + id: int + parent_id: int + title: str + command: str + command_type: int + FEEDBACK: ClassVar[int] = 0 + ROSRUN: ClassVar[int] = 1 + ROSLAUNCH: ClassVar[int] = 2 + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/MenuEntry' + + +@dataclass +class visualization_msgs__msg__InteractiveMarker: + """Class for visualization_msgs/msg/InteractiveMarker.""" + + header: std_msgs__msg__Header + pose: geometry_msgs__msg__Pose + name: str + description: str + scale: float + menu_entries: list[visualization_msgs__msg__MenuEntry] + controls: list[visualization_msgs__msg__InteractiveMarkerControl] + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarker' + + +@dataclass +class visualization_msgs__msg__InteractiveMarkerFeedback: + """Class for visualization_msgs/msg/InteractiveMarkerFeedback.""" + + header: std_msgs__msg__Header + client_id: str + marker_name: str + control_name: str + event_type: int + pose: geometry_msgs__msg__Pose + menu_entry_id: int + mouse_point: geometry_msgs__msg__Point + mouse_point_valid: bool + KEEP_ALIVE: ClassVar[int] = 0 + POSE_UPDATE: ClassVar[int] = 1 + MENU_SELECT: ClassVar[int] = 2 + BUTTON_CLICK: ClassVar[int] = 3 + MOUSE_DOWN: ClassVar[int] = 4 + MOUSE_UP: ClassVar[int] = 5 + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarkerFeedback' + + +@dataclass +class visualization_msgs__msg__InteractiveMarkerInit: + """Class for visualization_msgs/msg/InteractiveMarkerInit.""" + + server_id: str + seq_num: int + markers: list[visualization_msgs__msg__InteractiveMarker] + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarkerInit' + + +@dataclass +class visualization_msgs__msg__InteractiveMarkerPose: + """Class for visualization_msgs/msg/InteractiveMarkerPose.""" + + header: std_msgs__msg__Header + pose: geometry_msgs__msg__Pose + name: str + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarkerPose' + + +@dataclass +class visualization_msgs__msg__InteractiveMarkerUpdate: + """Class for visualization_msgs/msg/InteractiveMarkerUpdate.""" + + server_id: str + seq_num: int + type: int + markers: list[visualization_msgs__msg__InteractiveMarker] + poses: list[visualization_msgs__msg__InteractiveMarkerPose] + erases: list[str] + KEEP_ALIVE: ClassVar[int] = 0 + UPDATE: ClassVar[int] = 1 + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarkerUpdate' + + +@dataclass +class visualization_msgs__msg__MarkerArray: + """Class for visualization_msgs/msg/MarkerArray.""" + + markers: list[visualization_msgs__msg__Marker] + __msgtype__: ClassVar[str] = 'visualization_msgs/msg/MarkerArray' + + +FIELDDEFS: Typesdict = { + 'builtin_interfaces/msg/Duration': ( + [], + [ + ('sec', (T.BASE, ('int32', 0))), + ('nanosec', (T.BASE, ('uint32', 0))), + ], + ), + 'builtin_interfaces/msg/Time': ( + [], + [ + ('sec', (T.BASE, ('int32', 0))), + ('nanosec', (T.BASE, ('uint32', 0))), + ], + ), + 'std_msgs/msg/Header': ( + [], + [ + ('stamp', (T.NAME, 'builtin_interfaces/msg/Time')), + ('frame_id', (T.BASE, ('string', 0))), + ], + ), + 'vision_msgs/msg/Point2D': ( + [], + [ + ('x', (T.BASE, ('float64', 0))), + ('y', (T.BASE, ('float64', 0))), + ], + ), + 'vision_msgs/msg/Pose2D': ( + [], + [ + ('position', (T.NAME, 'vision_msgs/msg/Point2D')), + ('theta', (T.BASE, ('float64', 0))), + ], + ), + 'vision_msgs/msg/BoundingBox2D': ( + [], + [ + ('center', (T.NAME, 'vision_msgs/msg/Pose2D')), + ('size_x', (T.BASE, ('float64', 0))), + ('size_y', (T.BASE, ('float64', 0))), + ], + ), + 'dimos_msgs/msg/BoundingBox2DArray': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('boxes', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/BoundingBox2D'), 0))), + ], + ), + 'geometry_msgs/msg/Point': ( + [], + [ + ('x', (T.BASE, ('float64', 0))), + ('y', (T.BASE, ('float64', 0))), + ('z', (T.BASE, ('float64', 0))), + ], + ), + 'geometry_msgs/msg/Quaternion': ( + [], + [ + ('x', (T.BASE, ('float64', 0))), + ('y', (T.BASE, ('float64', 0))), + ('z', (T.BASE, ('float64', 0))), + ('w', (T.BASE, ('float64', 0))), + ], + ), + 'geometry_msgs/msg/Pose': ( + [], + [ + ('position', (T.NAME, 'geometry_msgs/msg/Point')), + ('orientation', (T.NAME, 'geometry_msgs/msg/Quaternion')), + ], + ), + 'geometry_msgs/msg/Vector3': ( + [], + [ + ('x', (T.BASE, ('float64', 0))), + ('y', (T.BASE, ('float64', 0))), + ('z', (T.BASE, ('float64', 0))), + ], + ), + 'vision_msgs/msg/BoundingBox3D': ( + [], + [ + ('center', (T.NAME, 'geometry_msgs/msg/Pose')), + ('size', (T.NAME, 'geometry_msgs/msg/Vector3')), + ], + ), + 'dimos_msgs/msg/BoundingBox3DArray': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('boxes', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/BoundingBox3D'), 0))), + ], + ), + 'dimos_msgs/msg/EntityMarker': ( + [], + [ + ('entity_id', (T.BASE, ('string', 0))), + ('label', (T.BASE, ('string', 0))), + ('entity_type', (T.BASE, ('string', 0))), + ('position', (T.NAME, 'geometry_msgs/msg/Point')), + ], + ), + 'dimos_msgs/msg/EntityMarkers': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('markers', (T.SEQUENCE, ((T.NAME, 'dimos_msgs/msg/EntityMarker'), 0))), + ], + ), + 'dimos_msgs/msg/GraspCandidate': ( + [], + [ + ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), + ('score', (T.BASE, ('float64', 0))), + ], + ), + 'dimos_msgs/msg/GraspCandidateArray': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('candidates', (T.SEQUENCE, ((T.NAME, 'dimos_msgs/msg/GraspCandidate'), 0))), + ], + ), + 'dimos_msgs/msg/ImuInfo': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('gyro_noise_density', (T.BASE, ('float64', 0))), + ('gyro_random_walk', (T.BASE, ('float64', 0))), + ('accel_noise_density', (T.BASE, ('float64', 0))), + ('accel_random_walk', (T.BASE, ('float64', 0))), + ('frequency', (T.BASE, ('float64', 0))), + ], + ), + 'dimos_msgs/msg/JointCommand': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('positions', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ], + ), + 'dimos_msgs/msg/LineSegment3D': ( + [], + [ + ('start', (T.NAME, 'geometry_msgs/msg/Point')), + ('end', (T.NAME, 'geometry_msgs/msg/Point')), + ('weight', (T.BASE, ('float64', 0))), + ], + ), + 'dimos_msgs/msg/LineSegments3D': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('segments', (T.SEQUENCE, ((T.NAME, 'dimos_msgs/msg/LineSegment3D'), 0))), + ], + ), + 'dimos_msgs/msg/MotorCommandArray': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('q', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('dq', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('kp', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('kd', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('tau', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ], + ), + 'dimos_msgs/msg/RobotState': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('state', (T.BASE, ('int32', 0))), + ('mode', (T.BASE, ('int32', 0))), + ('error_code', (T.BASE, ('int32', 0))), + ('warn_code', (T.BASE, ('int32', 0))), + ('cmdnum', (T.BASE, ('int32', 0))), + ('mt_brake', (T.BASE, ('int32', 0))), + ('mt_able', (T.BASE, ('int32', 0))), + ('tcp_pose', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('tcp_offset', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('joints', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ], + ), + 'dimos_msgs/msg/TrajectoryStatus': ( + [ + ('IDLE', 'uint8', 0), + ('EXECUTING', 'uint8', 1), + ('COMPLETED', 'uint8', 2), + ('ABORTED', 'uint8', 3), + ('FAULT', 'uint8', 4), + ], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('state', (T.BASE, ('uint8', 0))), + ('progress', (T.BASE, ('float64', 0))), + ('time_elapsed', (T.NAME, 'builtin_interfaces/msg/Duration')), + ('time_remaining', (T.NAME, 'builtin_interfaces/msg/Duration')), + ('error', (T.BASE, ('string', 0))), + ], + ), + 'dimos_msgs/msg/VideoStats': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('fps', (T.BASE, ('float64', 0))), + ('kbps', (T.BASE, ('float64', 0))), + ('width', (T.BASE, ('uint32', 0))), + ('height', (T.BASE, ('uint32', 0))), + ('loss_pct', (T.BASE, ('float64', 0))), + ('jitter_buffer_ms', (T.BASE, ('float64', 0))), + ('decode_ms', (T.BASE, ('float64', 0))), + ('frames_dropped', (T.BASE, ('uint64', 0))), + ('freezes', (T.BASE, ('uint64', 0))), + ('e2e_latency_ms', (T.BASE, ('float64', 0))), + ], + ), + 'foxglove_msgs/msg/CompressedVideo': ( + [], + [ + ('timestamp', (T.NAME, 'builtin_interfaces/msg/Time')), + ('frame_id', (T.BASE, ('string', 0))), + ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), + ('format', (T.BASE, ('string', 0))), + ], + ), + 'geometry_msgs/msg/Accel': ( + [], + [ + ('linear', (T.NAME, 'geometry_msgs/msg/Vector3')), + ('angular', (T.NAME, 'geometry_msgs/msg/Vector3')), + ], + ), + 'geometry_msgs/msg/AccelStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('accel', (T.NAME, 'geometry_msgs/msg/Accel')), + ], + ), + 'geometry_msgs/msg/AccelWithCovariance': ( + [], + [ + ('accel', (T.NAME, 'geometry_msgs/msg/Accel')), + ('covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 36))), + ], + ), + 'geometry_msgs/msg/AccelWithCovarianceStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('accel', (T.NAME, 'geometry_msgs/msg/AccelWithCovariance')), + ], + ), + 'geometry_msgs/msg/Inertia': ( + [], + [ + ('m', (T.BASE, ('float64', 0))), + ('com', (T.NAME, 'geometry_msgs/msg/Vector3')), + ('ixx', (T.BASE, ('float64', 0))), + ('ixy', (T.BASE, ('float64', 0))), + ('ixz', (T.BASE, ('float64', 0))), + ('iyy', (T.BASE, ('float64', 0))), + ('iyz', (T.BASE, ('float64', 0))), + ('izz', (T.BASE, ('float64', 0))), + ], + ), + 'geometry_msgs/msg/InertiaStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('inertia', (T.NAME, 'geometry_msgs/msg/Inertia')), + ], + ), + 'geometry_msgs/msg/Point32': ( + [], + [ + ('x', (T.BASE, ('float32', 0))), + ('y', (T.BASE, ('float32', 0))), + ('z', (T.BASE, ('float32', 0))), + ], + ), + 'geometry_msgs/msg/PointStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('point', (T.NAME, 'geometry_msgs/msg/Point')), + ], + ), + 'geometry_msgs/msg/Polygon': ( + [], + [ + ('points', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point32'), 0))), + ], + ), + 'geometry_msgs/msg/PolygonInstance': ( + [], + [ + ('polygon', (T.NAME, 'geometry_msgs/msg/Polygon')), + ('id', (T.BASE, ('int64', 0))), + ], + ), + 'geometry_msgs/msg/PolygonInstanceStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('polygon', (T.NAME, 'geometry_msgs/msg/PolygonInstance')), + ], + ), + 'geometry_msgs/msg/PolygonStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('polygon', (T.NAME, 'geometry_msgs/msg/Polygon')), + ], + ), + 'geometry_msgs/msg/Pose2D': ( + [], + [ + ('x', (T.BASE, ('float64', 0))), + ('y', (T.BASE, ('float64', 0))), + ('theta', (T.BASE, ('float64', 0))), + ], + ), + 'geometry_msgs/msg/PoseArray': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('poses', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Pose'), 0))), + ], + ), + 'geometry_msgs/msg/PoseStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), + ], + ), + 'geometry_msgs/msg/PoseWithCovariance': ( + [], + [ + ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), + ('covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 36))), + ], + ), + 'geometry_msgs/msg/PoseWithCovarianceStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('pose', (T.NAME, 'geometry_msgs/msg/PoseWithCovariance')), + ], + ), + 'geometry_msgs/msg/QuaternionStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('quaternion', (T.NAME, 'geometry_msgs/msg/Quaternion')), + ], + ), + 'geometry_msgs/msg/Transform': ( + [], + [ + ('translation', (T.NAME, 'geometry_msgs/msg/Vector3')), + ('rotation', (T.NAME, 'geometry_msgs/msg/Quaternion')), + ], + ), + 'geometry_msgs/msg/TransformStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('child_frame_id', (T.BASE, ('string', 0))), + ('transform', (T.NAME, 'geometry_msgs/msg/Transform')), + ], + ), + 'geometry_msgs/msg/Twist': ( + [], + [ + ('linear', (T.NAME, 'geometry_msgs/msg/Vector3')), + ('angular', (T.NAME, 'geometry_msgs/msg/Vector3')), + ], + ), + 'geometry_msgs/msg/TwistStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('twist', (T.NAME, 'geometry_msgs/msg/Twist')), + ], + ), + 'geometry_msgs/msg/TwistWithCovariance': ( + [], + [ + ('twist', (T.NAME, 'geometry_msgs/msg/Twist')), + ('covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 36))), + ], + ), + 'geometry_msgs/msg/TwistWithCovarianceStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('twist', (T.NAME, 'geometry_msgs/msg/TwistWithCovariance')), + ], + ), + 'geometry_msgs/msg/Vector3Stamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('vector', (T.NAME, 'geometry_msgs/msg/Vector3')), + ], + ), + 'geometry_msgs/msg/VelocityStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('body_frame_id', (T.BASE, ('string', 0))), + ('reference_frame_id', (T.BASE, ('string', 0))), + ('velocity', (T.NAME, 'geometry_msgs/msg/Twist')), + ], + ), + 'geometry_msgs/msg/VelocityWithCovarianceStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('body_frame_id', (T.BASE, ('string', 0))), + ('reference_frame_id', (T.BASE, ('string', 0))), + ('velocity', (T.NAME, 'geometry_msgs/msg/TwistWithCovariance')), + ], + ), + 'geometry_msgs/msg/Wrench': ( + [], + [ + ('force', (T.NAME, 'geometry_msgs/msg/Vector3')), + ('torque', (T.NAME, 'geometry_msgs/msg/Vector3')), + ], + ), + 'geometry_msgs/msg/WrenchStamped': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('wrench', (T.NAME, 'geometry_msgs/msg/Wrench')), + ], + ), + 'nav_msgs/msg/Goals': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('goals', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/PoseStamped'), 0))), + ], + ), + 'nav_msgs/msg/GridCells': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('cell_width', (T.BASE, ('float32', 0))), + ('cell_height', (T.BASE, ('float32', 0))), + ('cells', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point'), 0))), + ], + ), + 'nav_msgs/msg/MapMetaData': ( + [], + [ + ('map_load_time', (T.NAME, 'builtin_interfaces/msg/Time')), + ('resolution', (T.BASE, ('float32', 0))), + ('width', (T.BASE, ('uint32', 0))), + ('height', (T.BASE, ('uint32', 0))), + ('origin', (T.NAME, 'geometry_msgs/msg/Pose')), + ], + ), + 'nav_msgs/msg/OccupancyGrid': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('info', (T.NAME, 'nav_msgs/msg/MapMetaData')), + ('data', (T.SEQUENCE, ((T.BASE, ('int8', 0)), 0))), + ], + ), + 'nav_msgs/msg/Odometry': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('child_frame_id', (T.BASE, ('string', 0))), + ('pose', (T.NAME, 'geometry_msgs/msg/PoseWithCovariance')), + ('twist', (T.NAME, 'geometry_msgs/msg/TwistWithCovariance')), + ], + ), + 'nav_msgs/msg/Path': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('poses', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/PoseStamped'), 0))), + ], + ), + 'nav_msgs/msg/TrajectoryPoint': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), + ('velocity', (T.NAME, 'geometry_msgs/msg/Twist')), + ('acceleration', (T.NAME, 'geometry_msgs/msg/Accel')), + ('effort', (T.NAME, 'geometry_msgs/msg/Wrench')), + ], + ), + 'nav_msgs/msg/Trajectory': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('points', (T.SEQUENCE, ((T.NAME, 'nav_msgs/msg/TrajectoryPoint'), 0))), + ], + ), + 'sensor_msgs/msg/BatteryState': ( + [ + ('POWER_SUPPLY_STATUS_UNKNOWN', 'uint8', 0), + ('POWER_SUPPLY_STATUS_CHARGING', 'uint8', 1), + ('POWER_SUPPLY_STATUS_DISCHARGING', 'uint8', 2), + ('POWER_SUPPLY_STATUS_NOT_CHARGING', 'uint8', 3), + ('POWER_SUPPLY_STATUS_FULL', 'uint8', 4), + ('POWER_SUPPLY_HEALTH_UNKNOWN', 'uint8', 0), + ('POWER_SUPPLY_HEALTH_GOOD', 'uint8', 1), + ('POWER_SUPPLY_HEALTH_OVERHEAT', 'uint8', 2), + ('POWER_SUPPLY_HEALTH_DEAD', 'uint8', 3), + ('POWER_SUPPLY_HEALTH_OVERVOLTAGE', 'uint8', 4), + ('POWER_SUPPLY_HEALTH_UNSPEC_FAILURE', 'uint8', 5), + ('POWER_SUPPLY_HEALTH_COLD', 'uint8', 6), + ('POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE', 'uint8', 7), + ('POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE', 'uint8', 8), + ('POWER_SUPPLY_TECHNOLOGY_UNKNOWN', 'uint8', 0), + ('POWER_SUPPLY_TECHNOLOGY_NIMH', 'uint8', 1), + ('POWER_SUPPLY_TECHNOLOGY_LION', 'uint8', 2), + ('POWER_SUPPLY_TECHNOLOGY_LIPO', 'uint8', 3), + ('POWER_SUPPLY_TECHNOLOGY_LIFE', 'uint8', 4), + ('POWER_SUPPLY_TECHNOLOGY_NICD', 'uint8', 5), + ('POWER_SUPPLY_TECHNOLOGY_LIMN', 'uint8', 6), + ('POWER_SUPPLY_TECHNOLOGY_TERNARY', 'uint8', 7), + ('POWER_SUPPLY_TECHNOLOGY_VRLA', 'uint8', 8), + ], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('voltage', (T.BASE, ('float32', 0))), + ('temperature', (T.BASE, ('float32', 0))), + ('current', (T.BASE, ('float32', 0))), + ('charge', (T.BASE, ('float32', 0))), + ('capacity', (T.BASE, ('float32', 0))), + ('design_capacity', (T.BASE, ('float32', 0))), + ('percentage', (T.BASE, ('float32', 0))), + ('power_supply_status', (T.BASE, ('uint8', 0))), + ('power_supply_health', (T.BASE, ('uint8', 0))), + ('power_supply_technology', (T.BASE, ('uint8', 0))), + ('present', (T.BASE, ('bool', 0))), + ('cell_voltage', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ('cell_temperature', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ('location', (T.BASE, ('string', 0))), + ('serial_number', (T.BASE, ('string', 0))), + ], + ), + 'sensor_msgs/msg/RegionOfInterest': ( + [], + [ + ('x_offset', (T.BASE, ('uint32', 0))), + ('y_offset', (T.BASE, ('uint32', 0))), + ('height', (T.BASE, ('uint32', 0))), + ('width', (T.BASE, ('uint32', 0))), + ('do_rectify', (T.BASE, ('bool', 0))), + ], + ), + 'sensor_msgs/msg/CameraInfo': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('height', (T.BASE, ('uint32', 0))), + ('width', (T.BASE, ('uint32', 0))), + ('distortion_model', (T.BASE, ('string', 0))), + ('d', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('k', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), + ('r', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), + ('p', (T.ARRAY, ((T.BASE, ('float64', 0)), 12))), + ('binning_x', (T.BASE, ('uint32', 0))), + ('binning_y', (T.BASE, ('uint32', 0))), + ('roi', (T.NAME, 'sensor_msgs/msg/RegionOfInterest')), + ], + ), + 'sensor_msgs/msg/ChannelFloat32': ( + [], + [ + ('name', (T.BASE, ('string', 0))), + ('values', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ], + ), + 'sensor_msgs/msg/CompressedImage': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('format', (T.BASE, ('string', 0))), + ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), + ], + ), + 'sensor_msgs/msg/FluidPressure': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('fluid_pressure', (T.BASE, ('float64', 0))), + ('variance', (T.BASE, ('float64', 0))), + ], + ), + 'sensor_msgs/msg/Illuminance': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('illuminance', (T.BASE, ('float64', 0))), + ('variance', (T.BASE, ('float64', 0))), + ], + ), + 'sensor_msgs/msg/Image': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('height', (T.BASE, ('uint32', 0))), + ('width', (T.BASE, ('uint32', 0))), + ('encoding', (T.BASE, ('string', 0))), + ('is_bigendian', (T.BASE, ('uint8', 0))), + ('step', (T.BASE, ('uint32', 0))), + ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), + ], + ), + 'sensor_msgs/msg/Imu': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('orientation', (T.NAME, 'geometry_msgs/msg/Quaternion')), + ('orientation_covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), + ('angular_velocity', (T.NAME, 'geometry_msgs/msg/Vector3')), + ('angular_velocity_covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), + ('linear_acceleration', (T.NAME, 'geometry_msgs/msg/Vector3')), + ('linear_acceleration_covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), + ], + ), + 'sensor_msgs/msg/JointState': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('name', (T.SEQUENCE, ((T.BASE, ('string', 0)), 0))), + ('position', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('velocity', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('effort', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ], + ), + 'sensor_msgs/msg/Joy': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('axes', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ('buttons', (T.SEQUENCE, ((T.BASE, ('int32', 0)), 0))), + ], + ), + 'sensor_msgs/msg/JoyFeedback': ( + [ + ('TYPE_LED', 'uint8', 0), + ('TYPE_RUMBLE', 'uint8', 1), + ('TYPE_BUZZER', 'uint8', 2), + ], + [ + ('type', (T.BASE, ('uint8', 0))), + ('id', (T.BASE, ('uint8', 0))), + ('intensity', (T.BASE, ('float32', 0))), + ], + ), + 'sensor_msgs/msg/JoyFeedbackArray': ( + [], + [ + ('array', (T.SEQUENCE, ((T.NAME, 'sensor_msgs/msg/JoyFeedback'), 0))), + ], + ), + 'sensor_msgs/msg/LaserEcho': ( + [], + [ + ('echoes', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ], + ), + 'sensor_msgs/msg/LaserScan': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('angle_min', (T.BASE, ('float32', 0))), + ('angle_max', (T.BASE, ('float32', 0))), + ('angle_increment', (T.BASE, ('float32', 0))), + ('time_increment', (T.BASE, ('float32', 0))), + ('scan_time', (T.BASE, ('float32', 0))), + ('range_min', (T.BASE, ('float32', 0))), + ('range_max', (T.BASE, ('float32', 0))), + ('ranges', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ('intensities', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ], + ), + 'sensor_msgs/msg/MagneticField': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('magnetic_field', (T.NAME, 'geometry_msgs/msg/Vector3')), + ('magnetic_field_covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), + ], + ), + 'sensor_msgs/msg/MultiDOFJointState': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('joint_names', (T.SEQUENCE, ((T.BASE, ('string', 0)), 0))), + ('transforms', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Transform'), 0))), + ('twist', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Twist'), 0))), + ('wrench', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Wrench'), 0))), + ], + ), + 'sensor_msgs/msg/MultiEchoLaserScan': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('angle_min', (T.BASE, ('float32', 0))), + ('angle_max', (T.BASE, ('float32', 0))), + ('angle_increment', (T.BASE, ('float32', 0))), + ('time_increment', (T.BASE, ('float32', 0))), + ('scan_time', (T.BASE, ('float32', 0))), + ('range_min', (T.BASE, ('float32', 0))), + ('range_max', (T.BASE, ('float32', 0))), + ('ranges', (T.SEQUENCE, ((T.NAME, 'sensor_msgs/msg/LaserEcho'), 0))), + ('intensities', (T.SEQUENCE, ((T.NAME, 'sensor_msgs/msg/LaserEcho'), 0))), + ], + ), + 'sensor_msgs/msg/NavSatStatus': ( + [ + ('STATUS_UNKNOWN', 'int8', -2), + ('STATUS_NO_FIX', 'int8', -1), + ('STATUS_FIX', 'int8', 0), + ('STATUS_SBAS_FIX', 'int8', 1), + ('STATUS_GBAS_FIX', 'int8', 2), + ('SERVICE_UNKNOWN', 'uint16', 0), + ('SERVICE_GPS', 'uint16', 1), + ('SERVICE_GLONASS', 'uint16', 2), + ('SERVICE_COMPASS', 'uint16', 4), + ('SERVICE_GALILEO', 'uint16', 8), + ], + [ + ('status', (T.BASE, ('int8', 0))), + ('service', (T.BASE, ('uint16', 0))), + ], + ), + 'sensor_msgs/msg/NavSatFix': ( + [ + ('COVARIANCE_TYPE_UNKNOWN', 'uint8', 0), + ('COVARIANCE_TYPE_APPROXIMATED', 'uint8', 1), + ('COVARIANCE_TYPE_DIAGONAL_KNOWN', 'uint8', 2), + ('COVARIANCE_TYPE_KNOWN', 'uint8', 3), + ], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('status', (T.NAME, 'sensor_msgs/msg/NavSatStatus')), + ('latitude', (T.BASE, ('float64', 0))), + ('longitude', (T.BASE, ('float64', 0))), + ('altitude', (T.BASE, ('float64', 0))), + ('position_covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), + ('position_covariance_type', (T.BASE, ('uint8', 0))), + ], + ), + 'sensor_msgs/msg/PointCloud': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('points', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point32'), 0))), + ('channels', (T.SEQUENCE, ((T.NAME, 'sensor_msgs/msg/ChannelFloat32'), 0))), + ], + ), + 'sensor_msgs/msg/PointField': ( + [ + ('INT8', 'uint8', 1), + ('UINT8', 'uint8', 2), + ('INT16', 'uint8', 3), + ('UINT16', 'uint8', 4), + ('INT32', 'uint8', 5), + ('UINT32', 'uint8', 6), + ('FLOAT32', 'uint8', 7), + ('FLOAT64', 'uint8', 8), + ], + [ + ('name', (T.BASE, ('string', 0))), + ('offset', (T.BASE, ('uint32', 0))), + ('datatype', (T.BASE, ('uint8', 0))), + ('count', (T.BASE, ('uint32', 0))), + ], + ), + 'sensor_msgs/msg/PointCloud2': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('height', (T.BASE, ('uint32', 0))), + ('width', (T.BASE, ('uint32', 0))), + ('fields', (T.SEQUENCE, ((T.NAME, 'sensor_msgs/msg/PointField'), 0))), + ('is_bigendian', (T.BASE, ('bool', 0))), + ('point_step', (T.BASE, ('uint32', 0))), + ('row_step', (T.BASE, ('uint32', 0))), + ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), + ('is_dense', (T.BASE, ('bool', 0))), + ], + ), + 'sensor_msgs/msg/Range': ( + [ + ('ULTRASOUND', 'uint8', 0), + ('INFRARED', 'uint8', 1), + ], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('radiation_type', (T.BASE, ('uint8', 0))), + ('field_of_view', (T.BASE, ('float32', 0))), + ('min_range', (T.BASE, ('float32', 0))), + ('max_range', (T.BASE, ('float32', 0))), + ('range', (T.BASE, ('float32', 0))), + ('variance', (T.BASE, ('float32', 0))), + ], + ), + 'sensor_msgs/msg/RelativeHumidity': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('relative_humidity', (T.BASE, ('float64', 0))), + ('variance', (T.BASE, ('float64', 0))), + ], + ), + 'sensor_msgs/msg/Temperature': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('temperature', (T.BASE, ('float64', 0))), + ('variance', (T.BASE, ('float64', 0))), + ], + ), + 'sensor_msgs/msg/TimeReference': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('time_ref', (T.NAME, 'builtin_interfaces/msg/Time')), + ('source', (T.BASE, ('string', 0))), + ], + ), + 'shape_msgs/msg/MeshTriangle': ( + [], + [ + ('vertex_indices', (T.ARRAY, ((T.BASE, ('uint32', 0)), 3))), + ], + ), + 'shape_msgs/msg/Mesh': ( + [], + [ + ('triangles', (T.SEQUENCE, ((T.NAME, 'shape_msgs/msg/MeshTriangle'), 0))), + ('vertices', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point'), 0))), + ], + ), + 'shape_msgs/msg/Plane': ( + [], + [ + ('coef', (T.ARRAY, ((T.BASE, ('float64', 0)), 4))), + ], + ), + 'shape_msgs/msg/SolidPrimitive': ( + [ + ('BOX', 'uint8', 1), + ('SPHERE', 'uint8', 2), + ('CYLINDER', 'uint8', 3), + ('CONE', 'uint8', 4), + ('PRISM', 'uint8', 5), + ('BOX_X', 'uint8', 0), + ('BOX_Y', 'uint8', 1), + ('BOX_Z', 'uint8', 2), + ('SPHERE_RADIUS', 'uint8', 0), + ('CYLINDER_HEIGHT', 'uint8', 0), + ('CYLINDER_RADIUS', 'uint8', 1), + ('CONE_HEIGHT', 'uint8', 0), + ('CONE_RADIUS', 'uint8', 1), + ('PRISM_HEIGHT', 'uint8', 0), + ], + [ + ('type', (T.BASE, ('uint8', 0))), + ('dimensions', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 3))), + ('polygon', (T.NAME, 'geometry_msgs/msg/Polygon')), + ], + ), + 'std_msgs/msg/Bool': ( + [], + [ + ('data', (T.BASE, ('bool', 0))), + ], + ), + 'std_msgs/msg/Byte': ( + [], + [ + ('data', (T.BASE, ('byte', 0))), + ], + ), + 'std_msgs/msg/MultiArrayDimension': ( + [], + [ + ('label', (T.BASE, ('string', 0))), + ('size', (T.BASE, ('uint32', 0))), + ('stride', (T.BASE, ('uint32', 0))), + ], + ), + 'std_msgs/msg/MultiArrayLayout': ( + [], + [ + ('dim', (T.SEQUENCE, ((T.NAME, 'std_msgs/msg/MultiArrayDimension'), 0))), + ('data_offset', (T.BASE, ('uint32', 0))), + ], + ), + 'std_msgs/msg/ByteMultiArray': ( + [], + [ + ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), + ('data', (T.SEQUENCE, ((T.BASE, ('byte', 0)), 0))), + ], + ), + 'std_msgs/msg/Char': ( + [], + [ + ('data', (T.BASE, ('char', 0))), + ], + ), + 'std_msgs/msg/ColorRGBA': ( + [], + [ + ('r', (T.BASE, ('float32', 0))), + ('g', (T.BASE, ('float32', 0))), + ('b', (T.BASE, ('float32', 0))), + ('a', (T.BASE, ('float32', 0))), + ], + ), + 'std_msgs/msg/Empty': ( + [], + [ + ('structure_needs_at_least_one_member', (T.BASE, ('uint8', 0))), + ], + ), + 'std_msgs/msg/Float32': ( + [], + [ + ('data', (T.BASE, ('float32', 0))), + ], + ), + 'std_msgs/msg/Float32MultiArray': ( + [], + [ + ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), + ('data', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ], + ), + 'std_msgs/msg/Float64': ( + [], + [ + ('data', (T.BASE, ('float64', 0))), + ], + ), + 'std_msgs/msg/Float64MultiArray': ( + [], + [ + ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), + ('data', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ], + ), + 'std_msgs/msg/Int16': ( + [], + [ + ('data', (T.BASE, ('int16', 0))), + ], + ), + 'std_msgs/msg/Int16MultiArray': ( + [], + [ + ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), + ('data', (T.SEQUENCE, ((T.BASE, ('int16', 0)), 0))), + ], + ), + 'std_msgs/msg/Int32': ( + [], + [ + ('data', (T.BASE, ('int32', 0))), + ], + ), + 'std_msgs/msg/Int32MultiArray': ( + [], + [ + ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), + ('data', (T.SEQUENCE, ((T.BASE, ('int32', 0)), 0))), + ], + ), + 'std_msgs/msg/Int64': ( + [], + [ + ('data', (T.BASE, ('int64', 0))), + ], + ), + 'std_msgs/msg/Int64MultiArray': ( + [], + [ + ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), + ('data', (T.SEQUENCE, ((T.BASE, ('int64', 0)), 0))), + ], + ), + 'std_msgs/msg/Int8': ( + [], + [ + ('data', (T.BASE, ('int8', 0))), + ], + ), + 'std_msgs/msg/Int8MultiArray': ( + [], + [ + ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), + ('data', (T.SEQUENCE, ((T.BASE, ('int8', 0)), 0))), + ], + ), + 'std_msgs/msg/String': ( + [], + [ + ('data', (T.BASE, ('string', 0))), + ], + ), + 'std_msgs/msg/UInt16': ( + [], + [ + ('data', (T.BASE, ('uint16', 0))), + ], + ), + 'std_msgs/msg/UInt16MultiArray': ( + [], + [ + ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), + ('data', (T.SEQUENCE, ((T.BASE, ('uint16', 0)), 0))), + ], + ), + 'std_msgs/msg/UInt32': ( + [], + [ + ('data', (T.BASE, ('uint32', 0))), + ], + ), + 'std_msgs/msg/UInt32MultiArray': ( + [], + [ + ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), + ('data', (T.SEQUENCE, ((T.BASE, ('uint32', 0)), 0))), + ], + ), + 'std_msgs/msg/UInt64': ( + [], + [ + ('data', (T.BASE, ('uint64', 0))), + ], + ), + 'std_msgs/msg/UInt64MultiArray': ( + [], + [ + ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), + ('data', (T.SEQUENCE, ((T.BASE, ('uint64', 0)), 0))), + ], + ), + 'std_msgs/msg/UInt8': ( + [], + [ + ('data', (T.BASE, ('uint8', 0))), + ], + ), + 'std_msgs/msg/UInt8MultiArray': ( + [], + [ + ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), + ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), + ], + ), + 'tf2_msgs/msg/TF2Error': ( + [ + ('NO_ERROR', 'uint8', 0), + ('LOOKUP_ERROR', 'uint8', 1), + ('CONNECTIVITY_ERROR', 'uint8', 2), + ('EXTRAPOLATION_ERROR', 'uint8', 3), + ('INVALID_ARGUMENT_ERROR', 'uint8', 4), + ('TIMEOUT_ERROR', 'uint8', 5), + ('TRANSFORM_ERROR', 'uint8', 6), + ], + [ + ('error', (T.BASE, ('uint8', 0))), + ('error_string', (T.BASE, ('string', 0))), + ], + ), + 'tf2_msgs/msg/TFMessage': ( + [], + [ + ('transforms', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/TransformStamped'), 0))), + ], + ), + 'trajectory_msgs/msg/JointTrajectoryPoint': ( + [], + [ + ('positions', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('velocities', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('accelerations', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('effort', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ('time_from_start', (T.NAME, 'builtin_interfaces/msg/Duration')), + ], + ), + 'trajectory_msgs/msg/JointTrajectory': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('joint_names', (T.SEQUENCE, ((T.BASE, ('string', 0)), 0))), + ('points', (T.SEQUENCE, ((T.NAME, 'trajectory_msgs/msg/JointTrajectoryPoint'), 0))), + ], + ), + 'trajectory_msgs/msg/MultiDOFJointTrajectoryPoint': ( + [], + [ + ('transforms', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Transform'), 0))), + ('velocities', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Twist'), 0))), + ('accelerations', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Twist'), 0))), + ('time_from_start', (T.NAME, 'builtin_interfaces/msg/Duration')), + ], + ), + 'trajectory_msgs/msg/MultiDOFJointTrajectory': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('joint_names', (T.SEQUENCE, ((T.BASE, ('string', 0)), 0))), + ('points', (T.SEQUENCE, ((T.NAME, 'trajectory_msgs/msg/MultiDOFJointTrajectoryPoint'), 0))), + ], + ), + 'vision_msgs/msg/BoundingBox2DArray': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('boxes', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/BoundingBox2D'), 0))), + ], + ), + 'vision_msgs/msg/BoundingBox3DArray': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('boxes', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/BoundingBox3D'), 0))), + ], + ), + 'vision_msgs/msg/ObjectHypothesis': ( + [], + [ + ('class_id', (T.BASE, ('string', 0))), + ('score', (T.BASE, ('float64', 0))), + ], + ), + 'vision_msgs/msg/Classification': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('results', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/ObjectHypothesis'), 0))), + ], + ), + 'vision_msgs/msg/ObjectHypothesisWithPose': ( + [], + [ + ('hypothesis', (T.NAME, 'vision_msgs/msg/ObjectHypothesis')), + ('pose', (T.NAME, 'geometry_msgs/msg/PoseWithCovariance')), + ], + ), + 'vision_msgs/msg/Detection2D': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('results', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/ObjectHypothesisWithPose'), 0))), + ('bbox', (T.NAME, 'vision_msgs/msg/BoundingBox2D')), + ('id', (T.BASE, ('string', 0))), + ], + ), + 'vision_msgs/msg/Detection2DArray': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('detections', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/Detection2D'), 0))), + ], + ), + 'vision_msgs/msg/Detection3D': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('results', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/ObjectHypothesisWithPose'), 0))), + ('bbox', (T.NAME, 'vision_msgs/msg/BoundingBox3D')), + ('id', (T.BASE, ('string', 0))), + ], + ), + 'vision_msgs/msg/Detection3DArray': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('detections', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/Detection3D'), 0))), + ], + ), + 'vision_msgs/msg/VisionClass': ( + [], + [ + ('class_id', (T.BASE, ('uint16', 0))), + ('class_name', (T.BASE, ('string', 0))), + ], + ), + 'vision_msgs/msg/LabelInfo': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('class_map', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/VisionClass'), 0))), + ('threshold', (T.BASE, ('float32', 0))), + ], + ), + 'vision_msgs/msg/VisionInfo': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('method', (T.BASE, ('string', 0))), + ('database_location', (T.BASE, ('string', 0))), + ('database_version', (T.BASE, ('int32', 0))), + ], + ), + 'visualization_msgs/msg/ImageMarker': ( + [ + ('CIRCLE', 'int32', 0), + ('LINE_STRIP', 'int32', 1), + ('LINE_LIST', 'int32', 2), + ('POLYGON', 'int32', 3), + ('POINTS', 'int32', 4), + ('ADD', 'int32', 0), + ('REMOVE', 'int32', 1), + ], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('ns', (T.BASE, ('string', 0))), + ('id', (T.BASE, ('int32', 0))), + ('type', (T.BASE, ('int32', 0))), + ('action', (T.BASE, ('int32', 0))), + ('position', (T.NAME, 'geometry_msgs/msg/Point')), + ('scale', (T.BASE, ('float32', 0))), + ('outline_color', (T.NAME, 'std_msgs/msg/ColorRGBA')), + ('filled', (T.BASE, ('uint8', 0))), + ('fill_color', (T.NAME, 'std_msgs/msg/ColorRGBA')), + ('lifetime', (T.NAME, 'builtin_interfaces/msg/Duration')), + ('points', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point'), 0))), + ('outline_colors', (T.SEQUENCE, ((T.NAME, 'std_msgs/msg/ColorRGBA'), 0))), + ], + ), + 'visualization_msgs/msg/MeshFile': ( + [], + [ + ('filename', (T.BASE, ('string', 0))), + ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), + ], + ), + 'visualization_msgs/msg/UVCoordinate': ( + [], + [ + ('u', (T.BASE, ('float32', 0))), + ('v', (T.BASE, ('float32', 0))), + ], + ), + 'visualization_msgs/msg/Marker': ( + [ + ('ARROW', 'int32', 0), + ('CUBE', 'int32', 1), + ('SPHERE', 'int32', 2), + ('CYLINDER', 'int32', 3), + ('LINE_STRIP', 'int32', 4), + ('LINE_LIST', 'int32', 5), + ('CUBE_LIST', 'int32', 6), + ('SPHERE_LIST', 'int32', 7), + ('POINTS', 'int32', 8), + ('TEXT_VIEW_FACING', 'int32', 9), + ('MESH_RESOURCE', 'int32', 10), + ('TRIANGLE_LIST', 'int32', 11), + ('ARROW_STRIP', 'int32', 12), + ('ADD', 'int32', 0), + ('MODIFY', 'int32', 0), + ('DELETE', 'int32', 2), + ('DELETEALL', 'int32', 3), + ], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('ns', (T.BASE, ('string', 0))), + ('id', (T.BASE, ('int32', 0))), + ('type', (T.BASE, ('int32', 0))), + ('action', (T.BASE, ('int32', 0))), + ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), + ('scale', (T.NAME, 'geometry_msgs/msg/Vector3')), + ('color', (T.NAME, 'std_msgs/msg/ColorRGBA')), + ('lifetime', (T.NAME, 'builtin_interfaces/msg/Duration')), + ('frame_locked', (T.BASE, ('bool', 0))), + ('points', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point'), 0))), + ('colors', (T.SEQUENCE, ((T.NAME, 'std_msgs/msg/ColorRGBA'), 0))), + ('texture_resource', (T.BASE, ('string', 0))), + ('texture', (T.NAME, 'sensor_msgs/msg/CompressedImage')), + ('uv_coordinates', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/UVCoordinate'), 0))), + ('text', (T.BASE, ('string', 0))), + ('mesh_resource', (T.BASE, ('string', 0))), + ('mesh_file', (T.NAME, 'visualization_msgs/msg/MeshFile')), + ('mesh_use_embedded_materials', (T.BASE, ('bool', 0))), + ], + ), + 'visualization_msgs/msg/InteractiveMarkerControl': ( + [ + ('INHERIT', 'uint8', 0), + ('FIXED', 'uint8', 1), + ('VIEW_FACING', 'uint8', 2), + ('NONE', 'uint8', 0), + ('MENU', 'uint8', 1), + ('BUTTON', 'uint8', 2), + ('MOVE_AXIS', 'uint8', 3), + ('MOVE_PLANE', 'uint8', 4), + ('ROTATE_AXIS', 'uint8', 5), + ('MOVE_ROTATE', 'uint8', 6), + ('MOVE_3D', 'uint8', 7), + ('ROTATE_3D', 'uint8', 8), + ('MOVE_ROTATE_3D', 'uint8', 9), + ], + [ + ('name', (T.BASE, ('string', 0))), + ('orientation', (T.NAME, 'geometry_msgs/msg/Quaternion')), + ('orientation_mode', (T.BASE, ('uint8', 0))), + ('interaction_mode', (T.BASE, ('uint8', 0))), + ('always_visible', (T.BASE, ('bool', 0))), + ('markers', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/Marker'), 0))), + ('independent_marker_orientation', (T.BASE, ('bool', 0))), + ('description', (T.BASE, ('string', 0))), + ], + ), + 'visualization_msgs/msg/MenuEntry': ( + [ + ('FEEDBACK', 'uint8', 0), + ('ROSRUN', 'uint8', 1), + ('ROSLAUNCH', 'uint8', 2), + ], + [ + ('id', (T.BASE, ('uint32', 0))), + ('parent_id', (T.BASE, ('uint32', 0))), + ('title', (T.BASE, ('string', 0))), + ('command', (T.BASE, ('string', 0))), + ('command_type', (T.BASE, ('uint8', 0))), + ], + ), + 'visualization_msgs/msg/InteractiveMarker': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), + ('name', (T.BASE, ('string', 0))), + ('description', (T.BASE, ('string', 0))), + ('scale', (T.BASE, ('float32', 0))), + ('menu_entries', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/MenuEntry'), 0))), + ('controls', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/InteractiveMarkerControl'), 0))), + ], + ), + 'visualization_msgs/msg/InteractiveMarkerFeedback': ( + [ + ('KEEP_ALIVE', 'uint8', 0), + ('POSE_UPDATE', 'uint8', 1), + ('MENU_SELECT', 'uint8', 2), + ('BUTTON_CLICK', 'uint8', 3), + ('MOUSE_DOWN', 'uint8', 4), + ('MOUSE_UP', 'uint8', 5), + ], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('client_id', (T.BASE, ('string', 0))), + ('marker_name', (T.BASE, ('string', 0))), + ('control_name', (T.BASE, ('string', 0))), + ('event_type', (T.BASE, ('uint8', 0))), + ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), + ('menu_entry_id', (T.BASE, ('uint32', 0))), + ('mouse_point', (T.NAME, 'geometry_msgs/msg/Point')), + ('mouse_point_valid', (T.BASE, ('bool', 0))), + ], + ), + 'visualization_msgs/msg/InteractiveMarkerInit': ( + [], + [ + ('server_id', (T.BASE, ('string', 0))), + ('seq_num', (T.BASE, ('uint64', 0))), + ('markers', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/InteractiveMarker'), 0))), + ], + ), + 'visualization_msgs/msg/InteractiveMarkerPose': ( + [], + [ + ('header', (T.NAME, 'std_msgs/msg/Header')), + ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), + ('name', (T.BASE, ('string', 0))), + ], + ), + 'visualization_msgs/msg/InteractiveMarkerUpdate': ( + [ + ('KEEP_ALIVE', 'uint8', 0), + ('UPDATE', 'uint8', 1), + ], + [ + ('server_id', (T.BASE, ('string', 0))), + ('seq_num', (T.BASE, ('uint64', 0))), + ('type', (T.BASE, ('uint8', 0))), + ('markers', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/InteractiveMarker'), 0))), + ('poses', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/InteractiveMarkerPose'), 0))), + ('erases', (T.SEQUENCE, ((T.BASE, ('string', 0)), 0))), + ], + ), + 'visualization_msgs/msg/MarkerArray': ( + [], + [ + ('markers', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/Marker'), 0))), + ], + ), +} + diff --git a/packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi new file mode 100644 index 00000000000..1eb4aa66ee0 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi @@ -0,0 +1,3 @@ +__all__ = ['Duration', 'Time'] +from ..._types import builtin_interfaces__msg__Duration as Duration +from ..._types import builtin_interfaces__msg__Time as Time diff --git a/packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi new file mode 100644 index 00000000000..63aa855140d --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi @@ -0,0 +1,15 @@ +__all__ = ['BoundingBox2DArray', 'BoundingBox3DArray', 'EntityMarker', 'EntityMarkers', 'GraspCandidate', 'GraspCandidateArray', 'ImuInfo', 'JointCommand', 'LineSegment3D', 'LineSegments3D', 'MotorCommandArray', 'RobotState', 'TrajectoryStatus', 'VideoStats'] +from ..._types import dimos_msgs__msg__BoundingBox2DArray as BoundingBox2DArray +from ..._types import dimos_msgs__msg__BoundingBox3DArray as BoundingBox3DArray +from ..._types import dimos_msgs__msg__EntityMarker as EntityMarker +from ..._types import dimos_msgs__msg__EntityMarkers as EntityMarkers +from ..._types import dimos_msgs__msg__GraspCandidate as GraspCandidate +from ..._types import dimos_msgs__msg__GraspCandidateArray as GraspCandidateArray +from ..._types import dimos_msgs__msg__ImuInfo as ImuInfo +from ..._types import dimos_msgs__msg__JointCommand as JointCommand +from ..._types import dimos_msgs__msg__LineSegment3D as LineSegment3D +from ..._types import dimos_msgs__msg__LineSegments3D as LineSegments3D +from ..._types import dimos_msgs__msg__MotorCommandArray as MotorCommandArray +from ..._types import dimos_msgs__msg__RobotState as RobotState +from ..._types import dimos_msgs__msg__TrajectoryStatus as TrajectoryStatus +from ..._types import dimos_msgs__msg__VideoStats as VideoStats diff --git a/packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi new file mode 100644 index 00000000000..c6eaf3c2003 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi @@ -0,0 +1,2 @@ +__all__ = ['CompressedVideo'] +from ..._types import foxglove_msgs__msg__CompressedVideo as CompressedVideo diff --git a/packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi new file mode 100644 index 00000000000..ca37dc02977 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi @@ -0,0 +1,34 @@ +__all__ = ['Point', 'Quaternion', 'Pose', 'Vector3', 'Accel', 'AccelStamped', 'AccelWithCovariance', 'AccelWithCovarianceStamped', 'Inertia', 'InertiaStamped', 'Point32', 'PointStamped', 'Polygon', 'PolygonInstance', 'PolygonInstanceStamped', 'PolygonStamped', 'Pose2D', 'PoseArray', 'PoseStamped', 'PoseWithCovariance', 'PoseWithCovarianceStamped', 'QuaternionStamped', 'Transform', 'TransformStamped', 'Twist', 'TwistStamped', 'TwistWithCovariance', 'TwistWithCovarianceStamped', 'Vector3Stamped', 'VelocityStamped', 'VelocityWithCovarianceStamped', 'Wrench', 'WrenchStamped'] +from ..._types import geometry_msgs__msg__Point as Point +from ..._types import geometry_msgs__msg__Quaternion as Quaternion +from ..._types import geometry_msgs__msg__Pose as Pose +from ..._types import geometry_msgs__msg__Vector3 as Vector3 +from ..._types import geometry_msgs__msg__Accel as Accel +from ..._types import geometry_msgs__msg__AccelStamped as AccelStamped +from ..._types import geometry_msgs__msg__AccelWithCovariance as AccelWithCovariance +from ..._types import geometry_msgs__msg__AccelWithCovarianceStamped as AccelWithCovarianceStamped +from ..._types import geometry_msgs__msg__Inertia as Inertia +from ..._types import geometry_msgs__msg__InertiaStamped as InertiaStamped +from ..._types import geometry_msgs__msg__Point32 as Point32 +from ..._types import geometry_msgs__msg__PointStamped as PointStamped +from ..._types import geometry_msgs__msg__Polygon as Polygon +from ..._types import geometry_msgs__msg__PolygonInstance as PolygonInstance +from ..._types import geometry_msgs__msg__PolygonInstanceStamped as PolygonInstanceStamped +from ..._types import geometry_msgs__msg__PolygonStamped as PolygonStamped +from ..._types import geometry_msgs__msg__Pose2D as Pose2D +from ..._types import geometry_msgs__msg__PoseArray as PoseArray +from ..._types import geometry_msgs__msg__PoseStamped as PoseStamped +from ..._types import geometry_msgs__msg__PoseWithCovariance as PoseWithCovariance +from ..._types import geometry_msgs__msg__PoseWithCovarianceStamped as PoseWithCovarianceStamped +from ..._types import geometry_msgs__msg__QuaternionStamped as QuaternionStamped +from ..._types import geometry_msgs__msg__Transform as Transform +from ..._types import geometry_msgs__msg__TransformStamped as TransformStamped +from ..._types import geometry_msgs__msg__Twist as Twist +from ..._types import geometry_msgs__msg__TwistStamped as TwistStamped +from ..._types import geometry_msgs__msg__TwistWithCovariance as TwistWithCovariance +from ..._types import geometry_msgs__msg__TwistWithCovarianceStamped as TwistWithCovarianceStamped +from ..._types import geometry_msgs__msg__Vector3Stamped as Vector3Stamped +from ..._types import geometry_msgs__msg__VelocityStamped as VelocityStamped +from ..._types import geometry_msgs__msg__VelocityWithCovarianceStamped as VelocityWithCovarianceStamped +from ..._types import geometry_msgs__msg__Wrench as Wrench +from ..._types import geometry_msgs__msg__WrenchStamped as WrenchStamped diff --git a/packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi new file mode 100644 index 00000000000..a029ed23155 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi @@ -0,0 +1,9 @@ +__all__ = ['Goals', 'GridCells', 'MapMetaData', 'OccupancyGrid', 'Odometry', 'Path', 'TrajectoryPoint', 'Trajectory'] +from ..._types import nav_msgs__msg__Goals as Goals +from ..._types import nav_msgs__msg__GridCells as GridCells +from ..._types import nav_msgs__msg__MapMetaData as MapMetaData +from ..._types import nav_msgs__msg__OccupancyGrid as OccupancyGrid +from ..._types import nav_msgs__msg__Odometry as Odometry +from ..._types import nav_msgs__msg__Path as Path +from ..._types import nav_msgs__msg__TrajectoryPoint as TrajectoryPoint +from ..._types import nav_msgs__msg__Trajectory as Trajectory diff --git a/packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi new file mode 100644 index 00000000000..5a4747315a0 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi @@ -0,0 +1,28 @@ +__all__ = ['BatteryState', 'RegionOfInterest', 'CameraInfo', 'ChannelFloat32', 'CompressedImage', 'FluidPressure', 'Illuminance', 'Image', 'Imu', 'JointState', 'Joy', 'JoyFeedback', 'JoyFeedbackArray', 'LaserEcho', 'LaserScan', 'MagneticField', 'MultiDOFJointState', 'MultiEchoLaserScan', 'NavSatStatus', 'NavSatFix', 'PointCloud', 'PointField', 'PointCloud2', 'Range', 'RelativeHumidity', 'Temperature', 'TimeReference'] +from ..._types import sensor_msgs__msg__BatteryState as BatteryState +from ..._types import sensor_msgs__msg__RegionOfInterest as RegionOfInterest +from ..._types import sensor_msgs__msg__CameraInfo as CameraInfo +from ..._types import sensor_msgs__msg__ChannelFloat32 as ChannelFloat32 +from ..._types import sensor_msgs__msg__CompressedImage as CompressedImage +from ..._types import sensor_msgs__msg__FluidPressure as FluidPressure +from ..._types import sensor_msgs__msg__Illuminance as Illuminance +from ..._types import sensor_msgs__msg__Image as Image +from ..._types import sensor_msgs__msg__Imu as Imu +from ..._types import sensor_msgs__msg__JointState as JointState +from ..._types import sensor_msgs__msg__Joy as Joy +from ..._types import sensor_msgs__msg__JoyFeedback as JoyFeedback +from ..._types import sensor_msgs__msg__JoyFeedbackArray as JoyFeedbackArray +from ..._types import sensor_msgs__msg__LaserEcho as LaserEcho +from ..._types import sensor_msgs__msg__LaserScan as LaserScan +from ..._types import sensor_msgs__msg__MagneticField as MagneticField +from ..._types import sensor_msgs__msg__MultiDOFJointState as MultiDOFJointState +from ..._types import sensor_msgs__msg__MultiEchoLaserScan as MultiEchoLaserScan +from ..._types import sensor_msgs__msg__NavSatStatus as NavSatStatus +from ..._types import sensor_msgs__msg__NavSatFix as NavSatFix +from ..._types import sensor_msgs__msg__PointCloud as PointCloud +from ..._types import sensor_msgs__msg__PointField as PointField +from ..._types import sensor_msgs__msg__PointCloud2 as PointCloud2 +from ..._types import sensor_msgs__msg__Range as Range +from ..._types import sensor_msgs__msg__RelativeHumidity as RelativeHumidity +from ..._types import sensor_msgs__msg__Temperature as Temperature +from ..._types import sensor_msgs__msg__TimeReference as TimeReference diff --git a/packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi new file mode 100644 index 00000000000..ac6f552be2b --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi @@ -0,0 +1,5 @@ +__all__ = ['MeshTriangle', 'Mesh', 'Plane', 'SolidPrimitive'] +from ..._types import shape_msgs__msg__MeshTriangle as MeshTriangle +from ..._types import shape_msgs__msg__Mesh as Mesh +from ..._types import shape_msgs__msg__Plane as Plane +from ..._types import shape_msgs__msg__SolidPrimitive as SolidPrimitive diff --git a/packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi new file mode 100644 index 00000000000..11eb8ad20cf --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi @@ -0,0 +1,31 @@ +__all__ = ['Header', 'Bool', 'Byte', 'MultiArrayDimension', 'MultiArrayLayout', 'ByteMultiArray', 'Char', 'ColorRGBA', 'Empty', 'Float32', 'Float32MultiArray', 'Float64', 'Float64MultiArray', 'Int16', 'Int16MultiArray', 'Int32', 'Int32MultiArray', 'Int64', 'Int64MultiArray', 'Int8', 'Int8MultiArray', 'String', 'UInt16', 'UInt16MultiArray', 'UInt32', 'UInt32MultiArray', 'UInt64', 'UInt64MultiArray', 'UInt8', 'UInt8MultiArray'] +from ..._types import std_msgs__msg__Header as Header +from ..._types import std_msgs__msg__Bool as Bool +from ..._types import std_msgs__msg__Byte as Byte +from ..._types import std_msgs__msg__MultiArrayDimension as MultiArrayDimension +from ..._types import std_msgs__msg__MultiArrayLayout as MultiArrayLayout +from ..._types import std_msgs__msg__ByteMultiArray as ByteMultiArray +from ..._types import std_msgs__msg__Char as Char +from ..._types import std_msgs__msg__ColorRGBA as ColorRGBA +from ..._types import std_msgs__msg__Empty as Empty +from ..._types import std_msgs__msg__Float32 as Float32 +from ..._types import std_msgs__msg__Float32MultiArray as Float32MultiArray +from ..._types import std_msgs__msg__Float64 as Float64 +from ..._types import std_msgs__msg__Float64MultiArray as Float64MultiArray +from ..._types import std_msgs__msg__Int16 as Int16 +from ..._types import std_msgs__msg__Int16MultiArray as Int16MultiArray +from ..._types import std_msgs__msg__Int32 as Int32 +from ..._types import std_msgs__msg__Int32MultiArray as Int32MultiArray +from ..._types import std_msgs__msg__Int64 as Int64 +from ..._types import std_msgs__msg__Int64MultiArray as Int64MultiArray +from ..._types import std_msgs__msg__Int8 as Int8 +from ..._types import std_msgs__msg__Int8MultiArray as Int8MultiArray +from ..._types import std_msgs__msg__String as String +from ..._types import std_msgs__msg__UInt16 as UInt16 +from ..._types import std_msgs__msg__UInt16MultiArray as UInt16MultiArray +from ..._types import std_msgs__msg__UInt32 as UInt32 +from ..._types import std_msgs__msg__UInt32MultiArray as UInt32MultiArray +from ..._types import std_msgs__msg__UInt64 as UInt64 +from ..._types import std_msgs__msg__UInt64MultiArray as UInt64MultiArray +from ..._types import std_msgs__msg__UInt8 as UInt8 +from ..._types import std_msgs__msg__UInt8MultiArray as UInt8MultiArray diff --git a/packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi new file mode 100644 index 00000000000..39fa6b49941 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi @@ -0,0 +1,3 @@ +__all__ = ['TF2Error', 'TFMessage'] +from ..._types import tf2_msgs__msg__TF2Error as TF2Error +from ..._types import tf2_msgs__msg__TFMessage as TFMessage diff --git a/packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi new file mode 100644 index 00000000000..7a0c966c2be --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi @@ -0,0 +1,5 @@ +__all__ = ['JointTrajectoryPoint', 'JointTrajectory', 'MultiDOFJointTrajectoryPoint', 'MultiDOFJointTrajectory'] +from ..._types import trajectory_msgs__msg__JointTrajectoryPoint as JointTrajectoryPoint +from ..._types import trajectory_msgs__msg__JointTrajectory as JointTrajectory +from ..._types import trajectory_msgs__msg__MultiDOFJointTrajectoryPoint as MultiDOFJointTrajectoryPoint +from ..._types import trajectory_msgs__msg__MultiDOFJointTrajectory as MultiDOFJointTrajectory diff --git a/packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi new file mode 100644 index 00000000000..f4f3271f588 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi @@ -0,0 +1,17 @@ +__all__ = ['Point2D', 'Pose2D', 'BoundingBox2D', 'BoundingBox3D', 'BoundingBox2DArray', 'BoundingBox3DArray', 'ObjectHypothesis', 'Classification', 'ObjectHypothesisWithPose', 'Detection2D', 'Detection2DArray', 'Detection3D', 'Detection3DArray', 'VisionClass', 'LabelInfo', 'VisionInfo'] +from ..._types import vision_msgs__msg__Point2D as Point2D +from ..._types import vision_msgs__msg__Pose2D as Pose2D +from ..._types import vision_msgs__msg__BoundingBox2D as BoundingBox2D +from ..._types import vision_msgs__msg__BoundingBox3D as BoundingBox3D +from ..._types import vision_msgs__msg__BoundingBox2DArray as BoundingBox2DArray +from ..._types import vision_msgs__msg__BoundingBox3DArray as BoundingBox3DArray +from ..._types import vision_msgs__msg__ObjectHypothesis as ObjectHypothesis +from ..._types import vision_msgs__msg__Classification as Classification +from ..._types import vision_msgs__msg__ObjectHypothesisWithPose as ObjectHypothesisWithPose +from ..._types import vision_msgs__msg__Detection2D as Detection2D +from ..._types import vision_msgs__msg__Detection2DArray as Detection2DArray +from ..._types import vision_msgs__msg__Detection3D as Detection3D +from ..._types import vision_msgs__msg__Detection3DArray as Detection3DArray +from ..._types import vision_msgs__msg__VisionClass as VisionClass +from ..._types import vision_msgs__msg__LabelInfo as LabelInfo +from ..._types import vision_msgs__msg__VisionInfo as VisionInfo diff --git a/packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi new file mode 100644 index 00000000000..c36ca599c65 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi @@ -0,0 +1,13 @@ +__all__ = ['ImageMarker', 'MeshFile', 'UVCoordinate', 'Marker', 'InteractiveMarkerControl', 'MenuEntry', 'InteractiveMarker', 'InteractiveMarkerFeedback', 'InteractiveMarkerInit', 'InteractiveMarkerPose', 'InteractiveMarkerUpdate', 'MarkerArray'] +from ..._types import visualization_msgs__msg__ImageMarker as ImageMarker +from ..._types import visualization_msgs__msg__MeshFile as MeshFile +from ..._types import visualization_msgs__msg__UVCoordinate as UVCoordinate +from ..._types import visualization_msgs__msg__Marker as Marker +from ..._types import visualization_msgs__msg__InteractiveMarkerControl as InteractiveMarkerControl +from ..._types import visualization_msgs__msg__MenuEntry as MenuEntry +from ..._types import visualization_msgs__msg__InteractiveMarker as InteractiveMarker +from ..._types import visualization_msgs__msg__InteractiveMarkerFeedback as InteractiveMarkerFeedback +from ..._types import visualization_msgs__msg__InteractiveMarkerInit as InteractiveMarkerInit +from ..._types import visualization_msgs__msg__InteractiveMarkerPose as InteractiveMarkerPose +from ..._types import visualization_msgs__msg__InteractiveMarkerUpdate as InteractiveMarkerUpdate +from ..._types import visualization_msgs__msg__MarkerArray as MarkerArray diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/CMakeLists.txt new file mode 100644 index 00000000000..12d0575bcb3 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.20) +project(builtin_interfaces VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces}) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/package.xml new file mode 100644 index 00000000000..2e1d90bbbc2 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/package.xml @@ -0,0 +1 @@ +builtin_interfaces0.1.0DimOS message sourcesDimOSApache-2.0rosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/CMakeLists.txt new file mode 100644 index 00000000000..a920ce4ebe0 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.20) +project(dimos_msgs VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +find_package(builtin_interfaces REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(std_msgs REQUIRED) +find_package(vision_msgs REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces geometry_msgs std_msgs vision_msgs) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/package.xml new file mode 100644 index 00000000000..dbdcecaa2d3 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/package.xml @@ -0,0 +1 @@ +dimos_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesgeometry_msgsstd_msgsvision_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/CMakeLists.txt new file mode 100644 index 00000000000..a41d835698e --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.20) +project(foxglove_msgs VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +find_package(builtin_interfaces REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/package.xml new file mode 100644 index 00000000000..576acc0a793 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/package.xml @@ -0,0 +1 @@ +foxglove_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/CMakeLists.txt new file mode 100644 index 00000000000..53b1078b5c5 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.20) +project(geometry_msgs VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +find_package(std_msgs REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES std_msgs) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/package.xml new file mode 100644 index 00000000000..cfdf9a33d31 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/package.xml @@ -0,0 +1 @@ +geometry_msgs0.1.0DimOS message sourcesDimOSApache-2.0std_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/CMakeLists.txt new file mode 100644 index 00000000000..d429a44d1a3 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.20) +project(nav_msgs VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +find_package(builtin_interfaces REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(std_msgs REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces geometry_msgs std_msgs) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/package.xml new file mode 100644 index 00000000000..efa14c2b878 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/package.xml @@ -0,0 +1 @@ +nav_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesgeometry_msgsstd_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json new file mode 100644 index 00000000000..70536616bd2 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json @@ -0,0 +1 @@ +["builtin_interfaces", "std_msgs", "geometry_msgs", "vision_msgs", "dimos_msgs", "foxglove_msgs", "nav_msgs", "sensor_msgs", "shape_msgs", "tf2_msgs", "trajectory_msgs", "visualization_msgs"] diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/CMakeLists.txt new file mode 100644 index 00000000000..50604e983bf --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.20) +project(sensor_msgs VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +find_package(builtin_interfaces REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(std_msgs REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces geometry_msgs std_msgs) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/package.xml new file mode 100644 index 00000000000..fc56e4a4f5d --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/package.xml @@ -0,0 +1 @@ +sensor_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesgeometry_msgsstd_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/CMakeLists.txt new file mode 100644 index 00000000000..50ff6e65380 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.20) +project(shape_msgs VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +find_package(geometry_msgs REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES geometry_msgs) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/package.xml new file mode 100644 index 00000000000..5c57b45765c --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/package.xml @@ -0,0 +1 @@ +shape_msgs0.1.0DimOS message sourcesDimOSApache-2.0geometry_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/CMakeLists.txt new file mode 100644 index 00000000000..03d98a1aad8 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.20) +project(std_msgs VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +find_package(builtin_interfaces REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/msg/Empty.msg b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/msg/Empty.msg new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/package.xml new file mode 100644 index 00000000000..799db5dcff6 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/package.xml @@ -0,0 +1 @@ +std_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/CMakeLists.txt new file mode 100644 index 00000000000..d825ff76e54 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.20) +project(tf2_msgs VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +find_package(geometry_msgs REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES geometry_msgs) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/package.xml new file mode 100644 index 00000000000..e8f1b237c21 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/package.xml @@ -0,0 +1 @@ +tf2_msgs0.1.0DimOS message sourcesDimOSApache-2.0geometry_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/CMakeLists.txt new file mode 100644 index 00000000000..ecccce9ab8f --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.20) +project(trajectory_msgs VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +find_package(builtin_interfaces REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(std_msgs REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces geometry_msgs std_msgs) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/package.xml new file mode 100644 index 00000000000..b9d2f8fae45 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/package.xml @@ -0,0 +1 @@ +trajectory_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesgeometry_msgsstd_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/CMakeLists.txt new file mode 100644 index 00000000000..0145311b9d6 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.20) +project(vision_msgs VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(std_msgs REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES geometry_msgs std_msgs) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/package.xml new file mode 100644 index 00000000000..413b5cd9d33 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/package.xml @@ -0,0 +1 @@ +vision_msgs0.1.0DimOS message sourcesDimOSApache-2.0geometry_msgsstd_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/CMakeLists.txt new file mode 100644 index 00000000000..7526e7c721d --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.20) +project(visualization_msgs VERSION 0.1.0) +find_package(ament_cmake REQUIRED) +find_package(rosidl_cmake REQUIRED) +find_package(rosidl_adapter REQUIRED) +find_package(rosidl_generator_type_description REQUIRED) +find_package(rosidl_generator_c REQUIRED) +find_package(rosidl_generator_cpp REQUIRED) +find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) +find_package(builtin_interfaces REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(sensor_msgs REQUIRED) +find_package(std_msgs REQUIRED) +file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") +rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces geometry_msgs sensor_msgs std_msgs) +ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/package.xml new file mode 100644 index 00000000000..959c86e74f1 --- /dev/null +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/package.xml @@ -0,0 +1 @@ +visualization_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesgeometry_msgssensor_msgsstd_msgsrosidl_interface_packagesament_cmake diff --git a/setup.py b/setup.py index 44a5ed83bcc..04fcdeb235a 100644 --- a/setup.py +++ b/setup.py @@ -94,6 +94,22 @@ def run(self): super().run() if not getattr(self, "editable_mode", False): self._copy_relay_dist() + self._copy_native_sources() + + def _copy_native_sources(self): + source = Path(__file__).parent / "native" / "cpp" + destination = Path(self.build_lib) / "dimos" / "_native" / "cpp" + for path in sorted(source.rglob("*")): + relative = path.relative_to(source) + if any(part in {"build", "result", "_deps"} for part in relative.parts): + continue + if path.is_file() and ( + path.suffix in {".hpp", ".h", ".cpp", ".cmake", ".in"} + or path.name == "CMakeLists.txt" + ): + target = destination / relative + self.mkpath(str(target.parent)) + self.copy_file(str(path), str(target)) def _copy_relay_dist(self): src = Path(__file__).parent / "web" From 7c2f185f72aa81ada89d60ed96d644ebf0e9481f Mon Sep 17 00:00:00 2001 From: cc Date: Fri, 9 Oct 2026 11:44:53 -0700 Subject: [PATCH 04/11] refactor: migrate runtime consumers to native message values --- dimos/agents/mcp/test_generated_image.py | 1 + dimos/agents/test_generated_vlm.py | 1 + dimos/cli/spy/test_spy.py | 1 + dimos/e2e_tests/lcm_spy.py | 1 + .../isolated_python/test_generated_example.py | 1 + dimos/experimental/memory/rust_recorder.py | 1 + dimos/experimental/security_demo/security_module.py | 2 ++ .../sensors/camera/gstreamer/test_generated_frames.py | 1 + .../manipulation/grasping/grasp_gen_x/test_module.py | 1 + .../occupancy/test_generated_visualizations.py | 1 + dimos/mapping/pointclouds/test_generated_occupancy.py | 1 + dimos/mapping/test_generated_costmapper.py | 1 + dimos/memory/codecs/test_codecs.py | 1 + dimos/memory/store/test_mcap.py | 1 + dimos/models/vl/test_generated_images.py | 1 + dimos/msgs/geometry_msgs/test_Quaternion.py | 1 + dimos/msgs/geometry_msgs/test_Transform.py | 1 + dimos/msgs/geometry_msgs/test_Twist.py | 1 + dimos/msgs/geometry_msgs/test_Vector3.py | 1 + dimos/msgs/geometry_msgs/tool_publish.py | 1 + dimos/msgs/manipulation_msgs/test_grasp_candidate.py | 1 + dimos/msgs/sensor_msgs/test_image.py | 1 + dimos/msgs/test_camera_info.py | 1 + dimos/msgs/test_geometry.py | 1 + dimos/msgs/test_msg_construction.py | 1 + dimos/msgs/test_occupancy.py | 1 + dimos/msgs/test_pointcloud.py | 1 + .../frontier_exploration/test_generated_frontiers.py | 1 + .../experimental/patrolling/test_generated_patrol.py | 1 + .../replanning_a_star/test_generated_navigation.py | 1 + .../go2/replanning_a_star/test_generated_pipeline.py | 1 + dimos/perception/detection/conftest.py | 1 + .../detection/type/detection2d/test_generated_bbox.py | 1 + .../type/detection3d/test_generated_filters.py | 1 + .../type/detection3d/test_generated_projection.py | 1 + .../perception/experimental/test_generated_tracker.py | 1 + .../fiducial/test_generated_marker_detect.py | 1 + dimos/perception/memory/test_generated_inventory.py | 11 ++++++++--- dimos/protocol/pubsub/benchmark/test_replay_bench.py | 1 + dimos/protocol/pubsub/impl/jpeg_lcm.py | 1 + dimos/protocol/pubsub/impl/jpeg_shm.py | 1 + dimos/protocol/pubsub/impl/test_jpeg_cdr.py | 1 + dimos/protocol/pubsub/impl/webrtc/test_transport.py | 1 + dimos/protocol/tf/test_static_tf_publisher.py | 1 + dimos/robot/diy/alfred/test_generated_effector.py | 1 + dimos/robot/diy/alfred/test_mount_tf.py | 1 + .../unitree/g1/debug/demo_arrow_control_cmd_vel.py | 1 + dimos/robot/unitree/go2/dds/ros.py | 1 + dimos/robot/unitree/go2/dds/test_generated_codecs.py | 1 + dimos/robot/unitree/type/test_lidar.py | 1 + dimos/robot/unitree/type/test_pose_conversion.py | 1 + dimos/simulation/dimsim/cdr_schemas.py | 1 + dimos/teleop/hosted/arm_command.py | 1 + dimos/teleop/hosted/hosted_stats.py | 1 + dimos/teleop/hosted/test_hosted_stats.py | 1 + dimos/teleop/phone/phone_teleop_module.py | 1 + dimos/teleop/phone/test_phone_cdr.py | 5 +++++ dimos/teleop/utils/test_video_stats.py | 5 +++++ .../rerun/test_generated_entity_bridge.py | 1 + dimos/web/test_cockpit.py | 1 + 60 files changed, 76 insertions(+), 3 deletions(-) diff --git a/dimos/agents/mcp/test_generated_image.py b/dimos/agents/mcp/test_generated_image.py index 457002e0d91..f23d8881df5 100644 --- a/dimos/agents/mcp/test_generated_image.py +++ b/dimos/agents/mcp/test_generated_image.py @@ -20,6 +20,7 @@ import cv2 from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import Image +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.agents.mcp.mcp_client import _append_image_to_history diff --git a/dimos/agents/test_generated_vlm.py b/dimos/agents/test_generated_vlm.py index cac403becfb..d3ca3e13121 100644 --- a/dimos/agents/test_generated_vlm.py +++ b/dimos/agents/test_generated_vlm.py @@ -19,6 +19,7 @@ import cv2 from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import Image +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from langchain_core.messages import AIMessage, HumanMessage import numpy as np import pytest diff --git a/dimos/cli/spy/test_spy.py b/dimos/cli/spy/test_spy.py index cf6fc2c2ce7..83bf45f05d7 100644 --- a/dimos/cli/spy/test_spy.py +++ b/dimos/cli/spy/test_spy.py @@ -28,6 +28,7 @@ from dimos_cdrgen.registry import encode as cdr_encode from dimos_generated.geometry_msgs.msg import Vector3 +from dimos_message_build.registry import encode as cdr_encode import pytest from dimos.cli.spy.core import ( diff --git a/dimos/e2e_tests/lcm_spy.py b/dimos/e2e_tests/lcm_spy.py index 6d6b919a5d3..c505d428baf 100644 --- a/dimos/e2e_tests/lcm_spy.py +++ b/dimos/e2e_tests/lcm_spy.py @@ -21,6 +21,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import PoseStamped +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.core.global_config import global_config from dimos.core.transport_factory import transport_topic diff --git a/dimos/experimental/isolated_python/test_generated_example.py b/dimos/experimental/isolated_python/test_generated_example.py index 35c01af79d9..377ec046deb 100644 --- a/dimos/experimental/isolated_python/test_generated_example.py +++ b/dimos/experimental/isolated_python/test_generated_example.py @@ -19,6 +19,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.std_msgs.msg import Int32 +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.experimental.isolated_python.bootstrap import load_class from dimos.experimental.isolated_python.example.contract import ExampleExternal diff --git a/dimos/experimental/memory/rust_recorder.py b/dimos/experimental/memory/rust_recorder.py index a0bf80ea748..790e4f2fe3d 100644 --- a/dimos/experimental/memory/rust_recorder.py +++ b/dimos/experimental/memory/rust_recorder.py @@ -23,6 +23,7 @@ from dimos_cdrgen.registry import schema as cdr_schema from dimos_generated.std_msgs.msg import String from dimos_generated.tf2_msgs.msg import TFMessage +from dimos_message_build.registry import schema as cdr_schema from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator from dimos.constants import DIMOS_PROJECT_ROOT diff --git a/dimos/experimental/security_demo/security_module.py b/dimos/experimental/security_demo/security_module.py index 7853fd4cfa8..5be3b88b1ab 100644 --- a/dimos/experimental/security_demo/security_module.py +++ b/dimos/experimental/security_demo/security_module.py @@ -48,6 +48,8 @@ from dimos_generated.geometry_msgs.msg import Vector3 +from dimos_generated.geometry_msgs.msg import Vector3 + if TYPE_CHECKING: from dimos.perception.detection.type.detection2d.bbox import Detection2DBBox diff --git a/dimos/hardware/sensors/camera/gstreamer/test_generated_frames.py b/dimos/hardware/sensors/camera/gstreamer/test_generated_frames.py index af1b107373c..45d31a5e07c 100644 --- a/dimos/hardware/sensors/camera/gstreamer/test_generated_frames.py +++ b/dimos/hardware/sensors/camera/gstreamer/test_generated_frames.py @@ -20,6 +20,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import Image +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/manipulation/grasping/grasp_gen_x/test_module.py b/dimos/manipulation/grasping/grasp_gen_x/test_module.py index e13f04e36e1..6bf10a9f9f0 100644 --- a/dimos/manipulation/grasping/grasp_gen_x/test_module.py +++ b/dimos/manipulation/grasping/grasp_gen_x/test_module.py @@ -27,6 +27,7 @@ from dimos_generated.dimos_msgs.msg import GraspCandidate, GraspCandidateArray from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/mapping/occupancy/test_generated_visualizations.py b/dimos/mapping/occupancy/test_generated_visualizations.py index b96a44bb826..f3fffc3f2e9 100644 --- a/dimos/mapping/occupancy/test_generated_visualizations.py +++ b/dimos/mapping/occupancy/test_generated_visualizations.py @@ -23,6 +23,7 @@ from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid, Path from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/mapping/pointclouds/test_generated_occupancy.py b/dimos/mapping/pointclouds/test_generated_occupancy.py index 2069f38e375..d6b248e295a 100644 --- a/dimos/mapping/pointclouds/test_generated_occupancy.py +++ b/dimos/mapping/pointclouds/test_generated_occupancy.py @@ -22,6 +22,7 @@ from dimos_generated.nav_msgs.msg import OccupancyGrid from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from numpy.typing import NDArray import pytest diff --git a/dimos/mapping/test_generated_costmapper.py b/dimos/mapping/test_generated_costmapper.py index bae0adcdf20..36db39639ea 100644 --- a/dimos/mapping/test_generated_costmapper.py +++ b/dimos/mapping/test_generated_costmapper.py @@ -19,6 +19,7 @@ from dimos_generated.geometry_msgs.msg import Point, Pose from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.mapping.costmapper import CostMapper diff --git a/dimos/memory/codecs/test_codecs.py b/dimos/memory/codecs/test_codecs.py index fde098a5d82..2d6c1b4641d 100644 --- a/dimos/memory/codecs/test_codecs.py +++ b/dimos/memory/codecs/test_codecs.py @@ -19,6 +19,7 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.sensor_msgs.msg import CompressedImage, Image from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import encode as cdr_encode import numpy as np import pytest diff --git a/dimos/memory/store/test_mcap.py b/dimos/memory/store/test_mcap.py index 6bf674b51c9..0aafdc17d00 100644 --- a/dimos/memory/store/test_mcap.py +++ b/dimos/memory/store/test_mcap.py @@ -17,6 +17,7 @@ from dimos_generated.geometry_msgs.msg import Quaternion, Vector3 from dimos_generated.sensor_msgs.msg import CompressedImage, Imu from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import encode as cdr_encode, schema as cdr_schema from mcap.writer import Writer import numpy as np import pytest diff --git a/dimos/models/vl/test_generated_images.py b/dimos/models/vl/test_generated_images.py index 2795ed5fbf2..a81f3377849 100644 --- a/dimos/models/vl/test_generated_images.py +++ b/dimos/models/vl/test_generated_images.py @@ -21,6 +21,7 @@ from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection2DArray +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/msgs/geometry_msgs/test_Quaternion.py b/dimos/msgs/geometry_msgs/test_Quaternion.py index fcf4d78771f..c3bcd85fbcd 100644 --- a/dimos/msgs/geometry_msgs/test_Quaternion.py +++ b/dimos/msgs/geometry_msgs/test_Quaternion.py @@ -14,6 +14,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Quaternion, Vector3 +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/msgs/geometry_msgs/test_Transform.py b/dimos/msgs/geometry_msgs/test_Transform.py index f830ebb46ba..f5a17f1e792 100644 --- a/dimos/msgs/geometry_msgs/test_Transform.py +++ b/dimos/msgs/geometry_msgs/test_Transform.py @@ -26,6 +26,7 @@ Vector3, ) from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest from rosbags.typesys import Stores, get_typestore diff --git a/dimos/msgs/geometry_msgs/test_Twist.py b/dimos/msgs/geometry_msgs/test_Twist.py index 0dc7b6c95bf..4563457f0ea 100644 --- a/dimos/msgs/geometry_msgs/test_Twist.py +++ b/dimos/msgs/geometry_msgs/test_Twist.py @@ -16,6 +16,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Quaternion, Twist, Vector3 +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from rosbags.typesys import Stores, get_typestore diff --git a/dimos/msgs/geometry_msgs/test_Vector3.py b/dimos/msgs/geometry_msgs/test_Vector3.py index 2f7f85001c1..6ac52681719 100644 --- a/dimos/msgs/geometry_msgs/test_Vector3.py +++ b/dimos/msgs/geometry_msgs/test_Vector3.py @@ -14,6 +14,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Vector3 +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/msgs/geometry_msgs/tool_publish.py b/dimos/msgs/geometry_msgs/tool_publish.py index 592e54b1d4f..fb42e6acc5e 100644 --- a/dimos/msgs/geometry_msgs/tool_publish.py +++ b/dimos/msgs/geometry_msgs/tool_publish.py @@ -16,6 +16,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Vector3 +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import lcm diff --git a/dimos/msgs/manipulation_msgs/test_grasp_candidate.py b/dimos/msgs/manipulation_msgs/test_grasp_candidate.py index 8313f74b512..47a146c9fdc 100644 --- a/dimos/msgs/manipulation_msgs/test_grasp_candidate.py +++ b/dimos/msgs/manipulation_msgs/test_grasp_candidate.py @@ -16,6 +16,7 @@ from dimos_generated.dimos_msgs.msg import GraspCandidate, GraspCandidateArray from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.time import time_from_seconds diff --git a/dimos/msgs/sensor_msgs/test_image.py b/dimos/msgs/sensor_msgs/test_image.py index 9c258b86a88..b34783f1fed 100644 --- a/dimos/msgs/sensor_msgs/test_image.py +++ b/dimos/msgs/sensor_msgs/test_image.py @@ -20,6 +20,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from PIL import Image as PILImage import pytest diff --git a/dimos/msgs/test_camera_info.py b/dimos/msgs/test_camera_info.py index 81dcbd8955a..8e933b03dfc 100644 --- a/dimos/msgs/test_camera_info.py +++ b/dimos/msgs/test_camera_info.py @@ -21,6 +21,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import CameraInfo from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest import yaml diff --git a/dimos/msgs/test_geometry.py b/dimos/msgs/test_geometry.py index 08dfff82c9b..aa82c94d678 100644 --- a/dimos/msgs/test_geometry.py +++ b/dimos/msgs/test_geometry.py @@ -33,6 +33,7 @@ ) from dimos_generated.nav_msgs.msg import Odometry from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/msgs/test_msg_construction.py b/dimos/msgs/test_msg_construction.py index 6a265928fcf..aa298354a21 100644 --- a/dimos/msgs/test_msg_construction.py +++ b/dimos/msgs/test_msg_construction.py @@ -41,6 +41,7 @@ from dimos_generated.nav_msgs.msg import Odometry, Path from dimos_generated.sensor_msgs.msg import JointState, Joy from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest from rosbags.serde.errors import SerdeError diff --git a/dimos/msgs/test_occupancy.py b/dimos/msgs/test_occupancy.py index dabeecee18a..f676a5e3a23 100644 --- a/dimos/msgs/test_occupancy.py +++ b/dimos/msgs/test_occupancy.py @@ -19,6 +19,7 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from PIL import Image import pytest diff --git a/dimos/msgs/test_pointcloud.py b/dimos/msgs/test_pointcloud.py index a349c0800f7..20a9f8befce 100644 --- a/dimos/msgs/test_pointcloud.py +++ b/dimos/msgs/test_pointcloud.py @@ -23,6 +23,7 @@ from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 from dimos_generated.sensor_msgs.msg import PointCloud2, PointField from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/navigation/experimental/frontier_exploration/test_generated_frontiers.py b/dimos/navigation/experimental/frontier_exploration/test_generated_frontiers.py index 88635ce5745..eab92abf972 100644 --- a/dimos/navigation/experimental/frontier_exploration/test_generated_frontiers.py +++ b/dimos/navigation/experimental/frontier_exploration/test_generated_frontiers.py @@ -19,6 +19,7 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/navigation/experimental/patrolling/test_generated_patrol.py b/dimos/navigation/experimental/patrolling/test_generated_patrol.py index 588af6ebf9f..ce4c2cbdb8b 100644 --- a/dimos/navigation/experimental/patrolling/test_generated_patrol.py +++ b/dimos/navigation/experimental/patrolling/test_generated_patrol.py @@ -20,6 +20,7 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/navigation/go2/replanning_a_star/test_generated_navigation.py b/dimos/navigation/go2/replanning_a_star/test_generated_navigation.py index 340bdcc1417..4be7f99f14d 100644 --- a/dimos/navigation/go2/replanning_a_star/test_generated_navigation.py +++ b/dimos/navigation/go2/replanning_a_star/test_generated_navigation.py @@ -20,6 +20,7 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist, Vector3 from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid, Path from dimos_generated.std_msgs.msg import Bool, Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.core.global_config import GlobalConfig diff --git a/dimos/navigation/go2/replanning_a_star/test_generated_pipeline.py b/dimos/navigation/go2/replanning_a_star/test_generated_pipeline.py index bd9e60eec0e..000ff679237 100644 --- a/dimos/navigation/go2/replanning_a_star/test_generated_pipeline.py +++ b/dimos/navigation/go2/replanning_a_star/test_generated_pipeline.py @@ -22,6 +22,7 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid, Path from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/perception/detection/conftest.py b/dimos/perception/detection/conftest.py index 16bb8ec8d6b..9acde8afcfe 100644 --- a/dimos/perception/detection/conftest.py +++ b/dimos/perception/detection/conftest.py @@ -23,6 +23,7 @@ from dimos_generated.sensor_msgs.msg import CameraInfo, Image, PointCloud2 from dimos_generated.vision_msgs.msg import Detection2DArray from dimos_generated.visualization_msgs.msg import MarkerArray +from dimos_message_build.registry import decode as cdr_decode import pytest from dimos.core.transport import LCMTransport diff --git a/dimos/perception/detection/type/detection2d/test_generated_bbox.py b/dimos/perception/detection/type/detection2d/test_generated_bbox.py index 393b33a5fee..3000158328e 100644 --- a/dimos/perception/detection/type/detection2d/test_generated_bbox.py +++ b/dimos/perception/detection/type/detection2d/test_generated_bbox.py @@ -16,6 +16,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection2D, Detection2DArray +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.image import image_from_array, image_view diff --git a/dimos/perception/detection/type/detection3d/test_generated_filters.py b/dimos/perception/detection/type/detection3d/test_generated_filters.py index b3a679652be..c6b12c60cba 100644 --- a/dimos/perception/detection/type/detection3d/test_generated_filters.py +++ b/dimos/perception/detection/type/detection3d/test_generated_filters.py @@ -19,6 +19,7 @@ from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 from dimos_generated.sensor_msgs.msg import CameraInfo, PointCloud2, PointField, RegionOfInterest from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/perception/detection/type/detection3d/test_generated_projection.py b/dimos/perception/detection/type/detection3d/test_generated_projection.py index 8a2aea7cf0d..5405da85802 100644 --- a/dimos/perception/detection/type/detection3d/test_generated_projection.py +++ b/dimos/perception/detection/type/detection3d/test_generated_projection.py @@ -25,6 +25,7 @@ ) from dimos_generated.sensor_msgs.msg import CameraInfo, RegionOfInterest from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/perception/experimental/test_generated_tracker.py b/dimos/perception/experimental/test_generated_tracker.py index b8f486bc196..0e2e2bba577 100644 --- a/dimos/perception/experimental/test_generated_tracker.py +++ b/dimos/perception/experimental/test_generated_tracker.py @@ -26,6 +26,7 @@ Point2D, Pose2D, ) +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/perception/fiducial/test_generated_marker_detect.py b/dimos/perception/fiducial/test_generated_marker_detect.py index d614d485a91..50ea5b68e53 100644 --- a/dimos/perception/fiducial/test_generated_marker_detect.py +++ b/dimos/perception/fiducial/test_generated_marker_detect.py @@ -19,6 +19,7 @@ from dimos_generated.sensor_msgs.msg import CameraInfo, Image, RegionOfInterest from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection3D +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/perception/memory/test_generated_inventory.py b/dimos/perception/memory/test_generated_inventory.py index 8c3223fc4b8..9b0924e1830 100644 --- a/dimos/perception/memory/test_generated_inventory.py +++ b/dimos/perception/memory/test_generated_inventory.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 from dimos_generated.std_msgs.msg import Header import numpy as np @@ -56,11 +57,15 @@ def test_generated_support_merge_preserves_colors_and_source_time(): def test_generated_support_projection_reads_nested_transform_and_intrinsics(): - calibration = camera_info_from_intrinsics(10, 20, 5, 6, 100, 100, header=Header()) + calibration = camera_info_from_intrinsics( + 10, 20, 5, 6, 100, 100, header=Header(stamp=Time(sec=0, nanosec=0), frame_id="") + ) transform = TransformStamped( - header=Header(frame_id="optical"), + header=Header(frame_id="optical", stamp=Time(sec=0, nanosec=0)), child_frame_id="world", - transform=Transform(translation=Vector3(x=-1), rotation=Quaternion(w=1)), + transform=Transform( + translation=Vector3(x=-1, y=0.0, z=0.0), rotation=Quaternion(w=1, x=0.0, y=0.0, z=0.0) + ), ) assert _pixel_bbox(np.array([[1, 0, 2], [2, 1, 2]]), calibration, transform) == (5, 6, 10, 16) diff --git a/dimos/protocol/pubsub/benchmark/test_replay_bench.py b/dimos/protocol/pubsub/benchmark/test_replay_bench.py index 7823d8107d6..68ca0148034 100644 --- a/dimos/protocol/pubsub/benchmark/test_replay_bench.py +++ b/dimos/protocol/pubsub/benchmark/test_replay_bench.py @@ -23,6 +23,7 @@ from dimos_cdrgen.registry import encode as cdr_encode from dimos_generated.sensor_msgs.msg import CompressedImage, Image from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import encode as cdr_encode import numpy as np import pytest diff --git a/dimos/protocol/pubsub/impl/jpeg_lcm.py b/dimos/protocol/pubsub/impl/jpeg_lcm.py index 7dc46e22092..c2eb0df435b 100644 --- a/dimos/protocol/pubsub/impl/jpeg_lcm.py +++ b/dimos/protocol/pubsub/impl/jpeg_lcm.py @@ -23,6 +23,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import CompressedImage, Image +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.image import compressed_image_from_image, image_from_compressed from dimos.protocol.pubsub.encoders import DecodingError, PubSubEncoderMixin, TypedTopicProto diff --git a/dimos/protocol/pubsub/impl/jpeg_shm.py b/dimos/protocol/pubsub/impl/jpeg_shm.py index ee4a1f7be8f..c914f1bc545 100644 --- a/dimos/protocol/pubsub/impl/jpeg_shm.py +++ b/dimos/protocol/pubsub/impl/jpeg_shm.py @@ -16,6 +16,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import CompressedImage, Image +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.image import compressed_image_from_image, image_from_compressed from dimos.protocol.pubsub.encoders import PubSubEncoderMixin diff --git a/dimos/protocol/pubsub/impl/test_jpeg_cdr.py b/dimos/protocol/pubsub/impl/test_jpeg_cdr.py index effabf17d4c..a97d2ce9651 100644 --- a/dimos/protocol/pubsub/impl/test_jpeg_cdr.py +++ b/dimos/protocol/pubsub/impl/test_jpeg_cdr.py @@ -22,6 +22,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import CompressedImage, Image from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/protocol/pubsub/impl/webrtc/test_transport.py b/dimos/protocol/pubsub/impl/webrtc/test_transport.py index 901ec3bcbae..3a88a7f14bc 100644 --- a/dimos/protocol/pubsub/impl/webrtc/test_transport.py +++ b/dimos/protocol/pubsub/impl/webrtc/test_transport.py @@ -21,6 +21,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Point, TwistStamped, Vector3 +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from pydantic import ValidationError import pytest diff --git a/dimos/protocol/tf/test_static_tf_publisher.py b/dimos/protocol/tf/test_static_tf_publisher.py index 90316e4717e..d83c083c945 100644 --- a/dimos/protocol/tf/test_static_tf_publisher.py +++ b/dimos/protocol/tf/test_static_tf_publisher.py @@ -18,6 +18,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.tf2_msgs.msg import TFMessage +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.msgs.geometry import compose_transforms diff --git a/dimos/robot/diy/alfred/test_generated_effector.py b/dimos/robot/diy/alfred/test_generated_effector.py index d81168e2784..692adf84569 100644 --- a/dimos/robot/diy/alfred/test_generated_effector.py +++ b/dimos/robot/diy/alfred/test_generated_effector.py @@ -17,6 +17,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.nav_msgs.msg import Odometry +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.msgs.geometry import yaw diff --git a/dimos/robot/diy/alfred/test_mount_tf.py b/dimos/robot/diy/alfred/test_mount_tf.py index 609f8f9a521..5b799aafa38 100644 --- a/dimos/robot/diy/alfred/test_mount_tf.py +++ b/dimos/robot/diy/alfred/test_mount_tf.py @@ -16,6 +16,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.tf2_msgs.msg import TFMessage +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.robot.diy.alfred import mount_tf diff --git a/dimos/robot/unitree/g1/debug/demo_arrow_control_cmd_vel.py b/dimos/robot/unitree/g1/debug/demo_arrow_control_cmd_vel.py index 6b156f3d4a4..19162634f7d 100644 --- a/dimos/robot/unitree/g1/debug/demo_arrow_control_cmd_vel.py +++ b/dimos/robot/unitree/g1/debug/demo_arrow_control_cmd_vel.py @@ -22,6 +22,7 @@ from dimos_cdrgen.registry import encode as cdr_encode from dimos_generated.geometry_msgs.msg import Twist, Vector3 +from dimos_message_build.registry import encode as cdr_encode import lcm from dimos.core.transport import LCMTransport diff --git a/dimos/robot/unitree/go2/dds/ros.py b/dimos/robot/unitree/go2/dds/ros.py index b9ea5d53d90..20205e6c477 100644 --- a/dimos/robot/unitree/go2/dds/ros.py +++ b/dimos/robot/unitree/go2/dds/ros.py @@ -26,6 +26,7 @@ from dimos_generated.geometry_msgs.msg import Quaternion from dimos_generated.nav_msgs.msg import Odometry from dimos_generated.sensor_msgs.msg import CompressedImage, Imu, PointCloud2 +from dimos_message_build.registry import decode as cdr_decode import numpy as np from dimos.robot.unitree.go2.dds import cdr diff --git a/dimos/robot/unitree/go2/dds/test_generated_codecs.py b/dimos/robot/unitree/go2/dds/test_generated_codecs.py index 2e39b2b1993..0d9327ca2e6 100644 --- a/dimos/robot/unitree/go2/dds/test_generated_codecs.py +++ b/dimos/robot/unitree/go2/dds/test_generated_codecs.py @@ -29,6 +29,7 @@ from dimos_generated.nav_msgs.msg import Odometry from dimos_generated.sensor_msgs.msg import CompressedImage, Imu, PointCloud2, PointField from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import encode as cdr_encode import numpy as np import pytest from rosbags.typesys import Stores, get_typestore diff --git a/dimos/robot/unitree/type/test_lidar.py b/dimos/robot/unitree/type/test_lidar.py index 9d8faecddee..2bbf7429d95 100644 --- a/dimos/robot/unitree/type/test_lidar.py +++ b/dimos/robot/unitree/type/test_lidar.py @@ -20,6 +20,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest import reactivex as rx diff --git a/dimos/robot/unitree/type/test_pose_conversion.py b/dimos/robot/unitree/type/test_pose_conversion.py index 5c1a7571c06..5dda53c7355 100644 --- a/dimos/robot/unitree/type/test_pose_conversion.py +++ b/dimos/robot/unitree/type/test_pose_conversion.py @@ -18,6 +18,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import PoseStamped from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.robot.unitree.type.odometry import pose_from_webrtc_odometry, raw_odometry_msg_sample diff --git a/dimos/simulation/dimsim/cdr_schemas.py b/dimos/simulation/dimsim/cdr_schemas.py index 4ee6402b1b2..efb519eebe6 100644 --- a/dimos/simulation/dimsim/cdr_schemas.py +++ b/dimos/simulation/dimsim/cdr_schemas.py @@ -22,6 +22,7 @@ from dimos_cdrgen.registry import schema as cdr_schema from dimos_generated.geometry_msgs.msg import PoseStamped, Twist from dimos_generated.sensor_msgs.msg import Image, PointCloud2 +from dimos_message_build.registry import schema as cdr_schema from dimos.constants import DIMOS_PROJECT_ROOT diff --git a/dimos/teleop/hosted/arm_command.py b/dimos/teleop/hosted/arm_command.py index 06fea2a3bfd..e4e2ba46333 100644 --- a/dimos/teleop/hosted/arm_command.py +++ b/dimos/teleop/hosted/arm_command.py @@ -27,6 +27,7 @@ from dimos_cdrgen.registry import decode as cdr_decode from dimos_generated.geometry_msgs.msg import PoseStamped, Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Float32, Header +from dimos_message_build.registry import decode as cdr_decode from reactivex.disposable import Disposable from dimos.control.coordinator import ControlCoordinator diff --git a/dimos/teleop/hosted/hosted_stats.py b/dimos/teleop/hosted/hosted_stats.py index dcb73b889c3..07a240683f4 100644 --- a/dimos/teleop/hosted/hosted_stats.py +++ b/dimos/teleop/hosted/hosted_stats.py @@ -31,6 +31,7 @@ from dimos_cdrgen.registry import decode as cdr_decode from dimos_generated.dimos_msgs.msg import VideoStats from dimos_generated.geometry_msgs.msg import TwistStamped +from dimos_message_build.registry import decode as cdr_decode from reactivex.disposable import Disposable from dimos.core.core import rpc diff --git a/dimos/teleop/hosted/test_hosted_stats.py b/dimos/teleop/hosted/test_hosted_stats.py index 262770eef13..b7007a690b5 100644 --- a/dimos/teleop/hosted/test_hosted_stats.py +++ b/dimos/teleop/hosted/test_hosted_stats.py @@ -24,6 +24,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.core.module import Module diff --git a/dimos/teleop/phone/phone_teleop_module.py b/dimos/teleop/phone/phone_teleop_module.py index 654c78e9ffe..5217e77ccee 100644 --- a/dimos/teleop/phone/phone_teleop_module.py +++ b/dimos/teleop/phone/phone_teleop_module.py @@ -30,6 +30,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, schema as cdr_schema from dimos_generated.geometry_msgs.msg import Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Bool, Header +from dimos_message_build.registry import decode as cdr_decode, schema as cdr_schema from fastapi import WebSocket, WebSocketDisconnect from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles diff --git a/dimos/teleop/phone/test_phone_cdr.py b/dimos/teleop/phone/test_phone_cdr.py index 7595def569c..160489c6eee 100644 --- a/dimos/teleop/phone/test_phone_cdr.py +++ b/dimos/teleop/phone/test_phone_cdr.py @@ -24,6 +24,11 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Bool, Header +from dimos_message_build.registry import ( + decode as cdr_decode, + encode as cdr_encode, + schema as cdr_schema, +) from fastapi.testclient import TestClient import pytest diff --git a/dimos/teleop/utils/test_video_stats.py b/dimos/teleop/utils/test_video_stats.py index b622a602282..4cfd3b2926a 100644 --- a/dimos/teleop/utils/test_video_stats.py +++ b/dimos/teleop/utils/test_video_stats.py @@ -22,6 +22,11 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.dimos_msgs.msg import VideoStats from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import ( + decode as cdr_decode, + encode as cdr_encode, + schema as cdr_schema, +) import pytest from dimos.memory.store.sqlite import SqliteStore diff --git a/dimos/visualization/rerun/test_generated_entity_bridge.py b/dimos/visualization/rerun/test_generated_entity_bridge.py index ab7a6265912..51055074a22 100644 --- a/dimos/visualization/rerun/test_generated_entity_bridge.py +++ b/dimos/visualization/rerun/test_generated_entity_bridge.py @@ -17,6 +17,7 @@ from dimos_generated.dimos_msgs.msg import EntityMarker, EntityMarkers from dimos_generated.geometry_msgs.msg import Point from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import encode as cdr_encode, schema as cdr_schema import numpy as np import rerun as rr from rosbags.typesys import Stores, get_types_from_msg, get_typestore diff --git a/dimos/web/test_cockpit.py b/dimos/web/test_cockpit.py index 365ade1f2e9..4e2e6bcaaae 100644 --- a/dimos/web/test_cockpit.py +++ b/dimos/web/test_cockpit.py @@ -29,6 +29,7 @@ from dimos_generated.tf2_msgs.msg import TFMessage from dimos_generated.trajectory_msgs.msg import JointTrajectory from dimos_generated.visualization_msgs.msg import MarkerArray +from dimos_message_build.registry import schema as cdr_schema from langchain_core.messages import BaseMessage import pytest From 8813dc3af41b9778a0b0fedb074c065dd67341fc Mon Sep 17 00:00:00 2001 From: cc Date: Fri, 9 Oct 2026 11:45:15 -0700 Subject: [PATCH 05/11] docs: document native CDR limits and verify authoring workflows --- docs/development/message-limitations.md | 139 ++ examples/language-interop/cpp/main.cpp | 9 +- .../message-codegen/demo_aruco_detection.py | 31 +- .../message-codegen/demo_base_transport.py | 20 +- .../message-codegen/demo_bbox_navigation.py | 44 +- examples/message-codegen/demo_blueprint.py | 28 +- .../message-codegen/demo_camera_bridge.py | 45 +- .../message-codegen/demo_camera_mux_cdr.py | 5 +- .../message-codegen/demo_cloud_filters.py | 41 +- .../message-codegen/demo_command_center.py | 47 +- .../demo_coordinator_joints.py | 3 +- .../message-codegen/demo_detection_bbox.py | 3 +- .../demo_detection_projection.py | 27 +- .../demo_export_detection_fixture.py | 5 +- examples/message-codegen/demo_frontiers.py | 21 +- .../message-codegen/demo_galaxea_messages.py | 7 +- .../message-codegen/demo_go2_command_cdr.py | 11 +- .../message-codegen/demo_grasp_proposals.py | 5 +- examples/message-codegen/demo_grid_path.py | 27 +- .../message-codegen/demo_habitat_native.py | 19 +- .../message-codegen/demo_holonomic_path.py | 30 +- .../demo_holonomic_tracking.py | 23 +- examples/message-codegen/demo_hosted_map.py | 27 +- examples/message-codegen/demo_keyboard_cdr.py | 13 +- examples/message-codegen/demo_lidar.cpp | 6 +- examples/message-codegen/demo_live_bridge.py | 5 +- .../message-codegen/demo_marker_messages.py | 5 +- .../message-codegen/demo_message_helpers.py | 24 +- .../message-codegen/demo_mls_transformer.py | 48 +- examples/message-codegen/demo_movement.py | 25 +- examples/message-codegen/demo_native.py | 14 +- examples/message-codegen/demo_navigation.py | 47 +- .../demo_navigation_recording.py | 21 +- .../message-codegen/demo_navigation_skill.py | 10 +- examples/message-codegen/demo_occupancy.py | 5 +- .../message-codegen/demo_odometry_history.py | 64 +- .../message-codegen/demo_path_following.py | 25 +- examples/message-codegen/demo_patrol.py | 18 +- .../message-codegen/demo_person_follow.py | 27 +- examples/message-codegen/demo_phone_cdr.py | 3 +- .../message-codegen/demo_planning_backends.py | 31 +- .../message-codegen/demo_planning_joints.py | 19 +- examples/message-codegen/demo_pointcloud.py | 10 +- examples/message-codegen/demo_pubsub.py | 11 +- examples/message-codegen/demo_robot_tf.py | 3 +- examples/message-codegen/demo_ros_bridge.py | 21 +- examples/message-codegen/demo_self_filter.py | 12 +- examples/message-codegen/demo_video_stats.py | 3 +- .../message-codegen/demo_viewer_controls.py | 11 +- examples/message-codegen/demo_visual_servo.py | 24 +- examples/message-codegen/demo_vl_images.py | 8 +- examples/message-codegen/demo_vlm_image.py | 3 +- .../demo_whole_body_transport.py | 23 +- .../message-codegen/external-app/relay.cpp | 10 +- .../message-codegen/external-native/relay.cpp | 3 +- examples/message-project/demo_blueprint.py | 1 + examples/simplerobot/simplerobot.py | 26 +- .../src/dimos_generated/_types.pyi | 2038 ++++++++--------- .../builtin_interfaces/msg/__init__.pyi | 8 +- .../dimos_msgs/msg/__init__.pyi | 47 +- .../foxglove_msgs/msg/__init__.pyi | 2 +- .../geometry_msgs/msg/__init__.pyi | 104 +- .../dimos_generated/nav_msgs/msg/__init__.pyi | 29 +- .../sensor_msgs/msg/__init__.pyi | 86 +- .../shape_msgs/msg/__init__.pyi | 12 +- .../dimos_generated/std_msgs/msg/__init__.pyi | 95 +- .../dimos_generated/tf2_msgs/msg/__init__.pyi | 5 +- .../trajectory_msgs/msg/__init__.pyi | 17 +- .../vision_msgs/msg/__init__.pyi | 53 +- .../visualization_msgs/msg/__init__.pyi | 41 +- .../package/cpp/packages.json | 15 +- scripts/test_external_native_messages.sh | 37 +- 72 files changed, 2256 insertions(+), 1529 deletions(-) create mode 100644 docs/development/message-limitations.md diff --git a/docs/development/message-limitations.md b/docs/development/message-limitations.md new file mode 100644 index 00000000000..09888949b42 --- /dev/null +++ b/docs/development/message-limitations.md @@ -0,0 +1,139 @@ +# Native CDR proposal: accepted limitations + +The proposal directly uses rosbags 0.11.0 for Python, upstream ROSIDL/FastRTPS +with Fast CDR 2.4.0 for C++, and ros2msg 0.5.3 with re_cdr 0.1.0 for Rust. +On 2026-10-09 the user provisionally accepted the limitations below as non-blockers +for continuing this proposal. This is a scope decision, not evidence that malformed +input is safe or correctly decoded. No upstream patch or owned field codec was +added to conceal these behaviors. + +Use schema-matched CDR from trusted producers and recordings. The Python decoder +is **not a validation boundary for hostile or malformed input**. A trusted producer +can still have bugs; round-trip tests and transport authentication do not establish +parser safety. No denial-of-service or corruption of valid payloads was demonstrated +by the small cases below; malformed inputs can nevertheless become plausible, +unintended values. + +## The original 13 strict acceptance failures + +The assertions remain in `dimos/message_codegen/test_python_source.py`. Only the +exact failing parameters carry `xfail(strict=True)` with these identifiers. An +unexpected pass fails the check and requires reviewing the pin and limitation. +Run the original assertions without expected-failure handling using: + +```sh +python -m pytest --noconftest -o addopts='' --runxfail \ + dimos/message_codegen/test_python_source.py +``` + +With the accepted pin, this strict run has **8 passed, 13 failed**; the ordinary +run has **8 passed, 13 xfailed, 0 failed**. This distinction must remain visible in +validation reports. It is not an all-correct decoder result. + +### CDR-L01 + +**Exact-consumption policy: 3 cases.** A valid `Bool` followed by one, two or three +zero bytes is accepted, and those bytes disappear on re-encoding. Our original +rule required consuming the entire payload. Rosbags explicitly tolerates up to +three trailing bytes; framing and padding policies vary, so these tests do not +prove every padded sample is invalid CDR. The decoded boolean is unchanged. +Four extra bytes are still rejected in the ordinary, non-optimized test run. + +### CDR-L02 + +**String wire validity: 2 cases, little and big endian.** A declared string length +of zero, with no terminator, becomes an empty string. Ordinary CDR string lengths +include the NUL terminator. Re-encoding creates length one plus NUL. Some native +libraries also tolerate a zero-length null-string form; this tolerance does not +satisfy the original assertion. + +### CDR-L03 + +**String wire validity: 2 cases, little and big endian.** Length two with payload +`ab` and no NUL decodes as `a`. The decoder discards the final byte without +checking that it is a terminator. This is demonstrated truncation of malformed +input, not demonstrated corruption of a valid encoded string. + +### CDR-L04 + +**String wire validity: 2 cases, little and big endian.** Declared length +`0xffffffff` with only one NUL byte becomes an empty string. The upstream decoder +reads that length as signed `-1`; its returned body position is three although +five bytes were supplied. This demonstrates malformed/truncated-input acceptance, +not a demonstrated four-gigabyte allocation or denial-of-service. + +### CDR-L05 + +**Representation mismatch: 1 case.** Header `00 03 00 00` followed by byte `01` +is accepted as `Bool(True)`. Identifier `0003` means parameter-list CDR little +endian; it is not an unknown identifier, but this body is not a valid parameter +list and the proposal expects plain CDR (`0000` or `0001`). Rosbags interprets it +as plain little-endian CDR instead of rejecting the representation. + +### CDR-L06 + +**Boolean wire validity: 1 original case.** Boolean byte `02` becomes `True`, and +re-encoding changes it to `01`. The invalid value is normalized silently. +The separate existing array regression in `test_definitions.py` exercises the +same limitation in both byte orders: **2 additional explicit xfails**, not two +additional categories. Its valid padding and NaN checks remain ordinary tests. + +### CDR-L07 + +**Bounded-schema support: 1 case.** A valid `shape_msgs/msg/SolidPrimitive` with +three dimensions cannot encode/decode through the Python registry: it raises +`NotImplementedError`. This is a functionality gap. Valid bounded messages do +**not** currently work merely because the types can be constructed. + +### CDR-L08 + +**Bounded-schema error contract: 1 case.** The same type with four dimensions is +also rejected as unsupported, rather than with the assertion's expected bound +validation `ValueError`. It fails closed; this case does not demonstrate an +oversized value being accepted. No bound is silently truncated or removed. + +### CDR-L09 + +The original bounded `demo_msgs/msg/Telemetry` generation is retained as two +strict expected failures (C++ and Rust) in `test_native_libraries.py`. Its `.msg` +source is unchanged. These are additional manifestations of unsupported bounded +strings, not part of the original 13 Python decoder assertions. The built-in +catalog also has two endian-specific `CDR-L07` xfails for `SolidPrimitive`. + +## Other native API and schema limits + +Python encode/decode rejects every closure containing a bounded string or bounded +sequence. C++/Rust generation rejects bounded-string closures; Rust wide-string +mapping is also unvalidated and rejected. These failures remain errors at the +public boundary. The legacy `demo_msgs/msg/Telemetry` fixture contains both a +bounded string and bounded sequence. Its full three-language/default conformance +and derived viewer/package demos cannot be claimed as passing; its original +schema and assertions remain available for later library work. + +Python/Rust construction requires explicit fields. Python native classes do not +apply `.msg` defaults; Rust's upstream floating-default generation is disabled. +These are separate from the 13 wire/bounds cases. Native NumPy arrays and nested +values retain their library ownership/equality behavior; helpers supply explicit +copy/read-only-view contracts. Former pybind container methods are not the native +value API. Rosbags initializes Python classes and codecs in memory from installed +schemas; Python import does not compile native code or download dependencies. +Use the single frozen registry within a runtime process. Independent rosbags +reference stores replace its process-global `usertypes` module and can invalidate +ordinary pickle identities; run independent reference decoders in separate +processes. Oracle tests restore that global module after each case. + +C++ distribution is source-only with explicit, on-demand native preparation. +Prebuilt SDK products are out of scope. M20 SDK access, host multicast, Foxglove +sign-in and human visual acceptance are separate limits, not covered by these +expected failures. No benchmark acceptance is implied. + +## Source references and future changes + +- [Rosbags type system](https://ternaris.gitlab.io/rosbags/topics/typesys.html) +- [Rosbags decoder implementation](https://gitlab.com/ternaris/rosbags/-/blob/v0.11.0/src/rosbags/typesys/store.py) +- [OMG CDR string encoding](https://www.omg.org/cgi-bin/doc?formal%2F01-09-52.pdf=) +- [OMG representation identifiers](https://www.omg.org/spec/DDSI-RTPS/2.2/PDF) + +A future upstream version, finite boundary checks or a narrower contract requires +reviewing each expected failure explicitly. Do not broad-skip the suite, silently +relax its assertions, or add a new field codec to make the status green. diff --git a/examples/language-interop/cpp/main.cpp b/examples/language-interop/cpp/main.cpp index 9b50937e852..56574c11d55 100644 --- a/examples/language-interop/cpp/main.cpp +++ b/examples/language-interop/cpp/main.cpp @@ -1,3 +1,6 @@ +#include +#include +#include // C++ robot control example // Subscribes to robot pose and publishes twist commands @@ -8,7 +11,7 @@ #include #include -#include + class RobotController { public: @@ -16,7 +19,7 @@ class RobotController { void onPose(const lcm::ReceiveBuffer* buffer, const std::string&) { try { - const auto decoded = dimos::cdr::decode( + const auto decoded = dimos::native::cdr_decode( static_cast(buffer->data), buffer->data_size); const auto* msg = &decoded; const auto& pos = msg->pose.position; @@ -47,7 +50,7 @@ class RobotController { twist.angular.y = 0; twist.angular.z = std::sin(t) * 0.3; - const auto bytes = dimos::cdr::encode(twist); + const auto bytes = dimos::native::cdr_encode(twist); lcm_.publish("/cmd_vel#geometry_msgs.Twist", bytes.data(), bytes.size()); printf("[twist] linear=%.2f angular=%.2f\n", twist.linear.x, twist.angular.z); t += 0.1; diff --git a/examples/message-codegen/demo_aruco_detection.py b/examples/message-codegen/demo_aruco_detection.py index 5cdb47d58e3..22bb6aa2e9a 100644 --- a/examples/message-codegen/demo_aruco_detection.py +++ b/examples/message-codegen/demo_aruco_detection.py @@ -17,10 +17,11 @@ import cv2 from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 -from dimos_generated.sensor_msgs.msg import CameraInfo, Image +from dimos_generated.sensor_msgs.msg import CameraInfo, Image, RegionOfInterest from dimos_generated.std_msgs.msg import Header from dimos_generated.tf2_msgs.msg import TFMessage from dimos_generated.vision_msgs.msg import Detection3D, Detection3DArray +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.memory.type.observation import Observation @@ -36,12 +37,26 @@ def main() -> None: pixels[100:300, 100:300] = cv2.aruco.generateImageMarker(dictionary, 7, 200) header = Header(frame_id="camera", stamp=Time(sec=1700000000, nanosec=123456789)) image = image_from_array(pixels, encoding="mono8", header=header) - image = Image.decode(image.encode()) - camera = CameraInfo(width=400, height=400, k=[400, 0, 200, 0, 400, 200, 0, 0, 1]) + image = cdr_decode(cdr_encode(image), Image) + camera = CameraInfo( + width=400, + height=400, + k=np.array([400, 0, 200, 0, 400, 200, 0, 0, 1], dtype=np.float64), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + distortion_model="", + d=np.array([], dtype=np.float64), + r=np.zeros(9, dtype=np.float64), + p=np.zeros(12, dtype=np.float64), + binning_x=0, + binning_y=0, + roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), + ) tf = TransformStamped( - header=Header(frame_id="world"), + header=Header(frame_id="world", stamp=Time(sec=0, nanosec=0)), child_frame_id="camera", - transform=Transform(translation=Vector3(x=2), rotation=Quaternion(w=1)), + transform=Transform( + translation=Vector3(x=2, y=0.0, z=0.0), rotation=Quaternion(w=1, x=0.0, y=0.0, z=0.0) + ), ) found = detect_markers_in_image( image, @@ -51,7 +66,7 @@ def main() -> None: aruco_dictionary="DICT_4X4_50", ) assert len(found) == 1 - wire = Detection3D.decode(found[0].to_detection3d_msg().encode()) + wire = cdr_decode(found[0].to_detection3d_msg().encode(), Detection3D) assert wire.id == "7" assert wire.results[0].hypothesis.class_id == "DICT_4X4_50:7" assert wire.header.stamp == header.stamp @@ -68,14 +83,14 @@ def main() -> None: emit_empty_frames=True, ) arrays = list(MarkersPerFrame()(detector(iter([observation])))) - decoded_array = Detection3DArray.decode(arrays[0].data.encode()) + decoded_array = cdr_decode(arrays[0].data.encode(), Detection3DArray) assert len(decoded_array.detections) == 1 assert decoded_array.header.stamp == image.header.stamp print("Memory stream: image → marker observation → generated CDR array") publisher = MarkerTfModule() transforms: list[TFMessage] = [] unsubscribe = publisher.tf.subscribe( - lambda msg: transforms.append(TFMessage.decode(msg.encode())) + lambda msg: transforms.append(cdr_decode(msg.encode(), TFMessage)) ) try: publisher._process_detections(decoded_array) diff --git a/examples/message-codegen/demo_base_transport.py b/examples/message-codegen/demo_base_transport.py index 057b10ecd8f..0a202253f76 100644 --- a/examples/message-codegen/demo_base_transport.py +++ b/examples/message-codegen/demo_base_transport.py @@ -22,7 +22,9 @@ import uuid from demo_pubsub import free_port +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist, Vector3 +from dimos_generated.std_msgs.msg import Header from dimos.core.transport import LCMTransport, PubSubTransport, ZenohTransport from dimos.hardware.drive_trains.transport.adapter import TransportTwistAdapter @@ -68,14 +70,20 @@ def transport(topic: str, message_type: type, peer: int = 0) -> Any: def collect(message: Twist) -> None: received.append(message) - (stopped if message == Twist() else moving).set() + ( + stopped + if message + == Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + else moving + ).set() stack.callback(commands.subscribe(collect)) source = PoseStamped( pose=Pose( - position=Point(x=2.0, y=-1.0), - orientation=Quaternion(z=math.sqrt(0.5), w=math.sqrt(0.5)), - ) + position=Point(x=2.0, y=-1.0, z=0.0), + orientation=Quaternion(z=math.sqrt(0.5), w=math.sqrt(0.5), x=0.0, y=0.0), + ), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), ) def feedback_received() -> bool: @@ -93,7 +101,9 @@ def send_command() -> None: assert adapter.write_velocities([0.5, -0.2, 0.3]) retry_until(moving, send_command, timeout=5) - assert received[0] == Twist(linear=Vector3(x=0.5, y=-0.2), angular=Vector3(z=0.3)) + assert received[0] == Twist( + linear=Vector3(x=0.5, y=-0.2, z=0.0), angular=Vector3(z=0.3, x=0.0, y=0.0) + ) adapter.write_enable(False) assert stopped.wait(5), "Disabling the adapter did not deliver a generated stop command" assert adapter.read_velocities() == [0.0, 0.0, 0.0] diff --git a/examples/message-codegen/demo_bbox_navigation.py b/examples/message-codegen/demo_bbox_navigation.py index 5137c1642d4..249c64e9948 100644 --- a/examples/message-codegen/demo_bbox_navigation.py +++ b/examples/message-codegen/demo_bbox_navigation.py @@ -17,7 +17,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import PoseStamped -from dimos_generated.sensor_msgs.msg import CameraInfo +from dimos_generated.sensor_msgs.msg import CameraInfo, RegionOfInterest from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import ( BoundingBox2D, @@ -26,6 +26,8 @@ Point2D, Pose2D, ) +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode +import numpy as np from dimos.core.transport import LCMTransport from dimos.navigation.bbox_navigation import BBoxNavigationModule @@ -40,22 +42,46 @@ def main() -> None: ready = Event() received = Event() unsubscribe = module.goal_request.subscribe( - lambda value: (goals.append(PoseStamped.decode(value.encode())), received.set()) + lambda value: ( + goals.append(cdr_decode(value.encode(), PoseStamped)), + received.set(), + ) ) message = Detection2DArray( header=Header(frame_id="base_link", stamp=Time(sec=1700000000, nanosec=123456789)), - detections=[Detection2D(bbox=BoundingBox2D(center=Pose2D(position=Point2D(x=420, y=290))))], + detections=[ + Detection2D( + bbox=BoundingBox2D( + center=Pose2D(position=Point2D(x=420, y=290), theta=0.0), size_x=0.0, size_y=0.0 + ), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + results=[], + id="", + ) + ], ) try: module.start() module._on_detection(message) assert not goals - camera = CameraInfo(k=[500, 0, 320, 0, 250, 240, 0, 0, 1]) + camera = CameraInfo( + k=np.array([500, 0, 320, 0, 250, 240, 0, 0, 1], dtype=np.float64), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + height=0, + width=0, + distortion_model="", + d=np.array([], dtype=np.float64), + r=np.zeros(9, dtype=np.float64), + p=np.zeros(12, dtype=np.float64), + binning_x=0, + binning_y=0, + roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), + ) camera_unsubscribe = module.camera_info.subscribe(lambda _: ready.set()) - module.camera_info.transport.publish(CameraInfo.decode(camera.encode())) + module.camera_info.transport.publish(cdr_decode(cdr_encode(camera), CameraInfo)) assert ready.wait(2) camera_unsubscribe() - module.detection2d.transport.publish(Detection2DArray.decode(message.encode())) + module.detection2d.transport.publish(cdr_decode(cdr_encode(message), Detection2DArray)) assert received.wait(2) assert len(goals) == 1 goal = goals[0] @@ -65,7 +91,11 @@ def main() -> None: f"CDR goal: x={goal.pose.position.x:.2f}, y={goal.pose.position.y:.2f}, z={goal.pose.position.z:.2f} m" ) print("PASS: LCM calibration + bbox → generated goal with exact source header") - module._on_detection(Detection2DArray()) + module._on_detection( + Detection2DArray( + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), detections=[] + ) + ) assert len(goals) == 1 finally: unsubscribe() diff --git a/examples/message-codegen/demo_blueprint.py b/examples/message-codegen/demo_blueprint.py index 42e33a3f5a7..8b9cd373a6f 100644 --- a/examples/message-codegen/demo_blueprint.py +++ b/examples/message-codegen/demo_blueprint.py @@ -26,9 +26,12 @@ from unittest.mock import patch import uuid +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.dimos_msgs.msg import LineSegment3D, LineSegments3D from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.sensor_msgs.msg import Image +from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.core.coordination.blueprints import Blueprint, autoconnect @@ -83,7 +86,12 @@ def exchange(self, sample: int) -> str: self._image = None self._received.clear() lines = LineSegments3D( - segments=[LineSegment3D(start=Point(x=sample), end=Point(y=2), weight=sample)] + segments=[ + LineSegment3D( + start=Point(x=sample, y=0.0, z=0.0), end=Point(y=2, x=0.0, z=0.0), weight=sample + ) + ], + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), ) lines.header.stamp = time_from_nanoseconds(self._stamp) lines.header.frame_id = "map" @@ -93,11 +101,17 @@ def exchange(self, sample: int) -> str: step=1920, encoding="rgb8", data=np.full(640 * 480 * 3, sample % 256, dtype=np.uint8), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + is_bigendian=0, ) image.header.stamp = time_from_nanoseconds(self._stamp) image.header.frame_id = "camera" pose = PoseStamped( - header=lines.header, pose=Pose(position=Point(x=sample), orientation=Quaternion(w=1)) + header=lines.header, + pose=Pose( + position=Point(x=sample, y=0.0, z=0.0), + orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), + ), ) for _ in range(60): self.p0.publish(pose) @@ -110,13 +124,15 @@ def exchange(self, sample: int) -> str: f"Missing native relay reply for sample {sample}: " f"lines={self._lines is not None}, image={self._image is not None}" ) - expected = LineSegments3D.decode(lines.encode()) + expected = cdr_decode(cdr_encode(lines), LineSegments3D) expected.segments = [ - LineSegment3D(start=Point(x=sample), end=Point(y=2), weight=sample + 2) + LineSegment3D( + start=Point(x=sample, y=0.0, z=0.0), end=Point(y=2, x=0.0, z=0.0), weight=sample + 2 + ) ] - if self._lines.encode() != expected.encode(): + if self._lines.encode() != cdr_encode(expected): raise ValueError("Native custom message reply differs from the expected edits") - if self._image.encode() != image.encode(): + if self._image.encode() != cdr_encode(image): raise ValueError("Native image reply changed pixels or metadata") return ( f"sample {sample}: Python weight={sample} → C++ {sample + 1} → Rust {sample + 2}; " diff --git a/examples/message-codegen/demo_camera_bridge.py b/examples/message-codegen/demo_camera_bridge.py index 5f340f34027..dd4bc5af19a 100644 --- a/examples/message-codegen/demo_camera_bridge.py +++ b/examples/message-codegen/demo_camera_bridge.py @@ -17,8 +17,9 @@ from pathlib import Path from types import SimpleNamespace -from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion, Vector3 -from dimos_generated.sensor_msgs.msg import CameraInfo, CompressedImage +from dimos_generated.builtin_interfaces.msg import Time +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseWithCovariance, Quaternion, Vector3 +from dimos_generated.sensor_msgs.msg import CameraInfo, CompressedImage, RegionOfInterest from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import ( BoundingBox3D, @@ -43,16 +44,35 @@ def main() -> None: bridge._min_intervals = {} bridge._camera_infos = {} bridge._image_entities = set() - header = Header(frame_id="camera_optical") + header = Header(frame_id="camera_optical", stamp=Time(sec=0, nanosec=0)) pixels = np.zeros((120, 160, 3), dtype=np.uint8) pixels[:, :80, 0] = 255 pixels[:, 80:, 1] = 255 color = image_from_array(pixels, encoding="rgb8", header=header) - info = CameraInfo(header=header, width=160, height=120, k=[100, 0, 80, 0, 100, 60, 0, 0, 1]) + info = CameraInfo( + header=header, + width=160, + height=120, + k=np.array([100, 0, 80, 0, 100, 60, 0, 0, 1], dtype=np.float64), + distortion_model="", + d=np.array([], dtype=np.float64), + r=np.zeros(9, dtype=np.float64), + p=np.zeros(12, dtype=np.float64), + binning_x=0, + binning_y=0, + roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), + ) messages = [ ("color", color), ("camera_info", info), - ("jpeg", CompressedImage(header=header, format="jpeg", data=image_to_jpeg(color))), + ( + "jpeg", + CompressedImage( + header=header, + format="jpeg", + data=np.frombuffer(image_to_jpeg(color), dtype=np.uint8), + ), + ), ( "depth_mm", image_from_array( @@ -72,14 +92,25 @@ def main() -> None: Detection3D( id="4", bbox=BoundingBox3D( - center=Pose(position=Point(z=1), orientation=Quaternion(w=1)), + center=Pose( + position=Point(z=1, x=0.0, y=0.0), + orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), + ), size=Vector3(x=0.5, y=0.5, z=0.2), ), results=[ ObjectHypothesisWithPose( - hypothesis=ObjectHypothesis(class_id="demo-box", score=1) + hypothesis=ObjectHypothesis(class_id="demo-box", score=1), + pose=PoseWithCovariance( + pose=Pose( + position=Point(x=0.0, y=0.0, z=0.0), + orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), + ), + covariance=np.zeros(36, dtype=np.float64), + ), ) ], + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), ) ], ) diff --git a/examples/message-codegen/demo_camera_mux_cdr.py b/examples/message-codegen/demo_camera_mux_cdr.py index 8ba87f9aefb..2cb52fcc6c3 100644 --- a/examples/message-codegen/demo_camera_mux_cdr.py +++ b/examples/message-codegen/demo_camera_mux_cdr.py @@ -18,6 +18,7 @@ from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.core.module import Module @@ -46,8 +47,8 @@ def main() -> None: encoding="rgb8", header=Header(stamp=time_from_nanoseconds(stamp_ns + index), frame_id=camera), ) - mux._on_cam(camera, Image.decode(image.encode())) - output = Image.decode(mux.mux_image.publish.call_args.args[0].encode()) + mux._on_cam(camera, cdr_decode(cdr_encode(image), Image)) + output = cdr_decode(mux.mux_image.publish.call_args.args[0].encode(), Image) assert output.width == 100 and output.height == 36 assert to_nanoseconds(output.header.stamp) == stamp_ns + 1 assert output.header.frame_id == "camera_mux" diff --git a/examples/message-codegen/demo_cloud_filters.py b/examples/message-codegen/demo_cloud_filters.py index de8366f8bcd..8748dcbad4f 100644 --- a/examples/message-codegen/demo_cloud_filters.py +++ b/examples/message-codegen/demo_cloud_filters.py @@ -16,9 +16,11 @@ from typing import cast -from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped -from dimos_generated.sensor_msgs.msg import CameraInfo, PointCloud2 +from dimos_generated.builtin_interfaces.msg import Time +from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 +from dimos_generated.sensor_msgs.msg import CameraInfo, PointCloud2, RegionOfInterest from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.pointcloud import pointcloud_from_xyz @@ -33,15 +35,40 @@ def main() -> None: points = np.random.default_rng(42).normal(scale=0.05, size=(100, 3)) points[:, 2] += 2 points = np.vstack((points, [10, 10, -1])) - cloud = pointcloud_from_xyz(points, header=Header(frame_id="world")) - cloud = PointCloud2.decode(cloud.encode()) - transform = TransformStamped(transform=Transform(rotation=Quaternion(w=1))) + cloud = pointcloud_from_xyz( + points, header=Header(frame_id="world", stamp=Time(sec=0, nanosec=0)) + ) + cloud = cdr_decode(cdr_encode(cloud), PointCloud2) + transform = TransformStamped( + transform=Transform( + rotation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), translation=Vector3(x=0.0, y=0.0, z=0.0) + ), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + child_frame_id="", + ) # These geometric filters do not inspect the detection argument. detection = cast("Detection2DBBox", None) for name, operation in (("height", height_filter()), ("radius", radius_outlier())): - result = operation(detection, cloud, CameraInfo(), transform) + result = operation( + detection, + cloud, + CameraInfo( + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + height=0, + width=0, + distortion_model="", + d=np.array([], dtype=np.float64), + k=np.zeros(9, dtype=np.float64), + r=np.zeros(9, dtype=np.float64), + p=np.zeros(12, dtype=np.float64), + binning_x=0, + binning_y=0, + roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), + ), + transform, + ) assert result is not None - result = PointCloud2.decode(result.encode()) + result = cdr_decode(cdr_encode(result), PointCloud2) assert result.width == 100 and result.header == cloud.header print(f"{name}: 101 input points → {result.width} retained points; source header preserved") print("PASS: generated clouds survive filtering and CDR round trips") diff --git a/examples/message-codegen/demo_command_center.py b/examples/message-codegen/demo_command_center.py index 1732391893e..609167c72a9 100644 --- a/examples/message-codegen/demo_command_center.py +++ b/examples/message-codegen/demo_command_center.py @@ -17,8 +17,12 @@ import asyncio import json +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid, Path +from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode +import numpy as np from dimos.web.websocket_vis.websocket_vis_module import WebsocketVisModule @@ -27,24 +31,49 @@ def main() -> None: module = WebsocketVisModule() goals: list[PoseStamped] = [] unsubscribe = module.goal_request.subscribe( - lambda value: goals.append(PoseStamped.decode(value.encode())) + lambda value: goals.append(cdr_decode(value.encode(), PoseStamped)) ) try: module._create_server() - pose = PoseStamped(pose=Pose(position=Point(x=2, y=3), orientation=Quaternion(w=1))) - module._on_robot_pose(PoseStamped.decode(pose.encode())) - path = Path(poses=[pose, PoseStamped(pose=Pose(position=Point(x=5, y=3)))]) - module._on_path(Path.decode(path.encode())) + pose = PoseStamped( + pose=Pose( + position=Point(x=2, y=3, z=0.0), orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0) + ), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + ) + module._on_robot_pose(cdr_decode(cdr_encode(pose), PoseStamped)) + path = Path( + poses=[ + pose, + PoseStamped( + pose=Pose( + position=Point(x=5, y=3, z=0.0), + orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), + ), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + ), + ], + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + ) + module._on_path(cdr_decode(cdr_encode(path), Path)) grid = OccupancyGrid( info=MapMetaData( - width=2, height=2, resolution=1, origin=Pose(orientation=Quaternion(w=1)) + width=2, + height=2, + resolution=1, + origin=Pose( + orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), + position=Point(x=0.0, y=0.0, z=0.0), + ), + map_load_time=Time(sec=0, nanosec=0), ), - data=[100, 0, 0, -1], + data=np.array([100, 0, 0, -1], dtype=np.int8), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), ) - module._on_global_costmap(OccupancyGrid.decode(grid.encode())) + module._on_global_costmap(cdr_decode(cdr_encode(grid), OccupancyGrid)) assert module.sio is not None asyncio.run(module.sio.handlers["/"]["click"]("demo", [5, 3])) - assert goals[0].pose.position == Point(x=5, y=3) + assert goals[0].pose.position == Point(x=5, y=3, z=0.0) assert goals[0].header.frame_id == "world" print("Command-center state from CDR pose, path, and costmap:") print(json.dumps(module.vis_state, indent=2)) diff --git a/examples/message-codegen/demo_coordinator_joints.py b/examples/message-codegen/demo_coordinator_joints.py index 03749906c6e..c21fbf2fa19 100644 --- a/examples/message-codegen/demo_coordinator_joints.py +++ b/examples/message-codegen/demo_coordinator_joints.py @@ -18,6 +18,7 @@ import threading from dimos_generated.sensor_msgs.msg import JointState +from dimos_message_build.registry import decode as cdr_decode from dimos.control.components import HardwareComponent, HardwareType from dimos.control.coordinator import ControlCoordinator @@ -71,7 +72,7 @@ def receive(port: str, message: JointState) -> None: assert list(complete["right_arm_joints"].position) == [0.3, 0.4] assert len(complete["coordinator_joint_state"].position) == 4 for port, message in complete.items(): - assert JointState.decode(message.encode()) == message + assert cdr_decode(message.encode(), JointState) == message print( f"{port}: frame={message.header.frame_id}, names={list(message.name)}, q={list(message.position)}, stamp={to_nanoseconds(message.header.stamp)}" ) diff --git a/examples/message-codegen/demo_detection_bbox.py b/examples/message-codegen/demo_detection_bbox.py index 43a9b92bd98..70ba3abf48d 100644 --- a/examples/message-codegen/demo_detection_bbox.py +++ b/examples/message-codegen/demo_detection_bbox.py @@ -20,6 +20,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection2DArray +from dimos_message_build.registry import decode as cdr_decode import numpy as np from dimos.msgs.image import image_from_array, image_view @@ -45,7 +46,7 @@ def main() -> None: image=source, ) collection = ImageDetections2D(image=source, detections=[detection]) - array = Detection2DArray.decode(collection.to_ros_detection2d_array().encode()) + array = cdr_decode(collection.to_ros_detection2d_array().encode(), Detection2DArray) wire = array.detections[0] assert array.header == source.header assert wire.header == source.header diff --git a/examples/message-codegen/demo_detection_projection.py b/examples/message-codegen/demo_detection_projection.py index 78b58d18bc0..b33c55d32d4 100644 --- a/examples/message-codegen/demo_detection_projection.py +++ b/examples/message-codegen/demo_detection_projection.py @@ -22,8 +22,9 @@ TransformStamped, Vector3, ) -from dimos_generated.sensor_msgs.msg import CameraInfo, Image +from dimos_generated.sensor_msgs.msg import CameraInfo, Image, RegionOfInterest from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.image import image_from_array @@ -36,7 +37,7 @@ def main() -> None: depth = image_from_array( np.full((4, 4), 2000, dtype=np.uint16), encoding="16UC1", header=header ) - depth = Image.decode(depth.encode()) + depth = cdr_decode(cdr_encode(depth), Image) detection = Detection2DBBox( bbox=(0, 0, 3, 3), track_id=1, @@ -46,15 +47,29 @@ def main() -> None: ts=1700000000.0, image=depth, ) - camera = CameraInfo(width=4, height=4, k=[2, 0, 0, 0, 2, 0, 0, 0, 1]) + camera = CameraInfo( + width=4, + height=4, + k=np.array([2, 0, 0, 0, 2, 0, 0, 0, 1], dtype=np.float64), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + distortion_model="", + d=np.array([], dtype=np.float64), + r=np.zeros(9, dtype=np.float64), + p=np.zeros(12, dtype=np.float64), + binning_x=0, + binning_y=0, + roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), + ) transform = TransformStamped( - header=Header(frame_id="camera"), + header=Header(frame_id="camera", stamp=Time(sec=0, nanosec=0)), child_frame_id="world", - transform=Transform(translation=Vector3(x=-10), rotation=Quaternion(w=1)), + transform=Transform( + translation=Vector3(x=-10, y=0.0, z=0.0), rotation=Quaternion(w=1, x=0.0, y=0.0, z=0.0) + ), ) result = Detection3DPC.from_depth(detection, depth, camera, transform, filters=[]) assert result is not None - pose = PoseStamped.decode(result.pose.encode()) + pose = cdr_decode(result.pose.encode(), PoseStamped) assert pose.header.stamp == header.stamp assert pose.header.frame_id == "world" assert (pose.pose.position.x, pose.pose.position.y, pose.pose.position.z) == (11.5, 1.5, 2) diff --git a/examples/message-codegen/demo_export_detection_fixture.py b/examples/message-codegen/demo_export_detection_fixture.py index ae6a3ad0980..5088404599e 100644 --- a/examples/message-codegen/demo_export_detection_fixture.py +++ b/examples/message-codegen/demo_export_detection_fixture.py @@ -25,6 +25,7 @@ from dimos_generated.geometry_msgs.msg import PoseStamped from dimos_generated.sensor_msgs.msg import Image, PointCloud2 from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import encode as cdr_encode import numpy as np from numpy.core.multiarray import _reconstruct @@ -144,13 +145,13 @@ def nearest(kind: str, target: float) -> tuple[float, Path, Any]: np.testing.assert_array_equal(image_view(msg), value.data) else: msg = pose_from_webrtc_odometry(value) - data = msg.encode() + data = cdr_encode(msg) assert type(msg).decode(data).encode() == data name = f"{seek}-{kind}.cdr" (out / name).write_bytes(data) entry["streams"][kind] = { "file": name, - "msg_name": msg.msg_name, + "msg_name": msg.__msgtype__, "recorded_ts": ts, "source": str(p.relative_to(root)), "source_sha256": hashlib.sha256(p.read_bytes()).hexdigest(), diff --git a/examples/message-codegen/demo_frontiers.py b/examples/message-codegen/demo_frontiers.py index c19734d33f5..3b2b9e8a3b6 100644 --- a/examples/message-codegen/demo_frontiers.py +++ b/examples/message-codegen/demo_frontiers.py @@ -17,9 +17,10 @@ from pathlib import Path from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Pose, PoseStamped, Quaternion +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.memory.vis.space.space import Space @@ -36,19 +37,27 @@ def main() -> None: grid = OccupancyGrid( header=header, info=MapMetaData( - width=20, height=20, resolution=0.5, origin=Pose(orientation=Quaternion(w=1)) + width=20, + height=20, + resolution=0.5, + origin=Pose( + orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), + position=Point(x=0.0, y=0.0, z=0.0), + ), + map_load_time=Time(sec=0, nanosec=0), ), - data=cells.ravel(), + data=np.asarray(cells.ravel(), dtype=np.int8), ) explorer = WavefrontFrontierExplorer() try: - received = OccupancyGrid.decode(grid.encode()) + received = cdr_decode(cdr_encode(grid), OccupancyGrid) frontiers = explorer.detect_frontiers(grid_to_world(received, (5, 10)), received) assert len(frontiers) == 1 goal = PoseStamped( - header=received.header, pose=Pose(position=frontiers[0], orientation=Quaternion(w=1)) + header=received.header, + pose=Pose(position=frontiers[0], orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0)), ) - decoded = PoseStamped.decode(goal.encode()) + decoded = cdr_decode(cdr_encode(goal), PoseStamped) assert decoded.header == header assert decoded.pose.position.x == 5 and decoded.pose.position.y == 4.75 output = Path("build/message-codegen/demo/evidence/frontiers.svg") diff --git a/examples/message-codegen/demo_galaxea_messages.py b/examples/message-codegen/demo_galaxea_messages.py index e83894638ff..63735db466f 100644 --- a/examples/message-codegen/demo_galaxea_messages.py +++ b/examples/message-codegen/demo_galaxea_messages.py @@ -50,9 +50,12 @@ def receive(name: str, message: Any) -> None: robot._on_chassis_speed( TwistStamped( header=Header( - stamp=Time(sec=1700000000, nanosec=123456789 + index * 100000000) + stamp=Time(sec=1700000000, nanosec=123456789 + index * 100000000), + frame_id="", + ), + twist=Twist( + linear=Vector3(x=1.0, y=0.0, z=0.0), angular=Vector3(z=0.2, x=0.0, y=0.0) ), - twist=Twist(linear=Vector3(x=1.0), angular=Vector3(z=0.2)), ), None, ) diff --git a/examples/message-codegen/demo_go2_command_cdr.py b/examples/message-codegen/demo_go2_command_cdr.py index fc053c0b9cc..0451f7e2a24 100644 --- a/examples/message-codegen/demo_go2_command_cdr.py +++ b/examples/message-codegen/demo_go2_command_cdr.py @@ -19,6 +19,7 @@ from dimos_generated.geometry_msgs.msg import PoseStamped, Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.core.module import Module from dimos.msgs.time import time_from_nanoseconds @@ -36,15 +37,15 @@ def main() -> None: stamp_ns = time.time_ns() - 100_000_000 for offset in (0, 1): message = TwistStamped( - header=Header(stamp=time_from_nanoseconds(stamp_ns + offset)), - twist=Twist(linear=Vector3(x=99), angular=Vector3(z=-50)), + header=Header(stamp=time_from_nanoseconds(stamp_ns + offset), frame_id=""), + twist=Twist(linear=Vector3(x=99, y=0.0, z=0.0), angular=Vector3(z=-50, x=0.0, y=0.0)), ) - module._on_cmd_vel_in(TwistStamped.decode(message.encode())) + module._on_cmd_vel_in(cdr_decode(cdr_encode(message), TwistStamped)) assert module.tele_cmd_vel.publish.call_count == 2 - command = Twist.decode(module.tele_cmd_vel.publish.call_args.args[0].encode()) + command = cdr_decode(module.tele_cmd_vel.publish.call_args.args[0].encode(), Twist) assert command.linear.x == 1.5 and command.angular.z == -2 module._handle_nav_goal({"x": 2.5, "y": -1, "nonce": 1}) - goal = PoseStamped.decode(module.goal_request.publish.call_args.args[0].encode()) + goal = cdr_decode(module.goal_request.publish.call_args.args[0].encode(), PoseStamped) assert goal.header.frame_id == "world" and goal.pose.position.x == 2.5 module._estopped = True module._on_cmd_vel_in(message) diff --git a/examples/message-codegen/demo_grasp_proposals.py b/examples/message-codegen/demo_grasp_proposals.py index 3f2a0c99f94..e93fd4fd2ed 100644 --- a/examples/message-codegen/demo_grasp_proposals.py +++ b/examples/message-codegen/demo_grasp_proposals.py @@ -18,6 +18,7 @@ from dimos_generated.dimos_msgs.msg import GraspCandidateArray from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.manipulation.grasping.heuristic_grasp import HeuristicGraspModule @@ -37,9 +38,9 @@ def main() -> None: ) provider = HeuristicGraspModule() try: - proposals = provider.propose_grasps(PointCloud2.decode(cloud.encode())) + proposals = provider.propose_grasps(cdr_decode(cdr_encode(cloud), PointCloud2)) payload = proposals.encode() - received = GraspCandidateArray.decode(payload) + received = cdr_decode(payload, GraspCandidateArray) assert received.header == cloud.header assert len(received.candidates) == 1 candidate = received.candidates[0] diff --git a/examples/message-codegen/demo_grid_path.py b/examples/message-codegen/demo_grid_path.py index e82637cbe13..03b7345515b 100644 --- a/examples/message-codegen/demo_grid_path.py +++ b/examples/message-codegen/demo_grid_path.py @@ -20,9 +20,10 @@ from pathlib import Path as FilePath from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Pose, Quaternion +from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid, Path from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.mapping.occupancy.path_mask import make_path_mask @@ -42,11 +43,18 @@ def main() -> None: grid = OccupancyGrid( header=header, info=MapMetaData( - width=40, height=40, resolution=0.25, origin=Pose(orientation=Quaternion(w=1)) + width=40, + height=40, + resolution=0.25, + origin=Pose( + orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), + position=Point(x=0.0, y=0.0, z=0.0), + ), + map_load_time=Time(sec=0, nanosec=0), ), - data=cells.ravel(), + data=np.asarray(cells.ravel(), dtype=np.int8), ) - received = OccupancyGrid.decode(grid.encode()) + received = cdr_decode(cdr_encode(grid), OccupancyGrid) start = grid_to_world(received, (5, 5)) goal = grid_to_world(received, (35, 35)) output_dir = FilePath("build/message-codegen/demo/evidence") @@ -55,8 +63,15 @@ def main() -> None: name = "cpp" if use_cpp else "python" path = min_cost_astar(received, goal, start, use_cpp=use_cpp) assert path is not None - resampled = simple_resample_path(path, Pose(orientation=Quaternion(w=1)), 0.1) - decoded = Path.decode(resampled.encode()) + resampled = simple_resample_path( + path, + Pose( + orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), + position=Point(x=0.0, y=0.0, z=0.0), + ), + 0.1, + ) + decoded = cdr_decode(cdr_encode(resampled), Path) assert decoded.header == header assert all(pose.header == header for pose in decoded.poses) mask = make_path_mask(received, decoded, 0.1) diff --git a/examples/message-codegen/demo_habitat_native.py b/examples/message-codegen/demo_habitat_native.py index 587be189c71..5bf92641d03 100644 --- a/examples/message-codegen/demo_habitat_native.py +++ b/examples/message-codegen/demo_habitat_native.py @@ -19,10 +19,11 @@ from pathlib import Path import sys -from dimos_generated.geometry_msgs.msg import Twist +from dimos_generated.geometry_msgs.msg import Twist, Vector3 from dimos_generated.nav_msgs.msg import Odometry from dimos_generated.sensor_msgs.msg import CameraInfo, Image, PointCloud2 from dimos_generated.tf2_msgs.msg import TFMessage +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np root = Path(__file__).resolve().parents[2] @@ -80,10 +81,18 @@ header = value.transforms[0].header if name == "tf" else value.header assert header.stamp.sec == 12 and header.stamp.nanosec == 250000000 (output / (name + ".cdr")).write_bytes(payload) -assert Odometry.decode(payloads["odometry"][1]).pose.pose.position.x == 1 -assert PointCloud2.decode(payloads["cloud"][1]).row_step == 16 -assert TFMessage.decode(payloads["tf"][1]).transforms[1].transform.translation.z == 0.45 -assert Twist.decode(Twist().encode()).linear.x == 0 +assert cdr_decode(payloads["odometry"][1], Odometry).pose.pose.position.x == 1 +assert cdr_decode(payloads["cloud"][1], PointCloud2).row_step == 16 +assert cdr_decode(payloads["tf"][1], TFMessage).transforms[1].transform.translation.z == 0.45 +assert ( + cdr_decode( + cdr_encode( + Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + ), + Twist, + ).linear.x + == 0 +) print( json.dumps( { diff --git a/examples/message-codegen/demo_holonomic_path.py b/examples/message-codegen/demo_holonomic_path.py index ebcec9fd6dc..0ee291088ac 100644 --- a/examples/message-codegen/demo_holonomic_path.py +++ b/examples/message-codegen/demo_holonomic_path.py @@ -17,9 +17,11 @@ import math import time -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist +from dimos_generated.builtin_interfaces.msg import Time +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist, Vector3 from dimos_generated.nav_msgs.msg import Path from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.time import time_from_nanoseconds from dimos.navigation.dannav.holonomic_tc.module import DanHolonomicTCConfig, _HolonomicPathFollower @@ -30,12 +32,12 @@ def main() -> None: core = _HolonomicPathFollower( DanHolonomicTCConfig(speed_m_s=1.2, control_frequency=60.0, goal_tolerance=0.08) ) - command = Twist() + command = Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) stopped: list[str] = [] def receive(value: Twist) -> None: nonlocal command - command = Twist.decode(value.encode()) + command = cdr_decode(cdr_encode(value), Twist) subscription = core.cmd_vel.subscribe(receive) stop_subscription = core.stopped_navigating.subscribe(stopped.append) @@ -49,16 +51,22 @@ def odometry(tick: int) -> PoseStamped: stamp=time_from_nanoseconds(1700000000000000000 + round(tick * dt * 1e9)), ), pose=Pose( - position=Point(x=x, y=y), - orientation=Quaternion(z=math.sin(yaw / 2), w=math.cos(yaw / 2)), + position=Point(x=x, y=y, z=0.0), + orientation=Quaternion(z=math.sin(yaw / 2), w=math.cos(yaw / 2), x=0.0, y=0.0), ), ) - return PoseStamped.decode(value.encode()) + return cdr_decode(cdr_encode(value), PoseStamped) path = Path( - header=Header(frame_id="map"), + header=Header(frame_id="map", stamp=Time(sec=0, nanosec=0)), poses=[ - PoseStamped(pose=Pose(position=Point(x=px), orientation=Quaternion(w=1.0))) + PoseStamped( + pose=Pose( + position=Point(x=px, y=0.0, z=0.0), + orientation=Quaternion(w=1.0, x=0.0, y=0.0, z=0.0), + ), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + ) for px in (0.1, 1.0) ], ) @@ -67,14 +75,14 @@ def odometry(tick: int) -> PoseStamped: DanLocalPlannerConfig(lock_replan=0.5, resample_spacing_m=0.1, smoothing_window=3) ) gate.on_odom(odometry(0)) - committed = gate.on_planner_path(Path.decode(path.encode())) + committed = gate.on_planner_path(cdr_decode(cdr_encode(path), Path)) assert committed is not None - assert gate.on_planner_path(Path.decode(path.encode())) is None + assert gate.on_planner_path(cdr_decode(cdr_encode(path), Path)) is None print( f"Local planner committed {len(committed.poses)} resampled poses; duplicate replan held" ) core.handle_odom(odometry(0)) - core.start_planning(Path.decode(committed.encode())) + core.start_planning(cdr_decode(committed.encode(), Path)) for tick in range(300): if stopped: break diff --git a/examples/message-codegen/demo_holonomic_tracking.py b/examples/message-codegen/demo_holonomic_tracking.py index 097e7c4d166..37210ee175a 100644 --- a/examples/message-codegen/demo_holonomic_tracking.py +++ b/examples/message-codegen/demo_holonomic_tracking.py @@ -16,7 +16,8 @@ import math -from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion, Twist +from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion, Twist, Vector3 +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.navigation.dannav.holonomic_tc.command_limits import ( HolonomicCommandLimits, @@ -35,15 +36,23 @@ def main() -> None: limits = HolonomicCommandLimits(1.0, 1.0, 2.0, 2.0) controller = HolonomicTrackingController(k_position_per_s=2.0, k_yaw_per_s=1.0) controller.configure(limits) - target = Pose(position=Point(x=2.0, y=1.0), orientation=Quaternion(w=1.0)) - pose = Pose(orientation=Quaternion(w=1.0)) - command = Twist() + target = Pose( + position=Point(x=2.0, y=1.0, z=0.0), orientation=Quaternion(w=1.0, x=0.0, y=0.0, z=0.0) + ) + pose = Pose( + orientation=Quaternion(w=1.0, x=0.0, y=0.0, z=0.0), position=Point(x=0.0, y=0.0, z=0.0) + ) + command = Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) dt = 0.05 for tick in range(200): - reference = TrajectoryReferenceSample(tick * dt, Pose.decode(target.encode()), Twist()) - measured = TrajectoryMeasuredSample(tick * dt, Pose.decode(pose.encode()), command) + reference = TrajectoryReferenceSample( + tick * dt, + cdr_decode(cdr_encode(target), Pose), + Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)), + ) + measured = TrajectoryMeasuredSample(tick * dt, cdr_decode(cdr_encode(pose), Pose), command) raw = controller.control(reference, measured) - command = Twist.decode(clamp_holonomic_cmd_vel(command, raw, limits, dt).encode()) + command = cdr_decode(cdr_encode(clamp_holonomic_cmd_vel(command, raw, limits, dt)), Twist) pose.position.x += command.linear.x * dt pose.position.y += command.linear.y * dt if tick % 40 == 0: diff --git a/examples/message-codegen/demo_hosted_map.py b/examples/message-codegen/demo_hosted_map.py index 49d3858c807..50f64b0389f 100644 --- a/examples/message-codegen/demo_hosted_map.py +++ b/examples/message-codegen/demo_hosted_map.py @@ -18,8 +18,11 @@ import json from pathlib import Path -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped +from dimos_generated.builtin_interfaces.msg import Time +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid +from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.geometry import quaternion_from_euler @@ -36,13 +39,27 @@ def main() -> None: cells[20:44, 20:44] = 50 cells[28:36, 28:36] = 100 grid = OccupancyGrid( - info=MapMetaData(width=64, height=64, resolution=0.1), data=cells.ravel() + info=MapMetaData( + width=64, + height=64, + resolution=0.1, + map_load_time=Time(sec=0, nanosec=0), + origin=Pose( + position=Point(x=0.0, y=0.0, z=0.0), + orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), + ), + ), + data=np.asarray(cells.ravel(), dtype=np.int8), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), ) - module._on_costmap(OccupancyGrid.decode(grid.encode())) + module._on_costmap(cdr_decode(cdr_encode(grid), OccupancyGrid)) pose = PoseStamped( - pose=Pose(position=Point(x=3.2, y=3.2), orientation=quaternion_from_euler(0, 0, 1.0)) + pose=Pose( + position=Point(x=3.2, y=3.2, z=0.0), orientation=quaternion_from_euler(0, 0, 1.0) + ), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), ) - module._on_odom(PoseStamped.decode(pose.encode())) + module._on_odom(cdr_decode(cdr_encode(pose), PoseStamped)) assert [value["type"] for value in payloads] == ["map", "odom"] assert payloads[1]["yaw"] == 1.0 destination = Path("build/message-codegen/demo/evidence/hosted-map.png") diff --git a/examples/message-codegen/demo_keyboard_cdr.py b/examples/message-codegen/demo_keyboard_cdr.py index 51e3723eb47..d7b75d39dcb 100644 --- a/examples/message-codegen/demo_keyboard_cdr.py +++ b/examples/message-codegen/demo_keyboard_cdr.py @@ -14,8 +14,9 @@ """Exercise keyboard command and release events without a display or robot.""" -from dimos_generated.geometry_msgs.msg import Twist, TwistStamped +from dimos_generated.geometry_msgs.msg import Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Float32 +from dimos_message_build.registry import decode as cdr_decode import pygame from dimos.teleop.keyboard.keyboard_teleop_module import KeyboardTeleopModule @@ -27,9 +28,11 @@ def main() -> None: gripper: list[Float32] = [] subscriptions = [ module.ee_twist_command.subscribe( - lambda msg: commands.append(TwistStamped.decode(msg.encode())) + lambda msg: commands.append(cdr_decode(msg.encode(), TwistStamped)) + ), + module.gripper_command.subscribe( + lambda msg: gripper.append(cdr_decode(msg.encode(), Float32)) ), - module.gripper_command.subscribe(lambda msg: gripper.append(Float32.decode(msg.encode()))), ] try: held = {pygame.K_w, pygame.K_a} @@ -37,7 +40,9 @@ def main() -> None: assert commands[-1].twist.linear.y == 0.05 print("Release W while A remains held → CDR velocity: left 0.05 m/s") module._handle_pygame_event(pygame.event.Event(pygame.KEYUP, key=pygame.K_a), held) - assert commands[-1].twist == Twist() + assert commands[-1].twist == Twist( + linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0) + ) print("Release final motion key → CDR velocity: all six components zero") for key in [pygame.K_LEFTBRACKET, pygame.K_RIGHTBRACKET]: module._handle_pygame_event(pygame.event.Event(pygame.KEYDOWN, key=key), held) diff --git a/examples/message-codegen/demo_lidar.cpp b/examples/message-codegen/demo_lidar.cpp index 17bab0281b6..a777615c945 100644 --- a/examples/message-codegen/demo_lidar.cpp +++ b/examples/message-codegen/demo_lidar.cpp @@ -1,6 +1,8 @@ // Copyright 2026 Dimensional Inc. // SPDX-License-Identifier: Apache-2.0 +#include +#include #include #include #include @@ -18,8 +20,8 @@ int main() { point[3] = 0.5; } for (bool little : {true, false}) { - auto bytes = dimos::cdr::encode(cloud, little); - auto decoded = dimos::cdr::decode(bytes); + auto bytes = dimos::native::cdr_encode(cloud, little); + auto decoded = dimos::native::cdr_decode(bytes); assert(decoded == cloud); assert(decoded.header.stamp.sec == 1 && decoded.header.stamp.nanosec == 250000000); assert(decoded.width == 2 && decoded.fields.size() == 4 && decoded.data.size() == 32); diff --git a/examples/message-codegen/demo_live_bridge.py b/examples/message-codegen/demo_live_bridge.py index 7edbdcfa452..5b4663765d4 100644 --- a/examples/message-codegen/demo_live_bridge.py +++ b/examples/message-codegen/demo_live_bridge.py @@ -21,6 +21,7 @@ from typing import Any from uuid import uuid4 +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header import numpy as np @@ -98,7 +99,9 @@ def main() -> None: pixels[:, :80, 0] = 255 pixels[:, 80:, 2] = 255 message = image_from_array( - pixels, encoding="rgb8", header=Header(frame_id="camera_optical") + pixels, + encoding="rgb8", + header=Header(frame_id="camera_optical", stamp=Time(sec=0, nanosec=0)), ) for _ in range(10): sender.publish(Topic(channel, Image), message) diff --git a/examples/message-codegen/demo_marker_messages.py b/examples/message-codegen/demo_marker_messages.py index 90e97b3c1d0..ade184d7ddb 100644 --- a/examples/message-codegen/demo_marker_messages.py +++ b/examples/message-codegen/demo_marker_messages.py @@ -18,6 +18,7 @@ from dimos_generated.geometry_msgs.msg import Vector3 from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection3DArray +from dimos_message_build.registry import decode as cdr_decode import numpy as np from dimos.msgs.image import image_from_array @@ -41,7 +42,7 @@ def main() -> None: ts=0, image=image, center=Vector3(x=float(identifier), y=2, z=3), - size=Vector3(x=0.16, y=0.16), + size=Vector3(x=0.16, y=0.16, z=0.0), frame_id="world", marker_id=identifier, dictionary="DICT_APRILTAG_36h11", @@ -49,7 +50,7 @@ def main() -> None: for identifier in (7, 42) ] message = ImageDetections3D(image, markers).to_ros_detection3d_array() - decoded = Detection3DArray.decode(message.encode()) + decoded = cdr_decode(message.encode(), Detection3DArray) assert decoded.header.stamp == image.header.stamp for marker in decoded.detections: assert marker.results[0].hypothesis.class_id == f"DICT_APRILTAG_36h11:{marker.id}" diff --git a/examples/message-codegen/demo_message_helpers.py b/examples/message-codegen/demo_message_helpers.py index c84834403d7..cf6b8643e5f 100644 --- a/examples/message-codegen/demo_message_helpers.py +++ b/examples/message-codegen/demo_message_helpers.py @@ -16,10 +16,12 @@ from pathlib import Path +from dimos_generated.builtin_interfaces.msg import Duration, Time from dimos_generated.dimos_msgs.msg import LineSegment3D, LineSegments3D, TrajectoryStatus from dimos_generated.geometry_msgs.msg import Point from dimos_generated.sensor_msgs.msg import CameraInfo from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.camera_info import camera_info_from_yaml, intrinsic_matrix from dimos.msgs.time import ( @@ -31,25 +33,35 @@ def main() -> None: - message = LineSegments3D(segments=[LineSegment3D(start=Point(x=1), end=Point(y=2), weight=4)]) + message = LineSegments3D( + segments=[ + LineSegment3D(start=Point(x=1, y=0.0, z=0.0), end=Point(y=2, x=0.0, z=0.0), weight=4) + ], + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + ) message.header.stamp = time_from_nanoseconds(1_700_000_000_123_456_789) message.header.frame_id = "map" - decoded = LineSegments3D.decode(message.encode()) - print(f"{decoded.msg_name}: frame={decoded.header.frame_id}") + decoded = cdr_decode(cdr_encode(message), LineSegments3D) + print(f"{decoded.__msgtype__}: frame={decoded.header.frame_id}") print(f"Exact source nanoseconds: {to_nanoseconds(decoded.header.stamp)}") segment = decoded.segments[0] print(f"Segment: start.x={segment.start.x}, end.y={segment.end.y}, weight={segment.weight}") status = TrajectoryStatus( - state=TrajectoryStatus.EXECUTING, time_remaining=duration_from_seconds(1.25) + state=TrajectoryStatus.EXECUTING, + time_remaining=duration_from_seconds(1.25), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + progress=0.0, + time_elapsed=Duration(sec=0, nanosec=0), + error="", ) - remaining = TrajectoryStatus.decode(status.encode()).time_remaining + remaining = cdr_decode(cdr_encode(status), TrajectoryStatus).time_remaining print(f"Trajectory remaining: sec={remaining.sec}, nanosec={remaining.nanosec}") print(f"Seconds for a controller API: {to_seconds(remaining)}") calibration = camera_info_from_yaml( Path(__file__).resolve().parents[2] / "dimos/robot/unitree/go2/front_camera_720.yaml", header=Header(frame_id="camera_optical", stamp=message.header.stamp), ) - restored = CameraInfo.decode(calibration.encode()) + restored = cdr_decode(cdr_encode(calibration), CameraInfo) print(f"Camera calibration: {restored.width}x{restored.height}, {restored.distortion_model}") print(f"Camera source nanoseconds: {to_nanoseconds(restored.header.stamp)}") print(f"Intrinsic matrix (independent NumPy copy):\n{intrinsic_matrix(restored)}") diff --git a/examples/message-codegen/demo_mls_transformer.py b/examples/message-codegen/demo_mls_transformer.py index 548517a90f8..20c20f1ca5e 100644 --- a/examples/message-codegen/demo_mls_transformer.py +++ b/examples/message-codegen/demo_mls_transformer.py @@ -31,6 +31,7 @@ from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header from dimos_generated.tf2_msgs.msg import TFMessage +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import rerun as rr @@ -60,14 +61,17 @@ def main() -> None: edge = TransformStamped( header=cloud.header, child_frame_id="base_link", - transform=Transform(translation=Vector3(x=-2.0, y=-2.0, z=1.0), rotation=Quaternion(w=1.0)), + transform=Transform( + translation=Vector3(x=-2.0, y=-2.0, z=1.0), + rotation=Quaternion(w=1.0, x=0.0, y=0.0, z=0.0), + ), ) - tf.receive_transform(TransformStamped.decode(edge.encode())) + tf.receive_transform(cdr_decode(cdr_encode(edge), TransformStamped)) relay = StartRelay(world_frame="world") relay._tf = tf poses: list[PoseStamped] = [] unsubscribe = relay.start_pose.subscribe( - lambda value: poses.append(PoseStamped.decode(value.encode())) + lambda value: poses.append(cdr_decode(value.encode(), PoseStamped)) ) try: relay._on_tf(TFMessage(transforms=[edge])) @@ -84,17 +88,17 @@ def main() -> None: ts=0.0, pose=poses[0], tags={"region_bounds": (0.0, 0.0, 5.0, -1.0, 2.0)}, - _data=PointCloud2.decode(cloud.encode()), + _data=cdr_decode(cdr_encode(cloud), PointCloud2), ) ray_input = obs.derive(data=cloud, pose_tuple=(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)) [mapped] = list(RayTraceMap(voxel_size=0.2)(iter([ray_input]))) - mapped_cloud = PointCloud2.decode(mapped.data.encode()) + mapped_cloud = cdr_decode(mapped.data.encode(), PointCloud2) assert mapped_cloud.header.stamp.nanosec == 123456789 print( f"Ray-traced CDR local map: {mapped_cloud.width * mapped_cloud.height} points, frame={mapped_cloud.header.frame_id}" ) [result] = list(MLSPlan(goal=(2.0, 2.0, 0.0), voxel_size=0.2, robot_height=1.0)(iter([obs]))) - path = Path.decode(result.data.encode()) + path = cdr_decode(result.data.encode(), Path) assert result.tags["planned"] and len(path.poses) >= 2 assert path.header.stamp.nanosec == 123456789 print( @@ -110,21 +114,35 @@ def main() -> None: bridge._min_intervals = {} try: bridge._on_message( - TFMessage.decode(TFMessage(transforms=[edge]).encode()), SimpleNamespace(name="/tf") + cdr_decode(cdr_encode(TFMessage(transforms=[edge])), TFMessage), + SimpleNamespace(name="/tf"), ) finally: bridge.stop() bridge = RerunBridgeModule() bridge._min_intervals = {} try: - bridge._on_message(PointCloud2.decode(cloud.encode()), SimpleNamespace(name="/terrain")) - bridge._on_message(Path.decode(path.encode()), SimpleNamespace(name="/planned_path")) + bridge._on_message( + cdr_decode(cdr_encode(cloud), PointCloud2), SimpleNamespace(name="/terrain") + ) + bridge._on_message( + cdr_decode(cdr_encode(path), Path), SimpleNamespace(name="/planned_path") + ) grid = OccupancyGrid( header=path.header, - info=MapMetaData(width=2, height=2, resolution=1.0, origin=poses[0].pose), - data=[0, 100, -1, 50], + info=MapMetaData( + width=2, + height=2, + resolution=1.0, + origin=poses[0].pose, + map_load_time=Time(sec=0, nanosec=0), + ), + data=np.array([0, 100, -1, 50], dtype=np.int8), + ) + bridge._on_message( + cdr_decode(cdr_encode(grid), OccupancyGrid), + SimpleNamespace(name="/occupancy"), ) - bridge._on_message(OccupancyGrid.decode(grid.encode()), SimpleNamespace(name="/occupancy")) finally: bridge.stop() rr.log("world/ray_map", render_surface_map(mapped_cloud)) @@ -139,11 +157,15 @@ def main() -> None: LineSegment3D( start=Point(x=a.pose.position.x, y=a.pose.position.y, z=a.pose.position.z), end=Point(x=b.pose.position.x, y=b.pose.position.y, z=b.pose.position.z), + weight=1.0, ) for a, b in zip(path.poses, list(path.poses)[1:], strict=False) ], ) - rr.log("world/path_edges", render_node_edges(LineSegments3D.decode(segments.encode()))) + rr.log( + "world/path_edges", + render_node_edges(cdr_decode(cdr_encode(segments), LineSegments3D)), + ) rr.disconnect() assert output.stat().st_size > 0 print(f"Rerun recording: {output}") diff --git a/examples/message-codegen/demo_movement.py b/examples/message-codegen/demo_movement.py index 78dc166b23f..03bbe703c5e 100644 --- a/examples/message-codegen/demo_movement.py +++ b/examples/message-codegen/demo_movement.py @@ -17,6 +17,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Point, PointStamped, Twist, Vector3 from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.navigation.movement_manager.movement_manager import MovementManager @@ -26,24 +27,32 @@ def main() -> None: goals: list[PointStamped] = [] commands: list[Twist] = [] unsubs = [ - manager.goal.subscribe(lambda msg: goals.append(PointStamped.decode(msg.encode()))), - manager.cmd_vel.subscribe(lambda msg: commands.append(Twist.decode(msg.encode()))), + manager.goal.subscribe(lambda msg: goals.append(cdr_decode(msg.encode(), PointStamped))), + manager.cmd_vel.subscribe(lambda msg: commands.append(cdr_decode(msg.encode(), Twist))), ] try: clicked = PointStamped( header=Header(frame_id="map", stamp=Time(sec=1700000000, nanosec=123456789)), - point=Point(x=3, y=4), + point=Point(x=3, y=4, z=0.0), ) - manager._on_click(PointStamped.decode(clicked.encode())) + manager._on_click(cdr_decode(cdr_encode(clicked), PointStamped)) assert goals == [clicked] print("Click → CDR goal: (3, 4), map, 1700000000123456789 ns") - manager._on_nav(Twist(linear=Vector3(x=0.2))) - manager._on_teleop(Twist(linear=Vector3(x=0.5))) - manager._on_nav(Twist(linear=Vector3(x=0.9))) + manager._on_nav( + Twist(linear=Vector3(x=0.2, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + ) + manager._on_teleop( + Twist(linear=Vector3(x=0.5, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + ) + manager._on_nav( + Twist(linear=Vector3(x=0.9, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + ) assert [msg.linear.x for msg in commands] == [0.2, 0.5] print("Navigation: 0.2 m/s; teleop: 0.5 m/s; competing navigation suppressed") manager.config.tele_cooldown_sec = 0 - manager._on_nav(Twist(linear=Vector3(x=0.1))) + manager._on_nav( + Twist(linear=Vector3(x=0.1, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + ) assert commands[-1].linear.x == 0.1 print("Cooldown elapsed → navigation resumes at 0.1 m/s") print("PASS: generated click and velocity messages cross CDR output boundaries") diff --git a/examples/message-codegen/demo_native.py b/examples/message-codegen/demo_native.py index 5692d767480..228208b6be4 100644 --- a/examples/message-codegen/demo_native.py +++ b/examples/message-codegen/demo_native.py @@ -29,9 +29,12 @@ from urllib.parse import urlsplit import uuid +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.dimos_msgs.msg import LineSegment3D, LineSegments3D from dimos_generated.geometry_msgs.msg import Point from dimos_generated.sensor_msgs.msg import Image +from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import encode as cdr_encode import numpy as np from dimos.core.transport import LCMTransport, PubSubTransport, ZenohTransport @@ -151,7 +154,12 @@ def receive(value: Any, name: str = name) -> None: def demonstrate(backend: str, cpp: Path, rust: Path, evidence: Path) -> None: stamp = 1_700_000_000_123_456_789 - lines = LineSegments3D(segments=[LineSegment3D(start=Point(x=1), end=Point(y=2), weight=4)]) + lines = LineSegments3D( + segments=[ + LineSegment3D(start=Point(x=1, y=0.0, z=0.0), end=Point(y=2, x=0.0, z=0.0), weight=4) + ], + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + ) lines.header.frame_id = "map" lines.header.stamp = time_from_nanoseconds(stamp) image = Image( @@ -160,6 +168,8 @@ def demonstrate(backend: str, cpp: Path, rust: Path, evidence: Path) -> None: encoding="rgb8", step=1920, data=np.arange(640 * 480 * 3, dtype=np.uint8), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + is_bigendian=0, ) image.header.frame_id = "camera" image.header.stamp = time_from_nanoseconds(stamp) @@ -170,7 +180,7 @@ def demonstrate(backend: str, cpp: Path, rust: Path, evidence: Path) -> None: assert decoded_lines.header.frame_id == "map" assert decoded_lines.segments[0].start.x == 1 assert decoded_lines.segments[0].end.y == 2 - assert received["image"].encode() == image.encode() + assert received["image"].encode() == cdr_encode(image) print(f"{backend}: Python weight=4 → C++ weight=5 → Rust weight=6 → Python verified") print(f"{backend}: {len(image.data):,} image bytes and source nanoseconds={stamp} match") diff --git a/examples/message-codegen/demo_navigation.py b/examples/message-codegen/demo_navigation.py index 12e747ebe05..64d87a5bb52 100644 --- a/examples/message-codegen/demo_navigation.py +++ b/examples/message-codegen/demo_navigation.py @@ -24,10 +24,20 @@ from demo_pubsub import free_port from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Point, PointStamped, Pose, Quaternion, Twist +from dimos_generated.geometry_msgs.msg import ( + Point, + PointStamped, + Pose, + PoseWithCovariance, + Quaternion, + Twist, + TwistWithCovariance, + Vector3, +) from dimos_generated.nav_msgs.msg import OccupancyGrid, Odometry, Path from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Bool, Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.core.transport import LCMTransport, ZenohTransport @@ -108,7 +118,7 @@ def transport(name: str, message_type: type, peer: int) -> Any: x, y = np.meshgrid(np.arange(0, 6, 0.25), np.arange(0, 6, 0.25)) points = np.column_stack((x.ravel(), y.ravel(), np.zeros(x.size))) source = pointcloud_from_xyz(points, header=header) - voxels.add_frame(PointCloud2.decode(source.encode())) + voxels.add_frame(cdr_decode(cdr_encode(source), PointCloud2)) accumulated = voxels.get_global_pointcloud2() assert accumulated.header == header position = [1.0, 1.0, 0.0] @@ -118,10 +128,28 @@ def transport(name: str, message_type: type, peer: int) -> Any: received_paths: list[Path] = [] def feedback() -> None: - message = Odometry(header=header, child_frame_id="base_link") + message = Odometry( + header=header, + child_frame_id="base_link", + pose=PoseWithCovariance( + pose=Pose( + position=Point(x=0.0, y=0.0, z=0.0), + orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), + ), + covariance=np.zeros(36, dtype=np.float64), + ), + twist=TwistWithCovariance( + twist=Twist( + linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0) + ), + covariance=np.zeros(36, dtype=np.float64), + ), + ) message.pose.pose = Pose( - position=Point(x=position[0], y=position[1]), - orientation=Quaternion(z=math.sin(position[2] / 2), w=math.cos(position[2] / 2)), + position=Point(x=position[0], y=position[1], z=0.0), + orientation=Quaternion( + z=math.sin(position[2] / 2), w=math.cos(position[2] / 2), x=0.0, y=0.0 + ), ) odometry.publish(message) @@ -149,7 +177,7 @@ def initialized() -> bool: ) wait_until(initialized, timeout=5) - goals.publish(PointStamped(header=header, point=Point(x=3, y=1))) + goals.publish(PointStamped(header=header, point=Point(x=3, y=1, z=0.0))) assert arrived.wait(10), f"{backend}: navigation module did not report arrival" with lock: final = tuple(position) @@ -157,7 +185,12 @@ def initialized() -> bool: assert any(command.linear.x > 0 for command in commands) path = next(path for path in received_paths if len(path.poses)) assert path.header == header and all(pose.header == header for pose in path.poses) - wait_until(lambda: bool(commands) and commands[-1] == Twist(), timeout=5) + wait_until( + lambda: bool(commands) + and commands[-1] + == Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)), + timeout=5, + ) grid = module._planner._navigation_map.binary_costmap assert grid.header == header print( diff --git a/examples/message-codegen/demo_navigation_recording.py b/examples/message-codegen/demo_navigation_recording.py index e786d334aa5..3fa38af61cf 100644 --- a/examples/message-codegen/demo_navigation_recording.py +++ b/examples/message-codegen/demo_navigation_recording.py @@ -27,6 +27,8 @@ Quaternion, Transform, TransformStamped, + Twist, + TwistWithCovariance, Vector3, ) from dimos_generated.nav_msgs.msg import Odometry @@ -56,8 +58,8 @@ def main() -> None: header=Header(frame_id="lidar", stamp=stamp), ) pose = Pose( - position=Point(x=float(tick)), - orientation=Quaternion(z=math.sqrt(0.5), w=math.sqrt(0.5)), + position=Point(x=float(tick), y=0.0, z=0.0), + orientation=Quaternion(z=math.sqrt(0.5), w=math.sqrt(0.5), x=0.0, y=0.0), ) lidar.append(cloud, ts=timestamp) transforms.append( @@ -67,7 +69,8 @@ def main() -> None: header=Header(frame_id="world", stamp=stamp), child_frame_id="lidar", transform=Transform( - translation=Vector3(x=float(tick)), rotation=pose.orientation + translation=Vector3(x=float(tick), y=0.0, z=0.0), + rotation=pose.orientation, ), ) ] @@ -77,7 +80,17 @@ def main() -> None: odometry.append( Odometry( header=Header(frame_id="world", stamp=stamp), - pose=PoseWithCovariance(pose=pose), + pose=PoseWithCovariance( + pose=pose, covariance=np.zeros(36, dtype=np.float64) + ), + child_frame_id="", + twist=TwistWithCovariance( + twist=Twist( + linear=Vector3(x=0.0, y=0.0, z=0.0), + angular=Vector3(x=0.0, y=0.0, z=0.0), + ), + covariance=np.zeros(36, dtype=np.float64), + ), ), ts=timestamp, ) diff --git a/examples/message-codegen/demo_navigation_skill.py b/examples/message-codegen/demo_navigation_skill.py index 5a21c0d0892..f0561757c78 100644 --- a/examples/message-codegen/demo_navigation_skill.py +++ b/examples/message-codegen/demo_navigation_skill.py @@ -17,7 +17,10 @@ import math from unittest.mock import Mock, patch +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped +from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.agents.skills.navigation import NavigationSkillContainer @@ -37,14 +40,15 @@ def main() -> None: pose=Pose( position=Point(x=1, y=2, z=3), orientation=quaternion_from_euler(0.2, -0.3, math.pi / 2), - ) + ), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), ) - skill._on_odom(PoseStamped.decode(original.encode())) + skill._on_odom(cdr_decode(cdr_encode(original), PoseStamped)) print(skill.tag_location("desk")) location = memory.tag_location.call_args.args[0] memory.query_tagged_location.return_value = location print(skill._navigate_by_tagged_location("desk")) - goal = PoseStamped.decode(navigator.set_goal.call_args.args[0].encode()) + goal = cdr_decode(navigator.set_goal.call_args.args[0].encode(), PoseStamped) np.testing.assert_allclose( quaternion_euler(goal.pose.orientation), (0.2, -0.3, math.pi / 2) ) diff --git a/examples/message-codegen/demo_occupancy.py b/examples/message-codegen/demo_occupancy.py index cfb17f57dff..377c0057e0b 100644 --- a/examples/message-codegen/demo_occupancy.py +++ b/examples/message-codegen/demo_occupancy.py @@ -23,6 +23,7 @@ from dimos_generated.nav_msgs.msg import OccupancyGrid from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.mapping.occupancy.inflation import simple_inflate @@ -37,9 +38,9 @@ def main() -> None: points = np.column_stack((x.ravel(), y.ravel(), np.zeros(x.size))) points[(points[:, 0] > 1.8) & (points[:, 0] < 2.2), 2] = 1 header = Header(stamp=Time(sec=1700000000, nanosec=123456789), frame_id="map") - cloud = PointCloud2.decode(pointcloud_from_xyz(points, header=header).encode()) + cloud = cdr_decode(cdr_encode(pointcloud_from_xyz(points, header=header)), PointCloud2) grid = general_occupancy(cloud, resolution=0.1) - inflated = OccupancyGrid.decode(simple_inflate(grid, 0.2).encode()) + inflated = cdr_decode(cdr_encode(simple_inflate(grid, 0.2)), OccupancyGrid) assert inflated.header == header before = np.count_nonzero(occupancy_view(grid) == 100) after = np.count_nonzero(occupancy_view(inflated) == 100) diff --git a/examples/message-codegen/demo_odometry_history.py b/examples/message-codegen/demo_odometry_history.py index 28e2f769a9f..7885b155da7 100644 --- a/examples/message-codegen/demo_odometry_history.py +++ b/examples/message-codegen/demo_odometry_history.py @@ -18,9 +18,20 @@ from pathlib import Path as FilePath from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist +from dimos_generated.geometry_msgs.msg import ( + Point, + Pose, + PoseStamped, + PoseWithCovariance, + Quaternion, + Twist, + TwistWithCovariance, + Vector3, +) from dimos_generated.nav_msgs.msg import Odometry, Path from dimos_generated.std_msgs.msg import Bool, Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode +import numpy as np from dimos.mapping.odometry_hist import OdometryHist, path_at_true_height from dimos.memory.vis.space.elements import Polyline @@ -34,35 +45,66 @@ async def main() -> None: commands: list[Twist] = [] arrivals: list[Bool] = [] paths: list[Path] = [] - follower.nav_cmd_vel.subscribe(lambda msg: commands.append(Twist.decode(msg.encode()))) - follower.goal_reached.subscribe(lambda msg: arrivals.append(Bool.decode(msg.encode()))) - history.odom_hist.subscribe(lambda msg: paths.append(Path.decode(msg.encode()))) + follower.nav_cmd_vel.subscribe(lambda msg: commands.append(cdr_decode(msg.encode(), Twist))) + follower.goal_reached.subscribe(lambda msg: arrivals.append(cdr_decode(msg.encode(), Bool))) + history.odom_hist.subscribe(lambda msg: paths.append(cdr_decode(msg.encode(), Path))) header = Header(stamp=Time(sec=1700000000, nanosec=123456789), frame_id="map") reference = Path( header=header, poses=[ - PoseStamped(header=header, pose=Pose(position=Point(x=x), orientation=Quaternion(w=1))) + PoseStamped( + header=header, + pose=Pose( + position=Point(x=x, y=0.0, z=0.0), + orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), + ), + ) for x in [0, 1, 2] ], ) try: - follower._on_path(Path.decode(reference.encode())) + follower._on_path(cdr_decode(cdr_encode(reference), Path)) waypoints = follower._waypoints assert waypoints is not None x = 0.0 for tick in range(100): header.stamp.nanosec = 123456789 + tick pose = PoseStamped( - header=header, pose=Pose(position=Point(x=x, z=0.25), orientation=Quaternion(w=1)) + header=header, + pose=Pose( + position=Point(x=x, z=0.25, y=0.0), + orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), + ), + ) + sample = Odometry( + header=header, + child_frame_id="", + pose=PoseWithCovariance( + pose=Pose( + position=Point(x=0.0, y=0.0, z=0.0), + orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), + ), + covariance=np.zeros(36, dtype=np.float64), + ), + twist=TwistWithCovariance( + twist=Twist( + linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0) + ), + covariance=np.zeros(36, dtype=np.float64), + ), ) - sample = Odometry(header=header) sample.pose.pose = pose.pose - await history.handle_odometry(Odometry.decode(sample.encode())) - follower._step(PoseStamped.decode(pose.encode()), waypoints) + await history.handle_odometry(cdr_decode(cdr_encode(sample), Odometry)) + follower._step(cdr_decode(cdr_encode(pose), PoseStamped), waypoints) if arrivals: break x += commands[-1].linear.x * 0.1 - assert arrivals and arrivals[-1].data and commands[-1] == Twist() + assert ( + arrivals + and arrivals[-1].data + and commands[-1] + == Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + ) assert x >= 1.7 and x <= 2 recorded = paths[-1] assert recorded.poses[0].header.stamp.nanosec == 123456789 diff --git a/examples/message-codegen/demo_path_following.py b/examples/message-codegen/demo_path_following.py index 37addcf1692..86d0df0d5b7 100644 --- a/examples/message-codegen/demo_path_following.py +++ b/examples/message-codegen/demo_path_following.py @@ -16,9 +16,11 @@ from pathlib import Path as FilePath -from dimos_generated.geometry_msgs.msg import PoseStamped, Twist, Vector3 +from dimos_generated.builtin_interfaces.msg import Time +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist, Vector3 from dimos_generated.nav_msgs.msg import Path from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.control.benchmarking.paths import straight_line, trajectory_to_svg from dimos.control.benchmarking.plant import ( @@ -36,11 +38,11 @@ def main() -> None: reference = straight_line(length=2.0) - reference.header = Header(frame_id="world") + reference.header = Header(frame_id="world", stamp=Time(sec=0, nanosec=0)) reference.poses = [ PoseStamped(header=reference.header, pose=pose.pose) for pose in reference.poses ] - received = Path.decode(reference.encode()) + received = cdr_decode(cdr_encode(reference), Path) names = ["base/vx", "base/vy", "base/wz"] task = PathFollowerTask( "demo", PathFollowerTaskConfig(joint_names=names, speed=0.5), GlobalConfig() @@ -48,7 +50,16 @@ def main() -> None: channel = FopdtChannelParams(K=1.0, tau=0.1, L=0.0) plant = TwistBasePlantSim(TwistBasePlantParams(vx=channel, vy=channel, wz=channel)) plant.reset(0.0, 0.0, 0.0, 0.1) - assert task.start_path(received, PoseStamped(header=received.header)) + assert task.start_path( + received, + PoseStamped( + header=received.header, + pose=Pose( + position=Point(x=0.0, y=0.0, z=0.0), + orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), + ), + ), + ) trace: list[tuple[float, float]] = [] for tick in range(200): state = CoordinatorState( @@ -65,8 +76,10 @@ def main() -> None: break assert command is not None vx, vy, wz = command.velocities - wire = Twist(linear=Vector3(x=vx, y=vy), angular=Vector3(z=wz)).encode() - decoded = Twist.decode(wire) + wire = cdr_encode( + Twist(linear=Vector3(x=vx, y=vy, z=0.0), angular=Vector3(z=wz, x=0.0, y=0.0)) + ) + decoded = cdr_decode(wire, Twist) plant.step(decoded.linear.x, decoded.linear.y, decoded.angular.z, 0.1) assert task.get_state() == "arrived" assert abs(plant.x - 2.0) <= 0.2 and abs(plant.y) < 1e-9 diff --git a/examples/message-codegen/demo_patrol.py b/examples/message-codegen/demo_patrol.py index 6bb358146d4..67c8377bfd3 100644 --- a/examples/message-codegen/demo_patrol.py +++ b/examples/message-codegen/demo_patrol.py @@ -17,9 +17,10 @@ from pathlib import Path from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Pose, PoseStamped, Quaternion +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.memory.vis.space.space import Space @@ -36,11 +37,18 @@ def main() -> None: grid = OccupancyGrid( header=Header(frame_id="map", stamp=Time(sec=1700000000, nanosec=123456789)), info=MapMetaData( - width=24, height=24, resolution=0.5, origin=Pose(orientation=Quaternion(w=1)) + width=24, + height=24, + resolution=0.5, + origin=Pose( + orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), + position=Point(x=0.0, y=0.0, z=0.0), + ), + map_load_time=Time(sec=0, nanosec=0), ), - data=cells.ravel(), + data=np.asarray(cells.ravel(), dtype=np.int8), ) - grid = OccupancyGrid.decode(grid.encode()) + grid = cdr_decode(cdr_encode(grid), OccupancyGrid) for name in ("random", "coverage", "frontier"): router = create_patrol_router(name, 0.5) router.handle_occupancy_grid(grid) @@ -49,7 +57,7 @@ def main() -> None: for _ in range(5): goal = router.next_goal() assert goal is not None - goal = PoseStamped.decode(goal.encode()) + goal = cdr_decode(cdr_encode(goal), PoseStamped) assert goal.header == grid.header space.add(goal, color="#ff0000") router.handle_odom(goal) diff --git a/examples/message-codegen/demo_person_follow.py b/examples/message-codegen/demo_person_follow.py index 583322b065f..fcec5cbff7c 100644 --- a/examples/message-codegen/demo_person_follow.py +++ b/examples/message-codegen/demo_person_follow.py @@ -17,8 +17,11 @@ from types import SimpleNamespace from unittest.mock import MagicMock, patch -from dimos_generated.geometry_msgs.msg import Twist -from dimos_generated.sensor_msgs.msg import CameraInfo +from dimos_generated.builtin_interfaces.msg import Time +from dimos_generated.geometry_msgs.msg import Twist, Vector3 +from dimos_generated.sensor_msgs.msg import CameraInfo, RegionOfInterest +from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.agents.skills.person_follow import PersonFollowSkillContainer @@ -29,7 +32,19 @@ def main() -> None: - camera = CameraInfo(width=640, height=480, k=[500, 0, 320, 0, 500, 240, 0, 0, 1]) + camera = CameraInfo( + width=640, + height=480, + k=np.array([500, 0, 320, 0, 500, 240, 0, 0, 1], dtype=np.float64), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + distortion_model="", + d=np.array([], dtype=np.float64), + r=np.zeros(9, dtype=np.float64), + p=np.zeros(12, dtype=np.float64), + binning_x=0, + binning_y=0, + roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), + ) with patch("dimos.agents.skills.person_follow.create", return_value=MagicMock()): module = PersonFollowSkillContainer(camera_info=camera, g=GlobalConfig(simulation="")) image = image_from_array(np.zeros((480, 640, 3), dtype=np.uint8), encoding="rgb8") @@ -50,7 +65,7 @@ def main() -> None: commands: list[Twist] = [] def receive(value: Twist) -> None: - command = Twist.decode(value.encode()) + command = cdr_decode(cdr_encode(value), Twist) commands.append(command) print( f"CDR command: forward={command.linear.x:.2f} m/s, turn={command.angular.z:.2f} rad/s" @@ -66,7 +81,9 @@ def receive(value: Twist) -> None: assert thread is not None thread.join(timeout=2) assert not thread.is_alive() - assert commands[0].linear.x == 0.5 and commands[-1] == Twist() + assert commands[0].linear.x == 0.5 and commands[-1] == Twist( + linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0) + ) print("PASS: real control thread publishes motion, stops, and publishes zero") print("Tracker/model output is substituted; no inference or robot actuation.") finally: diff --git a/examples/message-codegen/demo_phone_cdr.py b/examples/message-codegen/demo_phone_cdr.py index b135a8c254a..6658fa2b7ff 100644 --- a/examples/message-codegen/demo_phone_cdr.py +++ b/examples/message-codegen/demo_phone_cdr.py @@ -20,6 +20,7 @@ import threading from dimos_generated.geometry_msgs.msg import TwistStamped +from dimos_message_build.registry import decode as cdr_decode import uvicorn from dimos.teleop.phone.phone_teleop_module import PhoneTeleopModule @@ -32,7 +33,7 @@ def __init__(self) -> None: def _on_sensors_bytes(self, data: bytes) -> None: super()._on_sensors_bytes(data) - self.received.put(TwistStamped.decode(data)) + self.received.put(cdr_decode(data, TwistStamped)) def main() -> None: diff --git a/examples/message-codegen/demo_planning_backends.py b/examples/message-codegen/demo_planning_backends.py index 4635ee62abb..888067f2865 100644 --- a/examples/message-codegen/demo_planning_backends.py +++ b/examples/message-codegen/demo_planning_backends.py @@ -21,6 +21,7 @@ from dimos_generated.sensor_msgs.msg import JointState from dimos_generated.std_msgs.msg import Header from dimos_generated.tf2_msgs.msg import TFMessage +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.manipulation.planning.groups.models import PlanningGroupDefinition @@ -59,17 +60,37 @@ def main() -> None: monitor = WorldMonitor(world=world) monitor.load_model(config) world.finalize() - start = JointState.decode( - JointState(name=config.joint_names, position=[-0.4, 0.3]).encode() + start = cdr_decode( + cdr_encode( + JointState( + name=config.joint_names, + position=np.array([-0.4, 0.3], dtype=np.float64), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + velocity=np.array([], dtype=np.float64), + effort=np.array([], dtype=np.float64), + ) + ), + JointState, + ) + goal = cdr_decode( + cdr_encode( + JointState( + name=config.joint_names, + position=np.array([0.4, -0.3], dtype=np.float64), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + velocity=np.array([], dtype=np.float64), + effort=np.array([], dtype=np.float64), + ) + ), + JointState, ) - goal = JointState.decode(JointState(name=config.joint_names, position=[0.4, -0.3]).encode()) result = RRTConnectPlanner().plan_joint_path(world, start, goal) assert result.is_success(), result path_points = interpolate_path(result.path, resolution=0.2) print(f"Drake model joints: {world.get_prepared_model().joint_space.names}") print(f"RRT result: {result.status.name}; interpolated waypoints={len(path_points)}") for index, point in enumerate(path_points): - decoded = JointState.decode(point.encode()) + decoded = cdr_decode(point.encode(), JointState) assert decoded == point assert world.check_config_collision_free(decoded) with world.scratch_context() as context: @@ -85,7 +106,7 @@ def main() -> None: ) pose = monitor.get_group_ee_pose("arm", decoded) transform = transform_from_pose(pose, child_frame_id="tool") - tf = TFMessage.decode(TFMessage(transforms=[transform]).encode()) + tf = cdr_decode(cdr_encode(TFMessage(transforms=[transform])), TFMessage) assert tf.transforms[0].header.stamp == decoded.header.stamp expected = np.array([np.cos(decoded.position[0]), np.sin(decoded.position[0]), 0.0]) np.testing.assert_allclose(pose_matrix(pose.pose)[:3, 3], expected, atol=1e-12) diff --git a/examples/message-codegen/demo_planning_joints.py b/examples/message-codegen/demo_planning_joints.py index e5a9f3f8b96..24e6b897b35 100644 --- a/examples/message-codegen/demo_planning_joints.py +++ b/examples/message-codegen/demo_planning_joints.py @@ -17,6 +17,8 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import JointState from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode +import numpy as np from dimos.manipulation.planning.groups.models import PlanningGroup from dimos.manipulation.planning.groups.utils import ( @@ -36,12 +38,21 @@ def main() -> None: source = JointState( header=Header(stamp=Time(sec=1700000000, nanosec=123456789), frame_id="robot"), name=["right/j1", "left/j2", "left/j1"], - position=[0.9, 0.3, -0.2], + position=np.array([0.9, 0.3, -0.2], dtype=np.float64), + velocity=np.array([], dtype=np.float64), + effort=np.array([], dtype=np.float64), ) - decoded = JointState.decode(source.encode()) + decoded = cdr_decode(cdr_encode(source), JointState) selected = filter_joint_state_to_selected_joints(decoded, group.joint_names) target = normalize_joint_target( - group, JointState(header=source.header, name=["left/j2", "left/j1"], position=[0.5, 0.1]) + group, + JointState( + header=source.header, + name=["left/j2", "left/j1"], + position=np.array([0.5, 0.1], dtype=np.float64), + velocity=np.array([], dtype=np.float64), + effort=np.array([], dtype=np.float64), + ), ) space = JointSpace( tuple( @@ -61,7 +72,7 @@ def main() -> None: assert positions.tolist() == [-0.2, 0.3] assert space.from_joint_state(target).tolist() == [0.1, 0.5] assert selected.header == target.header == source.header - assert JointState.decode(target.encode()) == target + assert cdr_decode(cdr_encode(target), JointState) == target print(f"Coordinator input: names={list(source.name)}, q={list(source.position)}") print(f"Selected {group.id}: names={list(selected.name)}, q={positions.tolist()}") print(f"Normalized target: q={list(target.position)}; within declared joint limits") diff --git a/examples/message-codegen/demo_pointcloud.py b/examples/message-codegen/demo_pointcloud.py index ffddace3d46..6b36b0fe5ac 100644 --- a/examples/message-codegen/demo_pointcloud.py +++ b/examples/message-codegen/demo_pointcloud.py @@ -19,7 +19,11 @@ import struct +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import PointCloud2, PointField +from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode +import numpy as np from dimos.msgs.pointcloud import pointcloud_view, pointcloud_xyz @@ -36,15 +40,17 @@ def main() -> None: point_step=20, row_step=32, is_bigendian=big_endian, - data=bytes(payload), + data=np.frombuffer(bytes(payload), dtype=np.uint8), fields=[ PointField(name="x", offset=0, datatype=7, count=1), PointField(name="y", offset=4, datatype=7, count=1), PointField(name="z", offset=8, datatype=7, count=1), PointField(name="tags", offset=12, datatype=4, count=2), ], + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + is_dense=False, ) - decoded = PointCloud2.decode(message.encode(little_endian=not big_endian)) + decoded = cdr_decode(cdr_encode(message, little_endian=not big_endian), PointCloud2) view = pointcloud_view(decoded) assert pointcloud_xyz(decoded).tolist() == [[1, 2, 3], [2, 2, 3]] assert view["tags"].tolist() == [[[7, 9]], [[7, 9]]] diff --git a/examples/message-codegen/demo_pubsub.py b/examples/message-codegen/demo_pubsub.py index fb1e51f0995..50403a013c4 100644 --- a/examples/message-codegen/demo_pubsub.py +++ b/examples/message-codegen/demo_pubsub.py @@ -22,9 +22,11 @@ from urllib.parse import urlsplit import uuid +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.dimos_msgs.msg import LineSegment3D, LineSegments3D from dimos_generated.geometry_msgs.msg import Point from dimos_generated.sensor_msgs.msg import Image +from dimos_generated.std_msgs.msg import Header import numpy as np from dimos.core.transport import LCMTransport, PubSubTransport, SHMTransport, ZenohTransport @@ -66,10 +68,17 @@ def demonstrate(backend: str) -> None: encoding="rgb8", step=1920, data=np.arange(640 * 480 * 3, dtype=np.uint8), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + is_bigendian=0, ) image.header.frame_id = "camera" image.header.stamp = time_from_nanoseconds(1_700_000_000_123_456_789) - lines = LineSegments3D(segments=[LineSegment3D(start=Point(x=1), end=Point(y=2), weight=4)]) + lines = LineSegments3D( + segments=[ + LineSegment3D(start=Point(x=1, y=0.0, z=0.0), end=Point(y=2, x=0.0, z=0.0), weight=4) + ], + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + ) lines.header.frame_id = "map" with ExitStack() as stack: pools = [ZenohSessionPool(), ZenohSessionPool()] diff --git a/examples/message-codegen/demo_robot_tf.py b/examples/message-codegen/demo_robot_tf.py index c15045c4d21..9ec44405af9 100644 --- a/examples/message-codegen/demo_robot_tf.py +++ b/examples/message-codegen/demo_robot_tf.py @@ -15,6 +15,7 @@ """Inspect a Go2 device pose and generated CDR TF chain without connecting to a robot.""" from dimos_generated.tf2_msgs.msg import TFMessage +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.geometry import compose_transforms from dimos.msgs.time import to_nanoseconds @@ -25,7 +26,7 @@ def main() -> None: pose = pose_from_webrtc_odometry(raw_odometry_msg_sample) edges = GO2Connection._odom_to_tf(pose, prefix="robot0") - decoded = TFMessage.decode(TFMessage(transforms=edges).encode()) + decoded = cdr_decode(cdr_encode(TFMessage(transforms=edges)), TFMessage) assert len(decoded.transforms) == 3 print(f"Device pose: frame={pose.header.frame_id}, stamp={to_nanoseconds(pose.header.stamp)}") for edge in decoded.transforms: diff --git a/examples/message-codegen/demo_ros_bridge.py b/examples/message-codegen/demo_ros_bridge.py index 8f6dc033049..b0135b2853f 100644 --- a/examples/message-codegen/demo_ros_bridge.py +++ b/examples/message-codegen/demo_ros_bridge.py @@ -18,9 +18,11 @@ import uuid from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import encode as cdr_encode +import numpy as np from dimos.msgs.protocol import DimosMsg from dimos.protocol.pubsub.impl.rospubsub import DimosROS, ROSTopic @@ -43,7 +45,7 @@ def collect(message: DimosMsg, topic: ROSTopic) -> None: stamp = message.header.stamp key = (topic.topic, stamp.nanosec) received[key] = message - print(f"ROS received {message.msg_name}: source={stamp.sec}.{stamp.nanosec:09d}") + print(f"ROS received {message.__msgtype__}: source={stamp.sec}.{stamp.nanosec:09d}") if len(received) == 6: done.set() @@ -58,14 +60,21 @@ def publish_next() -> None: return header = Header(stamp=Time(sec=1700000000, nanosec=123456789 + count), frame_id="map") messages: list[DimosMsg] = [ - PoseStamped(header=header, pose=Pose(position=Point(x=float(count)))), + PoseStamped( + header=header, + pose=Pose( + position=Point(x=float(count), y=0.0, z=0.0), + orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), + ), + ), Image( header=header, height=1, width=1, encoding="rgb8", step=3, - data=bytes([count, 128, 255 - count]), + data=np.frombuffer(bytes([count, 128, 255 - count]), dtype=np.uint8), + is_bigendian=0, ), ] for topic, message in zip(topics, messages, strict=True): @@ -76,7 +85,9 @@ def publish_next() -> None: timer = node.create_timer(0.1, publish_next) try: assert done.wait(15), "ROS discovery or message delivery timed out" - assert received == expected + assert {key: cdr_encode(value) for key, value in received.items()} == { + key: cdr_encode(value) for key, value in expected.items() + } for index in range(3): pose = received[(topics[0].topic, 123456789 + index)] image = received[(topics[1].topic, 123456789 + index)] diff --git a/examples/message-codegen/demo_self_filter.py b/examples/message-codegen/demo_self_filter.py index 2dda6e584b3..f0c5cf08843 100644 --- a/examples/message-codegen/demo_self_filter.py +++ b/examples/message-codegen/demo_self_filter.py @@ -17,9 +17,10 @@ from pathlib import Path from tempfile import TemporaryDirectory -from dimos_generated.geometry_msgs.msg import Transform, TransformStamped, Vector3 +from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.manipulation.planning.utils.point_cloud_self_filter import PointCloudSelfFilter @@ -50,16 +51,19 @@ def main() -> None: TransformStamped( header=Header(frame_id=frame, stamp=stamp), child_frame_id="arm", - transform=Transform(translation=Vector3(x=arm_x)), + transform=Transform( + translation=Vector3(x=arm_x, y=0.0, z=0.0), + rotation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), + ), ) ) source = pointcloud_from_xyz( np.array([[arm_x, 0, 0], [5.0, 0, 0]]), header=Header(frame_id="camera", stamp=stamp), ) - result = module.filter_cloud(PointCloud2.decode(source.encode())) + result = module.filter_cloud(cdr_decode(cdr_encode(source), PointCloud2)) assert result is not None - filtered, mask = (PointCloud2.decode(value.encode()) for value in result) + filtered, mask = (cdr_decode(value.encode(), PointCloud2) for value in result) np.testing.assert_allclose(pointcloud_xyz(filtered), [[5.0, 0, 0]]) assert filtered.header == source.header assert mask.header.stamp == stamp and mask.header.frame_id == "world" diff --git a/examples/message-codegen/demo_video_stats.py b/examples/message-codegen/demo_video_stats.py index 63ee0f59c5a..c2e27387da3 100644 --- a/examples/message-codegen/demo_video_stats.py +++ b/examples/message-codegen/demo_video_stats.py @@ -18,6 +18,7 @@ import tempfile from dimos_generated.dimos_msgs.msg import VideoStats +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.memory.store.sqlite import SqliteStore from dimos.teleop.utils.video_stats import video_stats_from_dict @@ -34,7 +35,7 @@ def main() -> None: "frames_dropped": 2**32 + 1, } ) - decoded = VideoStats.decode(message.encode()) + decoded = cdr_decode(cdr_encode(message), VideoStats) assert decoded == message with tempfile.TemporaryDirectory() as directory: path = Path(directory) / "video.db" diff --git a/examples/message-codegen/demo_viewer_controls.py b/examples/message-codegen/demo_viewer_controls.py index c6a1ebfc3b4..ecdfbc246e9 100644 --- a/examples/message-codegen/demo_viewer_controls.py +++ b/examples/message-codegen/demo_viewer_controls.py @@ -18,7 +18,8 @@ import json from threading import Event -from dimos_generated.geometry_msgs.msg import PointStamped, Twist +from dimos_generated.geometry_msgs.msg import PointStamped, Twist, Vector3 +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import websockets.asyncio.client as ws_client from dimos.core.global_config import GlobalConfig @@ -34,13 +35,13 @@ def main() -> None: stopped = Event() def receive_velocity(message: Twist) -> None: - velocities.append(Twist.decode(message.encode())) + velocities.append(cdr_decode(cdr_encode(message), Twist)) if len(velocities) == 2: stopped.set() subscriptions = [ server.clicked_point.subscribe( - lambda message: points.append(PointStamped.decode(message.encode())) + lambda message: points.append(cdr_decode(message.encode(), PointStamped)) ), server.tele_cmd_vel.subscribe(receive_velocity), ] @@ -71,7 +72,9 @@ async def send_events() -> None: assert point.header.frame_id == "map" assert (point.header.stamp.sec, point.header.stamp.nanosec) == (1700000000, 123000000) assert velocities[0].linear.x == 0.5 and velocities[0].angular.z == 0.8 - assert velocities[1] == Twist() + assert velocities[1] == Twist( + linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0) + ) print("Viewer click → CDR PointStamped: map (1.5, 2.5, 0), stamp 1700000000.123000000") print("Viewer velocity → CDR Twist: forward 0.5 m/s, yaw 0.8 rad/s") print("Viewer stop → CDR Twist: all six components zero") diff --git a/examples/message-codegen/demo_visual_servo.py b/examples/message-codegen/demo_visual_servo.py index d34f864db09..856e19546d3 100644 --- a/examples/message-codegen/demo_visual_servo.py +++ b/examples/message-codegen/demo_visual_servo.py @@ -14,15 +14,31 @@ """Print CDR velocity commands for synthetic camera detections.""" +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Twist -from dimos_generated.sensor_msgs.msg import CameraInfo +from dimos_generated.sensor_msgs.msg import CameraInfo, RegionOfInterest +from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode +import numpy as np from dimos.navigation.visual_servoing.visual_servoing_2d import VisualServoing2D def main() -> None: - camera = CameraInfo(width=640, height=480, k=[500, 0, 320, 0, 500, 240, 0, 0, 1]) - controller = VisualServoing2D(CameraInfo.decode(camera.encode())) + camera = CameraInfo( + width=640, + height=480, + k=np.array([500, 0, 320, 0, 500, 240, 0, 0, 1], dtype=np.float64), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + distortion_model="", + d=np.array([], dtype=np.float64), + r=np.zeros(9, dtype=np.float64), + p=np.zeros(12, dtype=np.float64), + binning_x=0, + binning_y=0, + roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), + ) + controller = VisualServoing2D(cdr_decode(cdr_encode(camera), CameraInfo)) for label, bbox, expected in ( ("far", (270, 0, 370, 100), (0.5, 0)), ("target distance", (245, 0, 395, 100), (0, 0)), @@ -30,7 +46,7 @@ def main() -> None: ("right of center", (370, 0, 470, 100), (0.36, -0.2)), ): command = controller.compute_twist(bbox, camera.width) - decoded = Twist.decode(command.encode()) + decoded = cdr_decode(command.encode(), Twist) assert abs(decoded.linear.x - expected[0]) < 1e-9 assert abs(decoded.angular.z - expected[1]) < 1e-9 print(f"{label}: linear={decoded.linear.x:.2f} m/s, angular={decoded.angular.z:.2f} rad/s") diff --git a/examples/message-codegen/demo_vl_images.py b/examples/message-codegen/demo_vl_images.py index dc09d6c7b58..5706ed921ac 100644 --- a/examples/message-codegen/demo_vl_images.py +++ b/examples/message-codegen/demo_vl_images.py @@ -14,9 +14,11 @@ """Exercise generated image preparation with a fixed model response, offline.""" +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection2DArray +from dimos_message_build.registry import decode as cdr_decode import numpy as np from dimos.models.vl.base import VlModel @@ -33,13 +35,15 @@ def stop(self) -> None: def main() -> None: image = image_from_array( - np.zeros((40, 60, 3), dtype=np.uint8), encoding="rgb8", header=Header(frame_id="camera") + np.zeros((40, 60, 3), dtype=np.uint8), + encoding="rgb8", + header=Header(frame_id="camera", stamp=Time(sec=0, nanosec=0)), ) model = FixedResponseModel(auto_resize=(30, 20)) resized, scale = model._prepare_image(image) assert (resized.width, resized.height, scale) == (30, 20, 0.5) detections = model.query_detections(image, "target") - wire = Detection2DArray.decode(detections.to_ros_detection2d_array().encode()) + wire = cdr_decode(detections.to_ros_detection2d_array().encode(), Detection2DArray) assert wire.header == image.header and len(wire.detections) == 1 print("Generated image: 60x40 → 30x20, scale=0.5") print("Fixed model response → one generated CDR detection; source header preserved") diff --git a/examples/message-codegen/demo_vlm_image.py b/examples/message-codegen/demo_vlm_image.py index 1e682394973..91677583d07 100644 --- a/examples/message-codegen/demo_vlm_image.py +++ b/examples/message-codegen/demo_vlm_image.py @@ -19,6 +19,7 @@ from unittest.mock import Mock, patch from dimos_generated.sensor_msgs.msg import Image +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from langchain_core.messages import AIMessage import numpy as np @@ -36,7 +37,7 @@ def main() -> None: with patch("langchain.chat_models.init_chat_model", return_value=model): agent = VLMAgent() try: - result = agent.query_image(Image.decode(image.encode()), "Describe the colors") + result = agent.query_image(cdr_decode(cdr_encode(image), Image), "Describe the colors") request = model.invoke.call_args.args[0][-1] encoded = request.content[1]["image_url"]["url"].split(",", 1)[1] destination = Path("build/message-codegen/demo/evidence/vlm-request.jpg") diff --git a/examples/message-codegen/demo_whole_body_transport.py b/examples/message-codegen/demo_whole_body_transport.py index 66c2a234cde..27b0bddefe1 100644 --- a/examples/message-codegen/demo_whole_body_transport.py +++ b/examples/message-codegen/demo_whole_body_transport.py @@ -21,9 +21,12 @@ import uuid from demo_pubsub import free_port +from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.dimos_msgs.msg import MotorCommandArray from dimos_generated.geometry_msgs.msg import Quaternion, Vector3 from dimos_generated.sensor_msgs.msg import Imu, JointState +from dimos_generated.std_msgs.msg import Header +import numpy as np from dimos.core.transport import LCMTransport, PubSubTransport, ZenohTransport from dimos.hardware.whole_body.spec import MotorCommand @@ -77,9 +80,25 @@ def collect(message: MotorCommandArray) -> None: def feedback_received() -> bool: states.publish( - JointState(position=[0.25, -0.5], velocity=[0.1, 0.2], effort=[1.0, 2.0]) + JointState( + position=np.array([0.25, -0.5], dtype=np.float64), + velocity=np.array([0.1, 0.2], dtype=np.float64), + effort=np.array([1.0, 2.0], dtype=np.float64), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + name=[], + ) + ) + imu.publish( + Imu( + orientation=Quaternion(w=0.8, z=0.6, x=0.0, y=0.0), + angular_velocity=Vector3(z=0.2, x=0.0, y=0.0), + header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + orientation_covariance=np.zeros(9, dtype=np.float64), + angular_velocity_covariance=np.zeros(9, dtype=np.float64), + linear_acceleration=Vector3(x=0.0, y=0.0, z=0.0), + linear_acceleration_covariance=np.zeros(9, dtype=np.float64), + ) ) - imu.publish(Imu(orientation=Quaternion(w=0.8, z=0.6), angular_velocity=Vector3(z=0.2))) return adapter.has_motor_states() and adapter.read_imu().gyroscope[2] == 0.2 wait_until(feedback_received, timeout=5) diff --git a/examples/message-codegen/external-app/relay.cpp b/examples/message-codegen/external-app/relay.cpp index 9eced06291f..c88686ff4ce 100644 --- a/examples/message-codegen/external-app/relay.cpp +++ b/examples/message-codegen/external-app/relay.cpp @@ -1,5 +1,7 @@ -#include -#include + + +#include +#include #include #include #include @@ -8,10 +10,10 @@ int main(int argc, char** argv) { if (argc != 3) return 2; std::ifstream input(argv[1], std::ios::binary); std::vector bytes{std::istreambuf_iterator(input), {}}; - auto value = dimos::cdr::decode(bytes); + auto value = dimos::native::cdr_decode(bytes); std::cout << "Installed C++ package received: " << value.application_note << '\n'; value.application_note += "/cpp"; - auto encoded = dimos::cdr::encode(value); + auto encoded = dimos::native::cdr_encode(value); std::ofstream output(argv[2], std::ios::binary); output.write(reinterpret_cast(encoded.data()), encoded.size()); return output ? 0 : 1; diff --git a/examples/message-codegen/external-native/relay.cpp b/examples/message-codegen/external-native/relay.cpp index 30e5ff884fe..ccf9d209e42 100644 --- a/examples/message-codegen/external-native/relay.cpp +++ b/examples/message-codegen/external-native/relay.cpp @@ -1,8 +1,9 @@ // Copyright 2026 Dimensional Inc. // SPDX-License-Identifier: Apache-2.0 +#include #include "dimos/native.hpp" -#include + using demo_msgs::msg::Telemetry; using namespace dimos::native; diff --git a/examples/message-project/demo_blueprint.py b/examples/message-project/demo_blueprint.py index 117d650a438..a838f78c7b7 100644 --- a/examples/message-project/demo_blueprint.py +++ b/examples/message-project/demo_blueprint.py @@ -27,6 +27,7 @@ from dimos_cdrgen.registry import encode as cdr_encode from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import encode as cdr_encode from story_messages.story_msgs.msg import DeviceReading from dimos.core.coordination.blueprints import Blueprint, autoconnect diff --git a/examples/simplerobot/simplerobot.py b/examples/simplerobot/simplerobot.py index 74098974c2d..33563b451d5 100644 --- a/examples/simplerobot/simplerobot.py +++ b/examples/simplerobot/simplerobot.py @@ -25,7 +25,7 @@ import math import time -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Twist, Vector3 +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist, Vector3 from dimos_generated.std_msgs.msg import Header import reactivex as rx @@ -61,8 +61,10 @@ class SimpleRobot(Module): config: SimpleRobotConfig cmd_vel: In[Twist] pose: Out[PoseStamped] - _pose = Pose() - _vel = Twist() + _pose = Pose( + position=Point(x=0.0, y=0.0, z=0.0), orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0) + ) + _vel = Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) _vel_time = 0.0 @rpc @@ -84,7 +86,11 @@ def _update(self) -> None: now = time.time() dt = 1.0 / self.config.update_rate - vel = self._vel if now - self._vel_time < self.config.cmd_timeout else Twist() + vel = ( + self._vel + if now - self._vel_time < self.config.cmd_timeout + else Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + ) self._pose = apply_twist(self._pose, vel, dt) @@ -128,14 +134,20 @@ def _update(self) -> None: time.sleep(1) print("Forward...") for _ in range(8): - robot._on_twist(Twist(linear=Vector3(x=1.0))) + robot._on_twist( + Twist(linear=Vector3(x=1.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + ) time.sleep(0.25) print("Turn...") for _ in range(12): - robot._on_twist(Twist(linear=Vector3(x=0.5), angular=Vector3(z=0.5))) + robot._on_twist( + Twist(linear=Vector3(x=0.5, y=0.0, z=0.0), angular=Vector3(z=0.5, x=0.0, y=0.0)) + ) time.sleep(0.25) print("Stop") - robot._on_twist(Twist()) + robot._on_twist( + Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + ) time.sleep(1) else: while True: diff --git a/packages/dimos-generated/src/dimos_generated/_types.pyi b/packages/dimos-generated/src/dimos_generated/_types.pyi index 4298c0abf5f..cf6c9bc0286 100644 --- a/packages/dimos-generated/src/dimos_generated/_types.pyi +++ b/packages/dimos-generated/src/dimos_generated/_types.pyi @@ -17,18 +17,15 @@ if TYPE_CHECKING: from typing import ClassVar import numpy as np - from rosbags.interfaces.typing import Typesdict - @dataclass class builtin_interfaces__msg__Duration: """Class for builtin_interfaces/msg/Duration.""" sec: int nanosec: int - __msgtype__: ClassVar[str] = 'builtin_interfaces/msg/Duration' - + __msgtype__: ClassVar[str] = "builtin_interfaces/msg/Duration" @dataclass class builtin_interfaces__msg__Time: @@ -36,8 +33,7 @@ class builtin_interfaces__msg__Time: sec: int nanosec: int - __msgtype__: ClassVar[str] = 'builtin_interfaces/msg/Time' - + __msgtype__: ClassVar[str] = "builtin_interfaces/msg/Time" @dataclass class std_msgs__msg__Header: @@ -45,8 +41,7 @@ class std_msgs__msg__Header: stamp: builtin_interfaces__msg__Time frame_id: str - __msgtype__: ClassVar[str] = 'std_msgs/msg/Header' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Header" @dataclass class vision_msgs__msg__Point2D: @@ -54,8 +49,7 @@ class vision_msgs__msg__Point2D: x: float y: float - __msgtype__: ClassVar[str] = 'vision_msgs/msg/Point2D' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/Point2D" @dataclass class vision_msgs__msg__Pose2D: @@ -63,8 +57,7 @@ class vision_msgs__msg__Pose2D: position: vision_msgs__msg__Point2D theta: float - __msgtype__: ClassVar[str] = 'vision_msgs/msg/Pose2D' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/Pose2D" @dataclass class vision_msgs__msg__BoundingBox2D: @@ -73,8 +66,7 @@ class vision_msgs__msg__BoundingBox2D: center: vision_msgs__msg__Pose2D size_x: float size_y: float - __msgtype__: ClassVar[str] = 'vision_msgs/msg/BoundingBox2D' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/BoundingBox2D" @dataclass class dimos_msgs__msg__BoundingBox2DArray: @@ -82,8 +74,7 @@ class dimos_msgs__msg__BoundingBox2DArray: header: std_msgs__msg__Header boxes: list[vision_msgs__msg__BoundingBox2D] - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/BoundingBox2DArray' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/BoundingBox2DArray" @dataclass class geometry_msgs__msg__Point: @@ -92,8 +83,7 @@ class geometry_msgs__msg__Point: x: float y: float z: float - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Point' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Point" @dataclass class geometry_msgs__msg__Quaternion: @@ -103,8 +93,7 @@ class geometry_msgs__msg__Quaternion: y: float z: float w: float - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Quaternion' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Quaternion" @dataclass class geometry_msgs__msg__Pose: @@ -112,8 +101,7 @@ class geometry_msgs__msg__Pose: position: geometry_msgs__msg__Point orientation: geometry_msgs__msg__Quaternion - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Pose' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Pose" @dataclass class geometry_msgs__msg__Vector3: @@ -122,8 +110,7 @@ class geometry_msgs__msg__Vector3: x: float y: float z: float - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Vector3' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Vector3" @dataclass class vision_msgs__msg__BoundingBox3D: @@ -131,8 +118,7 @@ class vision_msgs__msg__BoundingBox3D: center: geometry_msgs__msg__Pose size: geometry_msgs__msg__Vector3 - __msgtype__: ClassVar[str] = 'vision_msgs/msg/BoundingBox3D' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/BoundingBox3D" @dataclass class dimos_msgs__msg__BoundingBox3DArray: @@ -140,8 +126,7 @@ class dimos_msgs__msg__BoundingBox3DArray: header: std_msgs__msg__Header boxes: list[vision_msgs__msg__BoundingBox3D] - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/BoundingBox3DArray' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/BoundingBox3DArray" @dataclass class dimos_msgs__msg__EntityMarker: @@ -151,8 +136,7 @@ class dimos_msgs__msg__EntityMarker: label: str entity_type: str position: geometry_msgs__msg__Point - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/EntityMarker' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/EntityMarker" @dataclass class dimos_msgs__msg__EntityMarkers: @@ -160,8 +144,7 @@ class dimos_msgs__msg__EntityMarkers: header: std_msgs__msg__Header markers: list[dimos_msgs__msg__EntityMarker] - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/EntityMarkers' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/EntityMarkers" @dataclass class dimos_msgs__msg__GraspCandidate: @@ -169,8 +152,7 @@ class dimos_msgs__msg__GraspCandidate: pose: geometry_msgs__msg__Pose score: float - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/GraspCandidate' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/GraspCandidate" @dataclass class dimos_msgs__msg__GraspCandidateArray: @@ -178,8 +160,7 @@ class dimos_msgs__msg__GraspCandidateArray: header: std_msgs__msg__Header candidates: list[dimos_msgs__msg__GraspCandidate] - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/GraspCandidateArray' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/GraspCandidateArray" @dataclass class dimos_msgs__msg__ImuInfo: @@ -191,8 +172,7 @@ class dimos_msgs__msg__ImuInfo: accel_noise_density: float accel_random_walk: float frequency: float - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/ImuInfo' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/ImuInfo" @dataclass class dimos_msgs__msg__JointCommand: @@ -200,8 +180,7 @@ class dimos_msgs__msg__JointCommand: header: std_msgs__msg__Header positions: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/JointCommand' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/JointCommand" @dataclass class dimos_msgs__msg__LineSegment3D: @@ -210,8 +189,7 @@ class dimos_msgs__msg__LineSegment3D: start: geometry_msgs__msg__Point end: geometry_msgs__msg__Point weight: float - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/LineSegment3D' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/LineSegment3D" @dataclass class dimos_msgs__msg__LineSegments3D: @@ -219,8 +197,7 @@ class dimos_msgs__msg__LineSegments3D: header: std_msgs__msg__Header segments: list[dimos_msgs__msg__LineSegment3D] - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/LineSegments3D' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/LineSegments3D" @dataclass class dimos_msgs__msg__MotorCommandArray: @@ -232,8 +209,7 @@ class dimos_msgs__msg__MotorCommandArray: kp: np.ndarray[tuple[int, ...], np.dtype[np.float64]] kd: np.ndarray[tuple[int, ...], np.dtype[np.float64]] tau: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/MotorCommandArray' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/MotorCommandArray" @dataclass class dimos_msgs__msg__RobotState: @@ -250,8 +226,7 @@ class dimos_msgs__msg__RobotState: tcp_pose: np.ndarray[tuple[int, ...], np.dtype[np.float64]] tcp_offset: np.ndarray[tuple[int, ...], np.dtype[np.float64]] joints: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/RobotState' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/RobotState" @dataclass class dimos_msgs__msg__TrajectoryStatus: @@ -268,8 +243,7 @@ class dimos_msgs__msg__TrajectoryStatus: COMPLETED: ClassVar[int] = 2 ABORTED: ClassVar[int] = 3 FAULT: ClassVar[int] = 4 - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/TrajectoryStatus' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/TrajectoryStatus" @dataclass class dimos_msgs__msg__VideoStats: @@ -286,8 +260,7 @@ class dimos_msgs__msg__VideoStats: frames_dropped: int freezes: int e2e_latency_ms: float - __msgtype__: ClassVar[str] = 'dimos_msgs/msg/VideoStats' - + __msgtype__: ClassVar[str] = "dimos_msgs/msg/VideoStats" @dataclass class foxglove_msgs__msg__CompressedVideo: @@ -297,8 +270,7 @@ class foxglove_msgs__msg__CompressedVideo: frame_id: str data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] format: str - __msgtype__: ClassVar[str] = 'foxglove_msgs/msg/CompressedVideo' - + __msgtype__: ClassVar[str] = "foxglove_msgs/msg/CompressedVideo" @dataclass class geometry_msgs__msg__Accel: @@ -306,8 +278,7 @@ class geometry_msgs__msg__Accel: linear: geometry_msgs__msg__Vector3 angular: geometry_msgs__msg__Vector3 - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Accel' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Accel" @dataclass class geometry_msgs__msg__AccelStamped: @@ -315,8 +286,7 @@ class geometry_msgs__msg__AccelStamped: header: std_msgs__msg__Header accel: geometry_msgs__msg__Accel - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/AccelStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/AccelStamped" @dataclass class geometry_msgs__msg__AccelWithCovariance: @@ -324,8 +294,7 @@ class geometry_msgs__msg__AccelWithCovariance: accel: geometry_msgs__msg__Accel covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/AccelWithCovariance' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/AccelWithCovariance" @dataclass class geometry_msgs__msg__AccelWithCovarianceStamped: @@ -333,8 +302,7 @@ class geometry_msgs__msg__AccelWithCovarianceStamped: header: std_msgs__msg__Header accel: geometry_msgs__msg__AccelWithCovariance - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/AccelWithCovarianceStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/AccelWithCovarianceStamped" @dataclass class geometry_msgs__msg__Inertia: @@ -348,8 +316,7 @@ class geometry_msgs__msg__Inertia: iyy: float iyz: float izz: float - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Inertia' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Inertia" @dataclass class geometry_msgs__msg__InertiaStamped: @@ -357,8 +324,7 @@ class geometry_msgs__msg__InertiaStamped: header: std_msgs__msg__Header inertia: geometry_msgs__msg__Inertia - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/InertiaStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/InertiaStamped" @dataclass class geometry_msgs__msg__Point32: @@ -367,8 +333,7 @@ class geometry_msgs__msg__Point32: x: float y: float z: float - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Point32' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Point32" @dataclass class geometry_msgs__msg__PointStamped: @@ -376,16 +341,14 @@ class geometry_msgs__msg__PointStamped: header: std_msgs__msg__Header point: geometry_msgs__msg__Point - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PointStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/PointStamped" @dataclass class geometry_msgs__msg__Polygon: """Class for geometry_msgs/msg/Polygon.""" points: list[geometry_msgs__msg__Point32] - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Polygon' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Polygon" @dataclass class geometry_msgs__msg__PolygonInstance: @@ -393,8 +356,7 @@ class geometry_msgs__msg__PolygonInstance: polygon: geometry_msgs__msg__Polygon id: int - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PolygonInstance' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/PolygonInstance" @dataclass class geometry_msgs__msg__PolygonInstanceStamped: @@ -402,8 +364,7 @@ class geometry_msgs__msg__PolygonInstanceStamped: header: std_msgs__msg__Header polygon: geometry_msgs__msg__PolygonInstance - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PolygonInstanceStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/PolygonInstanceStamped" @dataclass class geometry_msgs__msg__PolygonStamped: @@ -411,8 +372,7 @@ class geometry_msgs__msg__PolygonStamped: header: std_msgs__msg__Header polygon: geometry_msgs__msg__Polygon - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PolygonStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/PolygonStamped" @dataclass class geometry_msgs__msg__Pose2D: @@ -421,8 +381,7 @@ class geometry_msgs__msg__Pose2D: x: float y: float theta: float - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Pose2D' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Pose2D" @dataclass class geometry_msgs__msg__PoseArray: @@ -430,8 +389,7 @@ class geometry_msgs__msg__PoseArray: header: std_msgs__msg__Header poses: list[geometry_msgs__msg__Pose] - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PoseArray' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/PoseArray" @dataclass class geometry_msgs__msg__PoseStamped: @@ -439,8 +397,7 @@ class geometry_msgs__msg__PoseStamped: header: std_msgs__msg__Header pose: geometry_msgs__msg__Pose - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PoseStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/PoseStamped" @dataclass class geometry_msgs__msg__PoseWithCovariance: @@ -448,8 +405,7 @@ class geometry_msgs__msg__PoseWithCovariance: pose: geometry_msgs__msg__Pose covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PoseWithCovariance' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/PoseWithCovariance" @dataclass class geometry_msgs__msg__PoseWithCovarianceStamped: @@ -457,8 +413,7 @@ class geometry_msgs__msg__PoseWithCovarianceStamped: header: std_msgs__msg__Header pose: geometry_msgs__msg__PoseWithCovariance - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/PoseWithCovarianceStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/PoseWithCovarianceStamped" @dataclass class geometry_msgs__msg__QuaternionStamped: @@ -466,8 +421,7 @@ class geometry_msgs__msg__QuaternionStamped: header: std_msgs__msg__Header quaternion: geometry_msgs__msg__Quaternion - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/QuaternionStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/QuaternionStamped" @dataclass class geometry_msgs__msg__Transform: @@ -475,8 +429,7 @@ class geometry_msgs__msg__Transform: translation: geometry_msgs__msg__Vector3 rotation: geometry_msgs__msg__Quaternion - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Transform' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Transform" @dataclass class geometry_msgs__msg__TransformStamped: @@ -485,8 +438,7 @@ class geometry_msgs__msg__TransformStamped: header: std_msgs__msg__Header child_frame_id: str transform: geometry_msgs__msg__Transform - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/TransformStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/TransformStamped" @dataclass class geometry_msgs__msg__Twist: @@ -494,8 +446,7 @@ class geometry_msgs__msg__Twist: linear: geometry_msgs__msg__Vector3 angular: geometry_msgs__msg__Vector3 - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Twist' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Twist" @dataclass class geometry_msgs__msg__TwistStamped: @@ -503,8 +454,7 @@ class geometry_msgs__msg__TwistStamped: header: std_msgs__msg__Header twist: geometry_msgs__msg__Twist - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/TwistStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/TwistStamped" @dataclass class geometry_msgs__msg__TwistWithCovariance: @@ -512,8 +462,7 @@ class geometry_msgs__msg__TwistWithCovariance: twist: geometry_msgs__msg__Twist covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/TwistWithCovariance' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/TwistWithCovariance" @dataclass class geometry_msgs__msg__TwistWithCovarianceStamped: @@ -521,8 +470,7 @@ class geometry_msgs__msg__TwistWithCovarianceStamped: header: std_msgs__msg__Header twist: geometry_msgs__msg__TwistWithCovariance - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/TwistWithCovarianceStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/TwistWithCovarianceStamped" @dataclass class geometry_msgs__msg__Vector3Stamped: @@ -530,8 +478,7 @@ class geometry_msgs__msg__Vector3Stamped: header: std_msgs__msg__Header vector: geometry_msgs__msg__Vector3 - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Vector3Stamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Vector3Stamped" @dataclass class geometry_msgs__msg__VelocityStamped: @@ -541,8 +488,7 @@ class geometry_msgs__msg__VelocityStamped: body_frame_id: str reference_frame_id: str velocity: geometry_msgs__msg__Twist - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/VelocityStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/VelocityStamped" @dataclass class geometry_msgs__msg__VelocityWithCovarianceStamped: @@ -552,8 +498,7 @@ class geometry_msgs__msg__VelocityWithCovarianceStamped: body_frame_id: str reference_frame_id: str velocity: geometry_msgs__msg__TwistWithCovariance - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/VelocityWithCovarianceStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/VelocityWithCovarianceStamped" @dataclass class geometry_msgs__msg__Wrench: @@ -561,8 +506,7 @@ class geometry_msgs__msg__Wrench: force: geometry_msgs__msg__Vector3 torque: geometry_msgs__msg__Vector3 - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/Wrench' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/Wrench" @dataclass class geometry_msgs__msg__WrenchStamped: @@ -570,8 +514,7 @@ class geometry_msgs__msg__WrenchStamped: header: std_msgs__msg__Header wrench: geometry_msgs__msg__Wrench - __msgtype__: ClassVar[str] = 'geometry_msgs/msg/WrenchStamped' - + __msgtype__: ClassVar[str] = "geometry_msgs/msg/WrenchStamped" @dataclass class nav_msgs__msg__Goals: @@ -579,8 +522,7 @@ class nav_msgs__msg__Goals: header: std_msgs__msg__Header goals: list[geometry_msgs__msg__PoseStamped] - __msgtype__: ClassVar[str] = 'nav_msgs/msg/Goals' - + __msgtype__: ClassVar[str] = "nav_msgs/msg/Goals" @dataclass class nav_msgs__msg__GridCells: @@ -590,8 +532,7 @@ class nav_msgs__msg__GridCells: cell_width: float cell_height: float cells: list[geometry_msgs__msg__Point] - __msgtype__: ClassVar[str] = 'nav_msgs/msg/GridCells' - + __msgtype__: ClassVar[str] = "nav_msgs/msg/GridCells" @dataclass class nav_msgs__msg__MapMetaData: @@ -602,8 +543,7 @@ class nav_msgs__msg__MapMetaData: width: int height: int origin: geometry_msgs__msg__Pose - __msgtype__: ClassVar[str] = 'nav_msgs/msg/MapMetaData' - + __msgtype__: ClassVar[str] = "nav_msgs/msg/MapMetaData" @dataclass class nav_msgs__msg__OccupancyGrid: @@ -612,8 +552,7 @@ class nav_msgs__msg__OccupancyGrid: header: std_msgs__msg__Header info: nav_msgs__msg__MapMetaData data: np.ndarray[tuple[int, ...], np.dtype[np.int8]] - __msgtype__: ClassVar[str] = 'nav_msgs/msg/OccupancyGrid' - + __msgtype__: ClassVar[str] = "nav_msgs/msg/OccupancyGrid" @dataclass class nav_msgs__msg__Odometry: @@ -623,8 +562,7 @@ class nav_msgs__msg__Odometry: child_frame_id: str pose: geometry_msgs__msg__PoseWithCovariance twist: geometry_msgs__msg__TwistWithCovariance - __msgtype__: ClassVar[str] = 'nav_msgs/msg/Odometry' - + __msgtype__: ClassVar[str] = "nav_msgs/msg/Odometry" @dataclass class nav_msgs__msg__Path: @@ -632,8 +570,7 @@ class nav_msgs__msg__Path: header: std_msgs__msg__Header poses: list[geometry_msgs__msg__PoseStamped] - __msgtype__: ClassVar[str] = 'nav_msgs/msg/Path' - + __msgtype__: ClassVar[str] = "nav_msgs/msg/Path" @dataclass class nav_msgs__msg__TrajectoryPoint: @@ -644,8 +581,7 @@ class nav_msgs__msg__TrajectoryPoint: velocity: geometry_msgs__msg__Twist acceleration: geometry_msgs__msg__Accel effort: geometry_msgs__msg__Wrench - __msgtype__: ClassVar[str] = 'nav_msgs/msg/TrajectoryPoint' - + __msgtype__: ClassVar[str] = "nav_msgs/msg/TrajectoryPoint" @dataclass class nav_msgs__msg__Trajectory: @@ -653,8 +589,7 @@ class nav_msgs__msg__Trajectory: header: std_msgs__msg__Header points: list[nav_msgs__msg__TrajectoryPoint] - __msgtype__: ClassVar[str] = 'nav_msgs/msg/Trajectory' - + __msgtype__: ClassVar[str] = "nav_msgs/msg/Trajectory" @dataclass class sensor_msgs__msg__BatteryState: @@ -699,8 +634,7 @@ class sensor_msgs__msg__BatteryState: POWER_SUPPLY_TECHNOLOGY_LIMN: ClassVar[int] = 6 POWER_SUPPLY_TECHNOLOGY_TERNARY: ClassVar[int] = 7 POWER_SUPPLY_TECHNOLOGY_VRLA: ClassVar[int] = 8 - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/BatteryState' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/BatteryState" @dataclass class sensor_msgs__msg__RegionOfInterest: @@ -711,8 +645,7 @@ class sensor_msgs__msg__RegionOfInterest: height: int width: int do_rectify: bool - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/RegionOfInterest' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/RegionOfInterest" @dataclass class sensor_msgs__msg__CameraInfo: @@ -729,8 +662,7 @@ class sensor_msgs__msg__CameraInfo: binning_x: int binning_y: int roi: sensor_msgs__msg__RegionOfInterest - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/CameraInfo' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/CameraInfo" @dataclass class sensor_msgs__msg__ChannelFloat32: @@ -738,8 +670,7 @@ class sensor_msgs__msg__ChannelFloat32: name: str values: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/ChannelFloat32' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/ChannelFloat32" @dataclass class sensor_msgs__msg__CompressedImage: @@ -748,8 +679,7 @@ class sensor_msgs__msg__CompressedImage: header: std_msgs__msg__Header format: str data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/CompressedImage' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/CompressedImage" @dataclass class sensor_msgs__msg__FluidPressure: @@ -758,8 +688,7 @@ class sensor_msgs__msg__FluidPressure: header: std_msgs__msg__Header fluid_pressure: float variance: float - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/FluidPressure' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/FluidPressure" @dataclass class sensor_msgs__msg__Illuminance: @@ -768,8 +697,7 @@ class sensor_msgs__msg__Illuminance: header: std_msgs__msg__Header illuminance: float variance: float - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Illuminance' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/Illuminance" @dataclass class sensor_msgs__msg__Image: @@ -782,8 +710,7 @@ class sensor_msgs__msg__Image: is_bigendian: int step: int data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Image' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/Image" @dataclass class sensor_msgs__msg__Imu: @@ -796,8 +723,7 @@ class sensor_msgs__msg__Imu: angular_velocity_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] linear_acceleration: geometry_msgs__msg__Vector3 linear_acceleration_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Imu' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/Imu" @dataclass class sensor_msgs__msg__JointState: @@ -808,8 +734,7 @@ class sensor_msgs__msg__JointState: position: np.ndarray[tuple[int, ...], np.dtype[np.float64]] velocity: np.ndarray[tuple[int, ...], np.dtype[np.float64]] effort: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/JointState' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/JointState" @dataclass class sensor_msgs__msg__Joy: @@ -818,8 +743,7 @@ class sensor_msgs__msg__Joy: header: std_msgs__msg__Header axes: np.ndarray[tuple[int, ...], np.dtype[np.float32]] buttons: np.ndarray[tuple[int, ...], np.dtype[np.int32]] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Joy' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/Joy" @dataclass class sensor_msgs__msg__JoyFeedback: @@ -831,24 +755,21 @@ class sensor_msgs__msg__JoyFeedback: TYPE_LED: ClassVar[int] = 0 TYPE_RUMBLE: ClassVar[int] = 1 TYPE_BUZZER: ClassVar[int] = 2 - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/JoyFeedback' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/JoyFeedback" @dataclass class sensor_msgs__msg__JoyFeedbackArray: """Class for sensor_msgs/msg/JoyFeedbackArray.""" array: list[sensor_msgs__msg__JoyFeedback] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/JoyFeedbackArray' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/JoyFeedbackArray" @dataclass class sensor_msgs__msg__LaserEcho: """Class for sensor_msgs/msg/LaserEcho.""" echoes: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/LaserEcho' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/LaserEcho" @dataclass class sensor_msgs__msg__LaserScan: @@ -864,8 +785,7 @@ class sensor_msgs__msg__LaserScan: range_max: float ranges: np.ndarray[tuple[int, ...], np.dtype[np.float32]] intensities: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/LaserScan' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/LaserScan" @dataclass class sensor_msgs__msg__MagneticField: @@ -874,8 +794,7 @@ class sensor_msgs__msg__MagneticField: header: std_msgs__msg__Header magnetic_field: geometry_msgs__msg__Vector3 magnetic_field_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/MagneticField' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/MagneticField" @dataclass class sensor_msgs__msg__MultiDOFJointState: @@ -886,8 +805,7 @@ class sensor_msgs__msg__MultiDOFJointState: transforms: list[geometry_msgs__msg__Transform] twist: list[geometry_msgs__msg__Twist] wrench: list[geometry_msgs__msg__Wrench] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/MultiDOFJointState' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/MultiDOFJointState" @dataclass class sensor_msgs__msg__MultiEchoLaserScan: @@ -903,8 +821,7 @@ class sensor_msgs__msg__MultiEchoLaserScan: range_max: float ranges: list[sensor_msgs__msg__LaserEcho] intensities: list[sensor_msgs__msg__LaserEcho] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/MultiEchoLaserScan' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/MultiEchoLaserScan" @dataclass class sensor_msgs__msg__NavSatStatus: @@ -922,8 +839,7 @@ class sensor_msgs__msg__NavSatStatus: SERVICE_GLONASS: ClassVar[int] = 2 SERVICE_COMPASS: ClassVar[int] = 4 SERVICE_GALILEO: ClassVar[int] = 8 - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/NavSatStatus' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/NavSatStatus" @dataclass class sensor_msgs__msg__NavSatFix: @@ -940,8 +856,7 @@ class sensor_msgs__msg__NavSatFix: COVARIANCE_TYPE_APPROXIMATED: ClassVar[int] = 1 COVARIANCE_TYPE_DIAGONAL_KNOWN: ClassVar[int] = 2 COVARIANCE_TYPE_KNOWN: ClassVar[int] = 3 - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/NavSatFix' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/NavSatFix" @dataclass class sensor_msgs__msg__PointCloud: @@ -950,8 +865,7 @@ class sensor_msgs__msg__PointCloud: header: std_msgs__msg__Header points: list[geometry_msgs__msg__Point32] channels: list[sensor_msgs__msg__ChannelFloat32] - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/PointCloud' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/PointCloud" @dataclass class sensor_msgs__msg__PointField: @@ -969,8 +883,7 @@ class sensor_msgs__msg__PointField: UINT32: ClassVar[int] = 6 FLOAT32: ClassVar[int] = 7 FLOAT64: ClassVar[int] = 8 - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/PointField' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/PointField" @dataclass class sensor_msgs__msg__PointCloud2: @@ -985,8 +898,7 @@ class sensor_msgs__msg__PointCloud2: row_step: int data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] is_dense: bool - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/PointCloud2' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/PointCloud2" @dataclass class sensor_msgs__msg__Range: @@ -1001,8 +913,7 @@ class sensor_msgs__msg__Range: variance: float ULTRASOUND: ClassVar[int] = 0 INFRARED: ClassVar[int] = 1 - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Range' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/Range" @dataclass class sensor_msgs__msg__RelativeHumidity: @@ -1011,8 +922,7 @@ class sensor_msgs__msg__RelativeHumidity: header: std_msgs__msg__Header relative_humidity: float variance: float - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/RelativeHumidity' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/RelativeHumidity" @dataclass class sensor_msgs__msg__Temperature: @@ -1021,8 +931,7 @@ class sensor_msgs__msg__Temperature: header: std_msgs__msg__Header temperature: float variance: float - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/Temperature' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/Temperature" @dataclass class sensor_msgs__msg__TimeReference: @@ -1031,16 +940,14 @@ class sensor_msgs__msg__TimeReference: header: std_msgs__msg__Header time_ref: builtin_interfaces__msg__Time source: str - __msgtype__: ClassVar[str] = 'sensor_msgs/msg/TimeReference' - + __msgtype__: ClassVar[str] = "sensor_msgs/msg/TimeReference" @dataclass class shape_msgs__msg__MeshTriangle: """Class for shape_msgs/msg/MeshTriangle.""" vertex_indices: np.ndarray[tuple[int, ...], np.dtype[np.uint32]] - __msgtype__: ClassVar[str] = 'shape_msgs/msg/MeshTriangle' - + __msgtype__: ClassVar[str] = "shape_msgs/msg/MeshTriangle" @dataclass class shape_msgs__msg__Mesh: @@ -1048,16 +955,14 @@ class shape_msgs__msg__Mesh: triangles: list[shape_msgs__msg__MeshTriangle] vertices: list[geometry_msgs__msg__Point] - __msgtype__: ClassVar[str] = 'shape_msgs/msg/Mesh' - + __msgtype__: ClassVar[str] = "shape_msgs/msg/Mesh" @dataclass class shape_msgs__msg__Plane: """Class for shape_msgs/msg/Plane.""" coef: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = 'shape_msgs/msg/Plane' - + __msgtype__: ClassVar[str] = "shape_msgs/msg/Plane" @dataclass class shape_msgs__msg__SolidPrimitive: @@ -1080,24 +985,21 @@ class shape_msgs__msg__SolidPrimitive: CONE_HEIGHT: ClassVar[int] = 0 CONE_RADIUS: ClassVar[int] = 1 PRISM_HEIGHT: ClassVar[int] = 0 - __msgtype__: ClassVar[str] = 'shape_msgs/msg/SolidPrimitive' - + __msgtype__: ClassVar[str] = "shape_msgs/msg/SolidPrimitive" @dataclass class std_msgs__msg__Bool: """Class for std_msgs/msg/Bool.""" data: bool - __msgtype__: ClassVar[str] = 'std_msgs/msg/Bool' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Bool" @dataclass class std_msgs__msg__Byte: """Class for std_msgs/msg/Byte.""" data: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/Byte' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Byte" @dataclass class std_msgs__msg__MultiArrayDimension: @@ -1106,8 +1008,7 @@ class std_msgs__msg__MultiArrayDimension: label: str size: int stride: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/MultiArrayDimension' - + __msgtype__: ClassVar[str] = "std_msgs/msg/MultiArrayDimension" @dataclass class std_msgs__msg__MultiArrayLayout: @@ -1115,8 +1016,7 @@ class std_msgs__msg__MultiArrayLayout: dim: list[std_msgs__msg__MultiArrayDimension] data_offset: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/MultiArrayLayout' - + __msgtype__: ClassVar[str] = "std_msgs/msg/MultiArrayLayout" @dataclass class std_msgs__msg__ByteMultiArray: @@ -1124,16 +1024,14 @@ class std_msgs__msg__ByteMultiArray: layout: std_msgs__msg__MultiArrayLayout data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - __msgtype__: ClassVar[str] = 'std_msgs/msg/ByteMultiArray' - + __msgtype__: ClassVar[str] = "std_msgs/msg/ByteMultiArray" @dataclass class std_msgs__msg__Char: """Class for std_msgs/msg/Char.""" data: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/Char' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Char" @dataclass class std_msgs__msg__ColorRGBA: @@ -1143,24 +1041,21 @@ class std_msgs__msg__ColorRGBA: g: float b: float a: float - __msgtype__: ClassVar[str] = 'std_msgs/msg/ColorRGBA' - + __msgtype__: ClassVar[str] = "std_msgs/msg/ColorRGBA" @dataclass class std_msgs__msg__Empty: """Class for std_msgs/msg/Empty.""" structure_needs_at_least_one_member: int = 0 - __msgtype__: ClassVar[str] = 'std_msgs/msg/Empty' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Empty" @dataclass class std_msgs__msg__Float32: """Class for std_msgs/msg/Float32.""" data: float - __msgtype__: ClassVar[str] = 'std_msgs/msg/Float32' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Float32" @dataclass class std_msgs__msg__Float32MultiArray: @@ -1168,16 +1063,14 @@ class std_msgs__msg__Float32MultiArray: layout: std_msgs__msg__MultiArrayLayout data: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - __msgtype__: ClassVar[str] = 'std_msgs/msg/Float32MultiArray' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Float32MultiArray" @dataclass class std_msgs__msg__Float64: """Class for std_msgs/msg/Float64.""" data: float - __msgtype__: ClassVar[str] = 'std_msgs/msg/Float64' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Float64" @dataclass class std_msgs__msg__Float64MultiArray: @@ -1185,16 +1078,14 @@ class std_msgs__msg__Float64MultiArray: layout: std_msgs__msg__MultiArrayLayout data: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = 'std_msgs/msg/Float64MultiArray' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Float64MultiArray" @dataclass class std_msgs__msg__Int16: """Class for std_msgs/msg/Int16.""" data: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/Int16' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Int16" @dataclass class std_msgs__msg__Int16MultiArray: @@ -1202,16 +1093,14 @@ class std_msgs__msg__Int16MultiArray: layout: std_msgs__msg__MultiArrayLayout data: np.ndarray[tuple[int, ...], np.dtype[np.int16]] - __msgtype__: ClassVar[str] = 'std_msgs/msg/Int16MultiArray' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Int16MultiArray" @dataclass class std_msgs__msg__Int32: """Class for std_msgs/msg/Int32.""" data: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/Int32' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Int32" @dataclass class std_msgs__msg__Int32MultiArray: @@ -1219,16 +1108,14 @@ class std_msgs__msg__Int32MultiArray: layout: std_msgs__msg__MultiArrayLayout data: np.ndarray[tuple[int, ...], np.dtype[np.int32]] - __msgtype__: ClassVar[str] = 'std_msgs/msg/Int32MultiArray' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Int32MultiArray" @dataclass class std_msgs__msg__Int64: """Class for std_msgs/msg/Int64.""" data: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/Int64' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Int64" @dataclass class std_msgs__msg__Int64MultiArray: @@ -1236,16 +1123,14 @@ class std_msgs__msg__Int64MultiArray: layout: std_msgs__msg__MultiArrayLayout data: np.ndarray[tuple[int, ...], np.dtype[np.int64]] - __msgtype__: ClassVar[str] = 'std_msgs/msg/Int64MultiArray' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Int64MultiArray" @dataclass class std_msgs__msg__Int8: """Class for std_msgs/msg/Int8.""" data: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/Int8' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Int8" @dataclass class std_msgs__msg__Int8MultiArray: @@ -1253,24 +1138,21 @@ class std_msgs__msg__Int8MultiArray: layout: std_msgs__msg__MultiArrayLayout data: np.ndarray[tuple[int, ...], np.dtype[np.int8]] - __msgtype__: ClassVar[str] = 'std_msgs/msg/Int8MultiArray' - + __msgtype__: ClassVar[str] = "std_msgs/msg/Int8MultiArray" @dataclass class std_msgs__msg__String: """Class for std_msgs/msg/String.""" data: str - __msgtype__: ClassVar[str] = 'std_msgs/msg/String' - + __msgtype__: ClassVar[str] = "std_msgs/msg/String" @dataclass class std_msgs__msg__UInt16: """Class for std_msgs/msg/UInt16.""" data: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt16' - + __msgtype__: ClassVar[str] = "std_msgs/msg/UInt16" @dataclass class std_msgs__msg__UInt16MultiArray: @@ -1278,16 +1160,14 @@ class std_msgs__msg__UInt16MultiArray: layout: std_msgs__msg__MultiArrayLayout data: np.ndarray[tuple[int, ...], np.dtype[np.uint16]] - __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt16MultiArray' - + __msgtype__: ClassVar[str] = "std_msgs/msg/UInt16MultiArray" @dataclass class std_msgs__msg__UInt32: """Class for std_msgs/msg/UInt32.""" data: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt32' - + __msgtype__: ClassVar[str] = "std_msgs/msg/UInt32" @dataclass class std_msgs__msg__UInt32MultiArray: @@ -1295,16 +1175,14 @@ class std_msgs__msg__UInt32MultiArray: layout: std_msgs__msg__MultiArrayLayout data: np.ndarray[tuple[int, ...], np.dtype[np.uint32]] - __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt32MultiArray' - + __msgtype__: ClassVar[str] = "std_msgs/msg/UInt32MultiArray" @dataclass class std_msgs__msg__UInt64: """Class for std_msgs/msg/UInt64.""" data: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt64' - + __msgtype__: ClassVar[str] = "std_msgs/msg/UInt64" @dataclass class std_msgs__msg__UInt64MultiArray: @@ -1312,16 +1190,14 @@ class std_msgs__msg__UInt64MultiArray: layout: std_msgs__msg__MultiArrayLayout data: np.ndarray[tuple[int, ...], np.dtype[np.uint64]] - __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt64MultiArray' - + __msgtype__: ClassVar[str] = "std_msgs/msg/UInt64MultiArray" @dataclass class std_msgs__msg__UInt8: """Class for std_msgs/msg/UInt8.""" data: int - __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt8' - + __msgtype__: ClassVar[str] = "std_msgs/msg/UInt8" @dataclass class std_msgs__msg__UInt8MultiArray: @@ -1329,8 +1205,7 @@ class std_msgs__msg__UInt8MultiArray: layout: std_msgs__msg__MultiArrayLayout data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - __msgtype__: ClassVar[str] = 'std_msgs/msg/UInt8MultiArray' - + __msgtype__: ClassVar[str] = "std_msgs/msg/UInt8MultiArray" @dataclass class tf2_msgs__msg__TF2Error: @@ -1345,16 +1220,14 @@ class tf2_msgs__msg__TF2Error: INVALID_ARGUMENT_ERROR: ClassVar[int] = 4 TIMEOUT_ERROR: ClassVar[int] = 5 TRANSFORM_ERROR: ClassVar[int] = 6 - __msgtype__: ClassVar[str] = 'tf2_msgs/msg/TF2Error' - + __msgtype__: ClassVar[str] = "tf2_msgs/msg/TF2Error" @dataclass class tf2_msgs__msg__TFMessage: """Class for tf2_msgs/msg/TFMessage.""" transforms: list[geometry_msgs__msg__TransformStamped] - __msgtype__: ClassVar[str] = 'tf2_msgs/msg/TFMessage' - + __msgtype__: ClassVar[str] = "tf2_msgs/msg/TFMessage" @dataclass class trajectory_msgs__msg__JointTrajectoryPoint: @@ -1365,8 +1238,7 @@ class trajectory_msgs__msg__JointTrajectoryPoint: accelerations: np.ndarray[tuple[int, ...], np.dtype[np.float64]] effort: np.ndarray[tuple[int, ...], np.dtype[np.float64]] time_from_start: builtin_interfaces__msg__Duration - __msgtype__: ClassVar[str] = 'trajectory_msgs/msg/JointTrajectoryPoint' - + __msgtype__: ClassVar[str] = "trajectory_msgs/msg/JointTrajectoryPoint" @dataclass class trajectory_msgs__msg__JointTrajectory: @@ -1375,8 +1247,7 @@ class trajectory_msgs__msg__JointTrajectory: header: std_msgs__msg__Header joint_names: list[str] points: list[trajectory_msgs__msg__JointTrajectoryPoint] - __msgtype__: ClassVar[str] = 'trajectory_msgs/msg/JointTrajectory' - + __msgtype__: ClassVar[str] = "trajectory_msgs/msg/JointTrajectory" @dataclass class trajectory_msgs__msg__MultiDOFJointTrajectoryPoint: @@ -1386,8 +1257,7 @@ class trajectory_msgs__msg__MultiDOFJointTrajectoryPoint: velocities: list[geometry_msgs__msg__Twist] accelerations: list[geometry_msgs__msg__Twist] time_from_start: builtin_interfaces__msg__Duration - __msgtype__: ClassVar[str] = 'trajectory_msgs/msg/MultiDOFJointTrajectoryPoint' - + __msgtype__: ClassVar[str] = "trajectory_msgs/msg/MultiDOFJointTrajectoryPoint" @dataclass class trajectory_msgs__msg__MultiDOFJointTrajectory: @@ -1396,8 +1266,7 @@ class trajectory_msgs__msg__MultiDOFJointTrajectory: header: std_msgs__msg__Header joint_names: list[str] points: list[trajectory_msgs__msg__MultiDOFJointTrajectoryPoint] - __msgtype__: ClassVar[str] = 'trajectory_msgs/msg/MultiDOFJointTrajectory' - + __msgtype__: ClassVar[str] = "trajectory_msgs/msg/MultiDOFJointTrajectory" @dataclass class vision_msgs__msg__BoundingBox2DArray: @@ -1405,8 +1274,7 @@ class vision_msgs__msg__BoundingBox2DArray: header: std_msgs__msg__Header boxes: list[vision_msgs__msg__BoundingBox2D] - __msgtype__: ClassVar[str] = 'vision_msgs/msg/BoundingBox2DArray' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/BoundingBox2DArray" @dataclass class vision_msgs__msg__BoundingBox3DArray: @@ -1414,8 +1282,7 @@ class vision_msgs__msg__BoundingBox3DArray: header: std_msgs__msg__Header boxes: list[vision_msgs__msg__BoundingBox3D] - __msgtype__: ClassVar[str] = 'vision_msgs/msg/BoundingBox3DArray' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/BoundingBox3DArray" @dataclass class vision_msgs__msg__ObjectHypothesis: @@ -1423,8 +1290,7 @@ class vision_msgs__msg__ObjectHypothesis: class_id: str score: float - __msgtype__: ClassVar[str] = 'vision_msgs/msg/ObjectHypothesis' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/ObjectHypothesis" @dataclass class vision_msgs__msg__Classification: @@ -1432,8 +1298,7 @@ class vision_msgs__msg__Classification: header: std_msgs__msg__Header results: list[vision_msgs__msg__ObjectHypothesis] - __msgtype__: ClassVar[str] = 'vision_msgs/msg/Classification' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/Classification" @dataclass class vision_msgs__msg__ObjectHypothesisWithPose: @@ -1441,8 +1306,7 @@ class vision_msgs__msg__ObjectHypothesisWithPose: hypothesis: vision_msgs__msg__ObjectHypothesis pose: geometry_msgs__msg__PoseWithCovariance - __msgtype__: ClassVar[str] = 'vision_msgs/msg/ObjectHypothesisWithPose' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/ObjectHypothesisWithPose" @dataclass class vision_msgs__msg__Detection2D: @@ -1452,8 +1316,7 @@ class vision_msgs__msg__Detection2D: results: list[vision_msgs__msg__ObjectHypothesisWithPose] bbox: vision_msgs__msg__BoundingBox2D id: str - __msgtype__: ClassVar[str] = 'vision_msgs/msg/Detection2D' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/Detection2D" @dataclass class vision_msgs__msg__Detection2DArray: @@ -1461,8 +1324,7 @@ class vision_msgs__msg__Detection2DArray: header: std_msgs__msg__Header detections: list[vision_msgs__msg__Detection2D] - __msgtype__: ClassVar[str] = 'vision_msgs/msg/Detection2DArray' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/Detection2DArray" @dataclass class vision_msgs__msg__Detection3D: @@ -1472,8 +1334,7 @@ class vision_msgs__msg__Detection3D: results: list[vision_msgs__msg__ObjectHypothesisWithPose] bbox: vision_msgs__msg__BoundingBox3D id: str - __msgtype__: ClassVar[str] = 'vision_msgs/msg/Detection3D' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/Detection3D" @dataclass class vision_msgs__msg__Detection3DArray: @@ -1481,8 +1342,7 @@ class vision_msgs__msg__Detection3DArray: header: std_msgs__msg__Header detections: list[vision_msgs__msg__Detection3D] - __msgtype__: ClassVar[str] = 'vision_msgs/msg/Detection3DArray' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/Detection3DArray" @dataclass class vision_msgs__msg__VisionClass: @@ -1490,8 +1350,7 @@ class vision_msgs__msg__VisionClass: class_id: int class_name: str - __msgtype__: ClassVar[str] = 'vision_msgs/msg/VisionClass' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/VisionClass" @dataclass class vision_msgs__msg__LabelInfo: @@ -1500,8 +1359,7 @@ class vision_msgs__msg__LabelInfo: header: std_msgs__msg__Header class_map: list[vision_msgs__msg__VisionClass] threshold: float - __msgtype__: ClassVar[str] = 'vision_msgs/msg/LabelInfo' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/LabelInfo" @dataclass class vision_msgs__msg__VisionInfo: @@ -1511,8 +1369,7 @@ class vision_msgs__msg__VisionInfo: method: str database_location: str database_version: int - __msgtype__: ClassVar[str] = 'vision_msgs/msg/VisionInfo' - + __msgtype__: ClassVar[str] = "vision_msgs/msg/VisionInfo" @dataclass class visualization_msgs__msg__ImageMarker: @@ -1538,8 +1395,7 @@ class visualization_msgs__msg__ImageMarker: POINTS: ClassVar[int] = 4 ADD: ClassVar[int] = 0 REMOVE: ClassVar[int] = 1 - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/ImageMarker' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/ImageMarker" @dataclass class visualization_msgs__msg__MeshFile: @@ -1547,8 +1403,7 @@ class visualization_msgs__msg__MeshFile: filename: str data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/MeshFile' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/MeshFile" @dataclass class visualization_msgs__msg__UVCoordinate: @@ -1556,8 +1411,7 @@ class visualization_msgs__msg__UVCoordinate: u: float v: float - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/UVCoordinate' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/UVCoordinate" @dataclass class visualization_msgs__msg__Marker: @@ -1599,8 +1453,7 @@ class visualization_msgs__msg__Marker: MODIFY: ClassVar[int] = 0 DELETE: ClassVar[int] = 2 DELETEALL: ClassVar[int] = 3 - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/Marker' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/Marker" @dataclass class visualization_msgs__msg__InteractiveMarkerControl: @@ -1627,8 +1480,7 @@ class visualization_msgs__msg__InteractiveMarkerControl: MOVE_3D: ClassVar[int] = 7 ROTATE_3D: ClassVar[int] = 8 MOVE_ROTATE_3D: ClassVar[int] = 9 - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarkerControl' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarkerControl" @dataclass class visualization_msgs__msg__MenuEntry: @@ -1642,8 +1494,7 @@ class visualization_msgs__msg__MenuEntry: FEEDBACK: ClassVar[int] = 0 ROSRUN: ClassVar[int] = 1 ROSLAUNCH: ClassVar[int] = 2 - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/MenuEntry' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/MenuEntry" @dataclass class visualization_msgs__msg__InteractiveMarker: @@ -1656,8 +1507,7 @@ class visualization_msgs__msg__InteractiveMarker: scale: float menu_entries: list[visualization_msgs__msg__MenuEntry] controls: list[visualization_msgs__msg__InteractiveMarkerControl] - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarker' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarker" @dataclass class visualization_msgs__msg__InteractiveMarkerFeedback: @@ -1678,8 +1528,7 @@ class visualization_msgs__msg__InteractiveMarkerFeedback: BUTTON_CLICK: ClassVar[int] = 3 MOUSE_DOWN: ClassVar[int] = 4 MOUSE_UP: ClassVar[int] = 5 - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarkerFeedback' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarkerFeedback" @dataclass class visualization_msgs__msg__InteractiveMarkerInit: @@ -1688,8 +1537,7 @@ class visualization_msgs__msg__InteractiveMarkerInit: server_id: str seq_num: int markers: list[visualization_msgs__msg__InteractiveMarker] - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarkerInit' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarkerInit" @dataclass class visualization_msgs__msg__InteractiveMarkerPose: @@ -1698,8 +1546,7 @@ class visualization_msgs__msg__InteractiveMarkerPose: header: std_msgs__msg__Header pose: geometry_msgs__msg__Pose name: str - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarkerPose' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarkerPose" @dataclass class visualization_msgs__msg__InteractiveMarkerUpdate: @@ -1713,1429 +1560,1432 @@ class visualization_msgs__msg__InteractiveMarkerUpdate: erases: list[str] KEEP_ALIVE: ClassVar[int] = 0 UPDATE: ClassVar[int] = 1 - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/InteractiveMarkerUpdate' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarkerUpdate" @dataclass class visualization_msgs__msg__MarkerArray: """Class for visualization_msgs/msg/MarkerArray.""" markers: list[visualization_msgs__msg__Marker] - __msgtype__: ClassVar[str] = 'visualization_msgs/msg/MarkerArray' - + __msgtype__: ClassVar[str] = "visualization_msgs/msg/MarkerArray" FIELDDEFS: Typesdict = { - 'builtin_interfaces/msg/Duration': ( + "builtin_interfaces/msg/Duration": ( [], [ - ('sec', (T.BASE, ('int32', 0))), - ('nanosec', (T.BASE, ('uint32', 0))), + ("sec", (T.BASE, ("int32", 0))), + ("nanosec", (T.BASE, ("uint32", 0))), ], ), - 'builtin_interfaces/msg/Time': ( + "builtin_interfaces/msg/Time": ( [], [ - ('sec', (T.BASE, ('int32', 0))), - ('nanosec', (T.BASE, ('uint32', 0))), + ("sec", (T.BASE, ("int32", 0))), + ("nanosec", (T.BASE, ("uint32", 0))), ], ), - 'std_msgs/msg/Header': ( + "std_msgs/msg/Header": ( [], [ - ('stamp', (T.NAME, 'builtin_interfaces/msg/Time')), - ('frame_id', (T.BASE, ('string', 0))), + ("stamp", (T.NAME, "builtin_interfaces/msg/Time")), + ("frame_id", (T.BASE, ("string", 0))), ], ), - 'vision_msgs/msg/Point2D': ( + "vision_msgs/msg/Point2D": ( [], [ - ('x', (T.BASE, ('float64', 0))), - ('y', (T.BASE, ('float64', 0))), + ("x", (T.BASE, ("float64", 0))), + ("y", (T.BASE, ("float64", 0))), ], ), - 'vision_msgs/msg/Pose2D': ( + "vision_msgs/msg/Pose2D": ( [], [ - ('position', (T.NAME, 'vision_msgs/msg/Point2D')), - ('theta', (T.BASE, ('float64', 0))), + ("position", (T.NAME, "vision_msgs/msg/Point2D")), + ("theta", (T.BASE, ("float64", 0))), ], ), - 'vision_msgs/msg/BoundingBox2D': ( + "vision_msgs/msg/BoundingBox2D": ( [], [ - ('center', (T.NAME, 'vision_msgs/msg/Pose2D')), - ('size_x', (T.BASE, ('float64', 0))), - ('size_y', (T.BASE, ('float64', 0))), + ("center", (T.NAME, "vision_msgs/msg/Pose2D")), + ("size_x", (T.BASE, ("float64", 0))), + ("size_y", (T.BASE, ("float64", 0))), ], ), - 'dimos_msgs/msg/BoundingBox2DArray': ( + "dimos_msgs/msg/BoundingBox2DArray": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('boxes', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/BoundingBox2D'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("boxes", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/BoundingBox2D"), 0))), ], ), - 'geometry_msgs/msg/Point': ( + "geometry_msgs/msg/Point": ( [], [ - ('x', (T.BASE, ('float64', 0))), - ('y', (T.BASE, ('float64', 0))), - ('z', (T.BASE, ('float64', 0))), + ("x", (T.BASE, ("float64", 0))), + ("y", (T.BASE, ("float64", 0))), + ("z", (T.BASE, ("float64", 0))), ], ), - 'geometry_msgs/msg/Quaternion': ( + "geometry_msgs/msg/Quaternion": ( [], [ - ('x', (T.BASE, ('float64', 0))), - ('y', (T.BASE, ('float64', 0))), - ('z', (T.BASE, ('float64', 0))), - ('w', (T.BASE, ('float64', 0))), + ("x", (T.BASE, ("float64", 0))), + ("y", (T.BASE, ("float64", 0))), + ("z", (T.BASE, ("float64", 0))), + ("w", (T.BASE, ("float64", 0))), ], ), - 'geometry_msgs/msg/Pose': ( + "geometry_msgs/msg/Pose": ( [], [ - ('position', (T.NAME, 'geometry_msgs/msg/Point')), - ('orientation', (T.NAME, 'geometry_msgs/msg/Quaternion')), + ("position", (T.NAME, "geometry_msgs/msg/Point")), + ("orientation", (T.NAME, "geometry_msgs/msg/Quaternion")), ], ), - 'geometry_msgs/msg/Vector3': ( + "geometry_msgs/msg/Vector3": ( [], [ - ('x', (T.BASE, ('float64', 0))), - ('y', (T.BASE, ('float64', 0))), - ('z', (T.BASE, ('float64', 0))), + ("x", (T.BASE, ("float64", 0))), + ("y", (T.BASE, ("float64", 0))), + ("z", (T.BASE, ("float64", 0))), ], ), - 'vision_msgs/msg/BoundingBox3D': ( + "vision_msgs/msg/BoundingBox3D": ( [], [ - ('center', (T.NAME, 'geometry_msgs/msg/Pose')), - ('size', (T.NAME, 'geometry_msgs/msg/Vector3')), + ("center", (T.NAME, "geometry_msgs/msg/Pose")), + ("size", (T.NAME, "geometry_msgs/msg/Vector3")), ], ), - 'dimos_msgs/msg/BoundingBox3DArray': ( + "dimos_msgs/msg/BoundingBox3DArray": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('boxes', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/BoundingBox3D'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("boxes", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/BoundingBox3D"), 0))), ], ), - 'dimos_msgs/msg/EntityMarker': ( + "dimos_msgs/msg/EntityMarker": ( [], [ - ('entity_id', (T.BASE, ('string', 0))), - ('label', (T.BASE, ('string', 0))), - ('entity_type', (T.BASE, ('string', 0))), - ('position', (T.NAME, 'geometry_msgs/msg/Point')), + ("entity_id", (T.BASE, ("string", 0))), + ("label", (T.BASE, ("string", 0))), + ("entity_type", (T.BASE, ("string", 0))), + ("position", (T.NAME, "geometry_msgs/msg/Point")), ], ), - 'dimos_msgs/msg/EntityMarkers': ( + "dimos_msgs/msg/EntityMarkers": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('markers', (T.SEQUENCE, ((T.NAME, 'dimos_msgs/msg/EntityMarker'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("markers", (T.SEQUENCE, ((T.NAME, "dimos_msgs/msg/EntityMarker"), 0))), ], ), - 'dimos_msgs/msg/GraspCandidate': ( + "dimos_msgs/msg/GraspCandidate": ( [], [ - ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), - ('score', (T.BASE, ('float64', 0))), + ("pose", (T.NAME, "geometry_msgs/msg/Pose")), + ("score", (T.BASE, ("float64", 0))), ], ), - 'dimos_msgs/msg/GraspCandidateArray': ( + "dimos_msgs/msg/GraspCandidateArray": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('candidates', (T.SEQUENCE, ((T.NAME, 'dimos_msgs/msg/GraspCandidate'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("candidates", (T.SEQUENCE, ((T.NAME, "dimos_msgs/msg/GraspCandidate"), 0))), ], ), - 'dimos_msgs/msg/ImuInfo': ( + "dimos_msgs/msg/ImuInfo": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('gyro_noise_density', (T.BASE, ('float64', 0))), - ('gyro_random_walk', (T.BASE, ('float64', 0))), - ('accel_noise_density', (T.BASE, ('float64', 0))), - ('accel_random_walk', (T.BASE, ('float64', 0))), - ('frequency', (T.BASE, ('float64', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("gyro_noise_density", (T.BASE, ("float64", 0))), + ("gyro_random_walk", (T.BASE, ("float64", 0))), + ("accel_noise_density", (T.BASE, ("float64", 0))), + ("accel_random_walk", (T.BASE, ("float64", 0))), + ("frequency", (T.BASE, ("float64", 0))), ], ), - 'dimos_msgs/msg/JointCommand': ( + "dimos_msgs/msg/JointCommand": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('positions', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("positions", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), ], ), - 'dimos_msgs/msg/LineSegment3D': ( + "dimos_msgs/msg/LineSegment3D": ( [], [ - ('start', (T.NAME, 'geometry_msgs/msg/Point')), - ('end', (T.NAME, 'geometry_msgs/msg/Point')), - ('weight', (T.BASE, ('float64', 0))), + ("start", (T.NAME, "geometry_msgs/msg/Point")), + ("end", (T.NAME, "geometry_msgs/msg/Point")), + ("weight", (T.BASE, ("float64", 0))), ], ), - 'dimos_msgs/msg/LineSegments3D': ( + "dimos_msgs/msg/LineSegments3D": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('segments', (T.SEQUENCE, ((T.NAME, 'dimos_msgs/msg/LineSegment3D'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("segments", (T.SEQUENCE, ((T.NAME, "dimos_msgs/msg/LineSegment3D"), 0))), ], ), - 'dimos_msgs/msg/MotorCommandArray': ( + "dimos_msgs/msg/MotorCommandArray": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('q', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('dq', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('kp', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('kd', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('tau', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("q", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("dq", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("kp", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("kd", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("tau", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), ], ), - 'dimos_msgs/msg/RobotState': ( + "dimos_msgs/msg/RobotState": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('state', (T.BASE, ('int32', 0))), - ('mode', (T.BASE, ('int32', 0))), - ('error_code', (T.BASE, ('int32', 0))), - ('warn_code', (T.BASE, ('int32', 0))), - ('cmdnum', (T.BASE, ('int32', 0))), - ('mt_brake', (T.BASE, ('int32', 0))), - ('mt_able', (T.BASE, ('int32', 0))), - ('tcp_pose', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('tcp_offset', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('joints', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("state", (T.BASE, ("int32", 0))), + ("mode", (T.BASE, ("int32", 0))), + ("error_code", (T.BASE, ("int32", 0))), + ("warn_code", (T.BASE, ("int32", 0))), + ("cmdnum", (T.BASE, ("int32", 0))), + ("mt_brake", (T.BASE, ("int32", 0))), + ("mt_able", (T.BASE, ("int32", 0))), + ("tcp_pose", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("tcp_offset", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("joints", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), ], ), - 'dimos_msgs/msg/TrajectoryStatus': ( + "dimos_msgs/msg/TrajectoryStatus": ( [ - ('IDLE', 'uint8', 0), - ('EXECUTING', 'uint8', 1), - ('COMPLETED', 'uint8', 2), - ('ABORTED', 'uint8', 3), - ('FAULT', 'uint8', 4), + ("IDLE", "uint8", 0), + ("EXECUTING", "uint8", 1), + ("COMPLETED", "uint8", 2), + ("ABORTED", "uint8", 3), + ("FAULT", "uint8", 4), ], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('state', (T.BASE, ('uint8', 0))), - ('progress', (T.BASE, ('float64', 0))), - ('time_elapsed', (T.NAME, 'builtin_interfaces/msg/Duration')), - ('time_remaining', (T.NAME, 'builtin_interfaces/msg/Duration')), - ('error', (T.BASE, ('string', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("state", (T.BASE, ("uint8", 0))), + ("progress", (T.BASE, ("float64", 0))), + ("time_elapsed", (T.NAME, "builtin_interfaces/msg/Duration")), + ("time_remaining", (T.NAME, "builtin_interfaces/msg/Duration")), + ("error", (T.BASE, ("string", 0))), ], ), - 'dimos_msgs/msg/VideoStats': ( + "dimos_msgs/msg/VideoStats": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('fps', (T.BASE, ('float64', 0))), - ('kbps', (T.BASE, ('float64', 0))), - ('width', (T.BASE, ('uint32', 0))), - ('height', (T.BASE, ('uint32', 0))), - ('loss_pct', (T.BASE, ('float64', 0))), - ('jitter_buffer_ms', (T.BASE, ('float64', 0))), - ('decode_ms', (T.BASE, ('float64', 0))), - ('frames_dropped', (T.BASE, ('uint64', 0))), - ('freezes', (T.BASE, ('uint64', 0))), - ('e2e_latency_ms', (T.BASE, ('float64', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("fps", (T.BASE, ("float64", 0))), + ("kbps", (T.BASE, ("float64", 0))), + ("width", (T.BASE, ("uint32", 0))), + ("height", (T.BASE, ("uint32", 0))), + ("loss_pct", (T.BASE, ("float64", 0))), + ("jitter_buffer_ms", (T.BASE, ("float64", 0))), + ("decode_ms", (T.BASE, ("float64", 0))), + ("frames_dropped", (T.BASE, ("uint64", 0))), + ("freezes", (T.BASE, ("uint64", 0))), + ("e2e_latency_ms", (T.BASE, ("float64", 0))), ], ), - 'foxglove_msgs/msg/CompressedVideo': ( + "foxglove_msgs/msg/CompressedVideo": ( [], [ - ('timestamp', (T.NAME, 'builtin_interfaces/msg/Time')), - ('frame_id', (T.BASE, ('string', 0))), - ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), - ('format', (T.BASE, ('string', 0))), + ("timestamp", (T.NAME, "builtin_interfaces/msg/Time")), + ("frame_id", (T.BASE, ("string", 0))), + ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), + ("format", (T.BASE, ("string", 0))), ], ), - 'geometry_msgs/msg/Accel': ( + "geometry_msgs/msg/Accel": ( [], [ - ('linear', (T.NAME, 'geometry_msgs/msg/Vector3')), - ('angular', (T.NAME, 'geometry_msgs/msg/Vector3')), + ("linear", (T.NAME, "geometry_msgs/msg/Vector3")), + ("angular", (T.NAME, "geometry_msgs/msg/Vector3")), ], ), - 'geometry_msgs/msg/AccelStamped': ( + "geometry_msgs/msg/AccelStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('accel', (T.NAME, 'geometry_msgs/msg/Accel')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("accel", (T.NAME, "geometry_msgs/msg/Accel")), ], ), - 'geometry_msgs/msg/AccelWithCovariance': ( + "geometry_msgs/msg/AccelWithCovariance": ( [], [ - ('accel', (T.NAME, 'geometry_msgs/msg/Accel')), - ('covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 36))), + ("accel", (T.NAME, "geometry_msgs/msg/Accel")), + ("covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 36))), ], ), - 'geometry_msgs/msg/AccelWithCovarianceStamped': ( + "geometry_msgs/msg/AccelWithCovarianceStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('accel', (T.NAME, 'geometry_msgs/msg/AccelWithCovariance')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("accel", (T.NAME, "geometry_msgs/msg/AccelWithCovariance")), ], ), - 'geometry_msgs/msg/Inertia': ( + "geometry_msgs/msg/Inertia": ( [], [ - ('m', (T.BASE, ('float64', 0))), - ('com', (T.NAME, 'geometry_msgs/msg/Vector3')), - ('ixx', (T.BASE, ('float64', 0))), - ('ixy', (T.BASE, ('float64', 0))), - ('ixz', (T.BASE, ('float64', 0))), - ('iyy', (T.BASE, ('float64', 0))), - ('iyz', (T.BASE, ('float64', 0))), - ('izz', (T.BASE, ('float64', 0))), + ("m", (T.BASE, ("float64", 0))), + ("com", (T.NAME, "geometry_msgs/msg/Vector3")), + ("ixx", (T.BASE, ("float64", 0))), + ("ixy", (T.BASE, ("float64", 0))), + ("ixz", (T.BASE, ("float64", 0))), + ("iyy", (T.BASE, ("float64", 0))), + ("iyz", (T.BASE, ("float64", 0))), + ("izz", (T.BASE, ("float64", 0))), ], ), - 'geometry_msgs/msg/InertiaStamped': ( + "geometry_msgs/msg/InertiaStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('inertia', (T.NAME, 'geometry_msgs/msg/Inertia')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("inertia", (T.NAME, "geometry_msgs/msg/Inertia")), ], ), - 'geometry_msgs/msg/Point32': ( + "geometry_msgs/msg/Point32": ( [], [ - ('x', (T.BASE, ('float32', 0))), - ('y', (T.BASE, ('float32', 0))), - ('z', (T.BASE, ('float32', 0))), + ("x", (T.BASE, ("float32", 0))), + ("y", (T.BASE, ("float32", 0))), + ("z", (T.BASE, ("float32", 0))), ], ), - 'geometry_msgs/msg/PointStamped': ( + "geometry_msgs/msg/PointStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('point', (T.NAME, 'geometry_msgs/msg/Point')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("point", (T.NAME, "geometry_msgs/msg/Point")), ], ), - 'geometry_msgs/msg/Polygon': ( + "geometry_msgs/msg/Polygon": ( [], [ - ('points', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point32'), 0))), + ("points", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point32"), 0))), ], ), - 'geometry_msgs/msg/PolygonInstance': ( + "geometry_msgs/msg/PolygonInstance": ( [], [ - ('polygon', (T.NAME, 'geometry_msgs/msg/Polygon')), - ('id', (T.BASE, ('int64', 0))), + ("polygon", (T.NAME, "geometry_msgs/msg/Polygon")), + ("id", (T.BASE, ("int64", 0))), ], ), - 'geometry_msgs/msg/PolygonInstanceStamped': ( + "geometry_msgs/msg/PolygonInstanceStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('polygon', (T.NAME, 'geometry_msgs/msg/PolygonInstance')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("polygon", (T.NAME, "geometry_msgs/msg/PolygonInstance")), ], ), - 'geometry_msgs/msg/PolygonStamped': ( + "geometry_msgs/msg/PolygonStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('polygon', (T.NAME, 'geometry_msgs/msg/Polygon')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("polygon", (T.NAME, "geometry_msgs/msg/Polygon")), ], ), - 'geometry_msgs/msg/Pose2D': ( + "geometry_msgs/msg/Pose2D": ( [], [ - ('x', (T.BASE, ('float64', 0))), - ('y', (T.BASE, ('float64', 0))), - ('theta', (T.BASE, ('float64', 0))), + ("x", (T.BASE, ("float64", 0))), + ("y", (T.BASE, ("float64", 0))), + ("theta", (T.BASE, ("float64", 0))), ], ), - 'geometry_msgs/msg/PoseArray': ( + "geometry_msgs/msg/PoseArray": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('poses', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Pose'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("poses", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Pose"), 0))), ], ), - 'geometry_msgs/msg/PoseStamped': ( + "geometry_msgs/msg/PoseStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("pose", (T.NAME, "geometry_msgs/msg/Pose")), ], ), - 'geometry_msgs/msg/PoseWithCovariance': ( + "geometry_msgs/msg/PoseWithCovariance": ( [], [ - ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), - ('covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 36))), + ("pose", (T.NAME, "geometry_msgs/msg/Pose")), + ("covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 36))), ], ), - 'geometry_msgs/msg/PoseWithCovarianceStamped': ( + "geometry_msgs/msg/PoseWithCovarianceStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('pose', (T.NAME, 'geometry_msgs/msg/PoseWithCovariance')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("pose", (T.NAME, "geometry_msgs/msg/PoseWithCovariance")), ], ), - 'geometry_msgs/msg/QuaternionStamped': ( + "geometry_msgs/msg/QuaternionStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('quaternion', (T.NAME, 'geometry_msgs/msg/Quaternion')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("quaternion", (T.NAME, "geometry_msgs/msg/Quaternion")), ], ), - 'geometry_msgs/msg/Transform': ( + "geometry_msgs/msg/Transform": ( [], [ - ('translation', (T.NAME, 'geometry_msgs/msg/Vector3')), - ('rotation', (T.NAME, 'geometry_msgs/msg/Quaternion')), + ("translation", (T.NAME, "geometry_msgs/msg/Vector3")), + ("rotation", (T.NAME, "geometry_msgs/msg/Quaternion")), ], ), - 'geometry_msgs/msg/TransformStamped': ( + "geometry_msgs/msg/TransformStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('child_frame_id', (T.BASE, ('string', 0))), - ('transform', (T.NAME, 'geometry_msgs/msg/Transform')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("child_frame_id", (T.BASE, ("string", 0))), + ("transform", (T.NAME, "geometry_msgs/msg/Transform")), ], ), - 'geometry_msgs/msg/Twist': ( + "geometry_msgs/msg/Twist": ( [], [ - ('linear', (T.NAME, 'geometry_msgs/msg/Vector3')), - ('angular', (T.NAME, 'geometry_msgs/msg/Vector3')), + ("linear", (T.NAME, "geometry_msgs/msg/Vector3")), + ("angular", (T.NAME, "geometry_msgs/msg/Vector3")), ], ), - 'geometry_msgs/msg/TwistStamped': ( + "geometry_msgs/msg/TwistStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('twist', (T.NAME, 'geometry_msgs/msg/Twist')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("twist", (T.NAME, "geometry_msgs/msg/Twist")), ], ), - 'geometry_msgs/msg/TwistWithCovariance': ( + "geometry_msgs/msg/TwistWithCovariance": ( [], [ - ('twist', (T.NAME, 'geometry_msgs/msg/Twist')), - ('covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 36))), + ("twist", (T.NAME, "geometry_msgs/msg/Twist")), + ("covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 36))), ], ), - 'geometry_msgs/msg/TwistWithCovarianceStamped': ( + "geometry_msgs/msg/TwistWithCovarianceStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('twist', (T.NAME, 'geometry_msgs/msg/TwistWithCovariance')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("twist", (T.NAME, "geometry_msgs/msg/TwistWithCovariance")), ], ), - 'geometry_msgs/msg/Vector3Stamped': ( + "geometry_msgs/msg/Vector3Stamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('vector', (T.NAME, 'geometry_msgs/msg/Vector3')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("vector", (T.NAME, "geometry_msgs/msg/Vector3")), ], ), - 'geometry_msgs/msg/VelocityStamped': ( + "geometry_msgs/msg/VelocityStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('body_frame_id', (T.BASE, ('string', 0))), - ('reference_frame_id', (T.BASE, ('string', 0))), - ('velocity', (T.NAME, 'geometry_msgs/msg/Twist')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("body_frame_id", (T.BASE, ("string", 0))), + ("reference_frame_id", (T.BASE, ("string", 0))), + ("velocity", (T.NAME, "geometry_msgs/msg/Twist")), ], ), - 'geometry_msgs/msg/VelocityWithCovarianceStamped': ( + "geometry_msgs/msg/VelocityWithCovarianceStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('body_frame_id', (T.BASE, ('string', 0))), - ('reference_frame_id', (T.BASE, ('string', 0))), - ('velocity', (T.NAME, 'geometry_msgs/msg/TwistWithCovariance')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("body_frame_id", (T.BASE, ("string", 0))), + ("reference_frame_id", (T.BASE, ("string", 0))), + ("velocity", (T.NAME, "geometry_msgs/msg/TwistWithCovariance")), ], ), - 'geometry_msgs/msg/Wrench': ( + "geometry_msgs/msg/Wrench": ( [], [ - ('force', (T.NAME, 'geometry_msgs/msg/Vector3')), - ('torque', (T.NAME, 'geometry_msgs/msg/Vector3')), + ("force", (T.NAME, "geometry_msgs/msg/Vector3")), + ("torque", (T.NAME, "geometry_msgs/msg/Vector3")), ], ), - 'geometry_msgs/msg/WrenchStamped': ( + "geometry_msgs/msg/WrenchStamped": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('wrench', (T.NAME, 'geometry_msgs/msg/Wrench')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("wrench", (T.NAME, "geometry_msgs/msg/Wrench")), ], ), - 'nav_msgs/msg/Goals': ( + "nav_msgs/msg/Goals": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('goals', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/PoseStamped'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("goals", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/PoseStamped"), 0))), ], ), - 'nav_msgs/msg/GridCells': ( + "nav_msgs/msg/GridCells": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('cell_width', (T.BASE, ('float32', 0))), - ('cell_height', (T.BASE, ('float32', 0))), - ('cells', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("cell_width", (T.BASE, ("float32", 0))), + ("cell_height", (T.BASE, ("float32", 0))), + ("cells", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point"), 0))), ], ), - 'nav_msgs/msg/MapMetaData': ( + "nav_msgs/msg/MapMetaData": ( [], [ - ('map_load_time', (T.NAME, 'builtin_interfaces/msg/Time')), - ('resolution', (T.BASE, ('float32', 0))), - ('width', (T.BASE, ('uint32', 0))), - ('height', (T.BASE, ('uint32', 0))), - ('origin', (T.NAME, 'geometry_msgs/msg/Pose')), + ("map_load_time", (T.NAME, "builtin_interfaces/msg/Time")), + ("resolution", (T.BASE, ("float32", 0))), + ("width", (T.BASE, ("uint32", 0))), + ("height", (T.BASE, ("uint32", 0))), + ("origin", (T.NAME, "geometry_msgs/msg/Pose")), ], ), - 'nav_msgs/msg/OccupancyGrid': ( + "nav_msgs/msg/OccupancyGrid": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('info', (T.NAME, 'nav_msgs/msg/MapMetaData')), - ('data', (T.SEQUENCE, ((T.BASE, ('int8', 0)), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("info", (T.NAME, "nav_msgs/msg/MapMetaData")), + ("data", (T.SEQUENCE, ((T.BASE, ("int8", 0)), 0))), ], ), - 'nav_msgs/msg/Odometry': ( + "nav_msgs/msg/Odometry": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('child_frame_id', (T.BASE, ('string', 0))), - ('pose', (T.NAME, 'geometry_msgs/msg/PoseWithCovariance')), - ('twist', (T.NAME, 'geometry_msgs/msg/TwistWithCovariance')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("child_frame_id", (T.BASE, ("string", 0))), + ("pose", (T.NAME, "geometry_msgs/msg/PoseWithCovariance")), + ("twist", (T.NAME, "geometry_msgs/msg/TwistWithCovariance")), ], ), - 'nav_msgs/msg/Path': ( + "nav_msgs/msg/Path": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('poses', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/PoseStamped'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("poses", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/PoseStamped"), 0))), ], ), - 'nav_msgs/msg/TrajectoryPoint': ( + "nav_msgs/msg/TrajectoryPoint": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), - ('velocity', (T.NAME, 'geometry_msgs/msg/Twist')), - ('acceleration', (T.NAME, 'geometry_msgs/msg/Accel')), - ('effort', (T.NAME, 'geometry_msgs/msg/Wrench')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("pose", (T.NAME, "geometry_msgs/msg/Pose")), + ("velocity", (T.NAME, "geometry_msgs/msg/Twist")), + ("acceleration", (T.NAME, "geometry_msgs/msg/Accel")), + ("effort", (T.NAME, "geometry_msgs/msg/Wrench")), ], ), - 'nav_msgs/msg/Trajectory': ( + "nav_msgs/msg/Trajectory": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('points', (T.SEQUENCE, ((T.NAME, 'nav_msgs/msg/TrajectoryPoint'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("points", (T.SEQUENCE, ((T.NAME, "nav_msgs/msg/TrajectoryPoint"), 0))), ], ), - 'sensor_msgs/msg/BatteryState': ( + "sensor_msgs/msg/BatteryState": ( [ - ('POWER_SUPPLY_STATUS_UNKNOWN', 'uint8', 0), - ('POWER_SUPPLY_STATUS_CHARGING', 'uint8', 1), - ('POWER_SUPPLY_STATUS_DISCHARGING', 'uint8', 2), - ('POWER_SUPPLY_STATUS_NOT_CHARGING', 'uint8', 3), - ('POWER_SUPPLY_STATUS_FULL', 'uint8', 4), - ('POWER_SUPPLY_HEALTH_UNKNOWN', 'uint8', 0), - ('POWER_SUPPLY_HEALTH_GOOD', 'uint8', 1), - ('POWER_SUPPLY_HEALTH_OVERHEAT', 'uint8', 2), - ('POWER_SUPPLY_HEALTH_DEAD', 'uint8', 3), - ('POWER_SUPPLY_HEALTH_OVERVOLTAGE', 'uint8', 4), - ('POWER_SUPPLY_HEALTH_UNSPEC_FAILURE', 'uint8', 5), - ('POWER_SUPPLY_HEALTH_COLD', 'uint8', 6), - ('POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE', 'uint8', 7), - ('POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE', 'uint8', 8), - ('POWER_SUPPLY_TECHNOLOGY_UNKNOWN', 'uint8', 0), - ('POWER_SUPPLY_TECHNOLOGY_NIMH', 'uint8', 1), - ('POWER_SUPPLY_TECHNOLOGY_LION', 'uint8', 2), - ('POWER_SUPPLY_TECHNOLOGY_LIPO', 'uint8', 3), - ('POWER_SUPPLY_TECHNOLOGY_LIFE', 'uint8', 4), - ('POWER_SUPPLY_TECHNOLOGY_NICD', 'uint8', 5), - ('POWER_SUPPLY_TECHNOLOGY_LIMN', 'uint8', 6), - ('POWER_SUPPLY_TECHNOLOGY_TERNARY', 'uint8', 7), - ('POWER_SUPPLY_TECHNOLOGY_VRLA', 'uint8', 8), + ("POWER_SUPPLY_STATUS_UNKNOWN", "uint8", 0), + ("POWER_SUPPLY_STATUS_CHARGING", "uint8", 1), + ("POWER_SUPPLY_STATUS_DISCHARGING", "uint8", 2), + ("POWER_SUPPLY_STATUS_NOT_CHARGING", "uint8", 3), + ("POWER_SUPPLY_STATUS_FULL", "uint8", 4), + ("POWER_SUPPLY_HEALTH_UNKNOWN", "uint8", 0), + ("POWER_SUPPLY_HEALTH_GOOD", "uint8", 1), + ("POWER_SUPPLY_HEALTH_OVERHEAT", "uint8", 2), + ("POWER_SUPPLY_HEALTH_DEAD", "uint8", 3), + ("POWER_SUPPLY_HEALTH_OVERVOLTAGE", "uint8", 4), + ("POWER_SUPPLY_HEALTH_UNSPEC_FAILURE", "uint8", 5), + ("POWER_SUPPLY_HEALTH_COLD", "uint8", 6), + ("POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE", "uint8", 7), + ("POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE", "uint8", 8), + ("POWER_SUPPLY_TECHNOLOGY_UNKNOWN", "uint8", 0), + ("POWER_SUPPLY_TECHNOLOGY_NIMH", "uint8", 1), + ("POWER_SUPPLY_TECHNOLOGY_LION", "uint8", 2), + ("POWER_SUPPLY_TECHNOLOGY_LIPO", "uint8", 3), + ("POWER_SUPPLY_TECHNOLOGY_LIFE", "uint8", 4), + ("POWER_SUPPLY_TECHNOLOGY_NICD", "uint8", 5), + ("POWER_SUPPLY_TECHNOLOGY_LIMN", "uint8", 6), + ("POWER_SUPPLY_TECHNOLOGY_TERNARY", "uint8", 7), + ("POWER_SUPPLY_TECHNOLOGY_VRLA", "uint8", 8), ], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('voltage', (T.BASE, ('float32', 0))), - ('temperature', (T.BASE, ('float32', 0))), - ('current', (T.BASE, ('float32', 0))), - ('charge', (T.BASE, ('float32', 0))), - ('capacity', (T.BASE, ('float32', 0))), - ('design_capacity', (T.BASE, ('float32', 0))), - ('percentage', (T.BASE, ('float32', 0))), - ('power_supply_status', (T.BASE, ('uint8', 0))), - ('power_supply_health', (T.BASE, ('uint8', 0))), - ('power_supply_technology', (T.BASE, ('uint8', 0))), - ('present', (T.BASE, ('bool', 0))), - ('cell_voltage', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), - ('cell_temperature', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), - ('location', (T.BASE, ('string', 0))), - ('serial_number', (T.BASE, ('string', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("voltage", (T.BASE, ("float32", 0))), + ("temperature", (T.BASE, ("float32", 0))), + ("current", (T.BASE, ("float32", 0))), + ("charge", (T.BASE, ("float32", 0))), + ("capacity", (T.BASE, ("float32", 0))), + ("design_capacity", (T.BASE, ("float32", 0))), + ("percentage", (T.BASE, ("float32", 0))), + ("power_supply_status", (T.BASE, ("uint8", 0))), + ("power_supply_health", (T.BASE, ("uint8", 0))), + ("power_supply_technology", (T.BASE, ("uint8", 0))), + ("present", (T.BASE, ("bool", 0))), + ("cell_voltage", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), + ("cell_temperature", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), + ("location", (T.BASE, ("string", 0))), + ("serial_number", (T.BASE, ("string", 0))), ], ), - 'sensor_msgs/msg/RegionOfInterest': ( + "sensor_msgs/msg/RegionOfInterest": ( [], [ - ('x_offset', (T.BASE, ('uint32', 0))), - ('y_offset', (T.BASE, ('uint32', 0))), - ('height', (T.BASE, ('uint32', 0))), - ('width', (T.BASE, ('uint32', 0))), - ('do_rectify', (T.BASE, ('bool', 0))), + ("x_offset", (T.BASE, ("uint32", 0))), + ("y_offset", (T.BASE, ("uint32", 0))), + ("height", (T.BASE, ("uint32", 0))), + ("width", (T.BASE, ("uint32", 0))), + ("do_rectify", (T.BASE, ("bool", 0))), ], ), - 'sensor_msgs/msg/CameraInfo': ( + "sensor_msgs/msg/CameraInfo": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('height', (T.BASE, ('uint32', 0))), - ('width', (T.BASE, ('uint32', 0))), - ('distortion_model', (T.BASE, ('string', 0))), - ('d', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('k', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), - ('r', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), - ('p', (T.ARRAY, ((T.BASE, ('float64', 0)), 12))), - ('binning_x', (T.BASE, ('uint32', 0))), - ('binning_y', (T.BASE, ('uint32', 0))), - ('roi', (T.NAME, 'sensor_msgs/msg/RegionOfInterest')), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("height", (T.BASE, ("uint32", 0))), + ("width", (T.BASE, ("uint32", 0))), + ("distortion_model", (T.BASE, ("string", 0))), + ("d", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("k", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), + ("r", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), + ("p", (T.ARRAY, ((T.BASE, ("float64", 0)), 12))), + ("binning_x", (T.BASE, ("uint32", 0))), + ("binning_y", (T.BASE, ("uint32", 0))), + ("roi", (T.NAME, "sensor_msgs/msg/RegionOfInterest")), ], ), - 'sensor_msgs/msg/ChannelFloat32': ( + "sensor_msgs/msg/ChannelFloat32": ( [], [ - ('name', (T.BASE, ('string', 0))), - ('values', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ("name", (T.BASE, ("string", 0))), + ("values", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), ], ), - 'sensor_msgs/msg/CompressedImage': ( + "sensor_msgs/msg/CompressedImage": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('format', (T.BASE, ('string', 0))), - ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("format", (T.BASE, ("string", 0))), + ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), ], ), - 'sensor_msgs/msg/FluidPressure': ( + "sensor_msgs/msg/FluidPressure": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('fluid_pressure', (T.BASE, ('float64', 0))), - ('variance', (T.BASE, ('float64', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("fluid_pressure", (T.BASE, ("float64", 0))), + ("variance", (T.BASE, ("float64", 0))), ], ), - 'sensor_msgs/msg/Illuminance': ( + "sensor_msgs/msg/Illuminance": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('illuminance', (T.BASE, ('float64', 0))), - ('variance', (T.BASE, ('float64', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("illuminance", (T.BASE, ("float64", 0))), + ("variance", (T.BASE, ("float64", 0))), ], ), - 'sensor_msgs/msg/Image': ( + "sensor_msgs/msg/Image": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('height', (T.BASE, ('uint32', 0))), - ('width', (T.BASE, ('uint32', 0))), - ('encoding', (T.BASE, ('string', 0))), - ('is_bigendian', (T.BASE, ('uint8', 0))), - ('step', (T.BASE, ('uint32', 0))), - ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("height", (T.BASE, ("uint32", 0))), + ("width", (T.BASE, ("uint32", 0))), + ("encoding", (T.BASE, ("string", 0))), + ("is_bigendian", (T.BASE, ("uint8", 0))), + ("step", (T.BASE, ("uint32", 0))), + ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), ], ), - 'sensor_msgs/msg/Imu': ( + "sensor_msgs/msg/Imu": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('orientation', (T.NAME, 'geometry_msgs/msg/Quaternion')), - ('orientation_covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), - ('angular_velocity', (T.NAME, 'geometry_msgs/msg/Vector3')), - ('angular_velocity_covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), - ('linear_acceleration', (T.NAME, 'geometry_msgs/msg/Vector3')), - ('linear_acceleration_covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("orientation", (T.NAME, "geometry_msgs/msg/Quaternion")), + ("orientation_covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), + ("angular_velocity", (T.NAME, "geometry_msgs/msg/Vector3")), + ("angular_velocity_covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), + ("linear_acceleration", (T.NAME, "geometry_msgs/msg/Vector3")), + ("linear_acceleration_covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), ], ), - 'sensor_msgs/msg/JointState': ( + "sensor_msgs/msg/JointState": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('name', (T.SEQUENCE, ((T.BASE, ('string', 0)), 0))), - ('position', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('velocity', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('effort', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("name", (T.SEQUENCE, ((T.BASE, ("string", 0)), 0))), + ("position", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("velocity", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("effort", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), ], ), - 'sensor_msgs/msg/Joy': ( + "sensor_msgs/msg/Joy": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('axes', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), - ('buttons', (T.SEQUENCE, ((T.BASE, ('int32', 0)), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("axes", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), + ("buttons", (T.SEQUENCE, ((T.BASE, ("int32", 0)), 0))), ], ), - 'sensor_msgs/msg/JoyFeedback': ( + "sensor_msgs/msg/JoyFeedback": ( [ - ('TYPE_LED', 'uint8', 0), - ('TYPE_RUMBLE', 'uint8', 1), - ('TYPE_BUZZER', 'uint8', 2), + ("TYPE_LED", "uint8", 0), + ("TYPE_RUMBLE", "uint8", 1), + ("TYPE_BUZZER", "uint8", 2), ], [ - ('type', (T.BASE, ('uint8', 0))), - ('id', (T.BASE, ('uint8', 0))), - ('intensity', (T.BASE, ('float32', 0))), + ("type", (T.BASE, ("uint8", 0))), + ("id", (T.BASE, ("uint8", 0))), + ("intensity", (T.BASE, ("float32", 0))), ], ), - 'sensor_msgs/msg/JoyFeedbackArray': ( + "sensor_msgs/msg/JoyFeedbackArray": ( [], [ - ('array', (T.SEQUENCE, ((T.NAME, 'sensor_msgs/msg/JoyFeedback'), 0))), + ("array", (T.SEQUENCE, ((T.NAME, "sensor_msgs/msg/JoyFeedback"), 0))), ], ), - 'sensor_msgs/msg/LaserEcho': ( + "sensor_msgs/msg/LaserEcho": ( [], [ - ('echoes', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ("echoes", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), ], ), - 'sensor_msgs/msg/LaserScan': ( + "sensor_msgs/msg/LaserScan": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('angle_min', (T.BASE, ('float32', 0))), - ('angle_max', (T.BASE, ('float32', 0))), - ('angle_increment', (T.BASE, ('float32', 0))), - ('time_increment', (T.BASE, ('float32', 0))), - ('scan_time', (T.BASE, ('float32', 0))), - ('range_min', (T.BASE, ('float32', 0))), - ('range_max', (T.BASE, ('float32', 0))), - ('ranges', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), - ('intensities', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("angle_min", (T.BASE, ("float32", 0))), + ("angle_max", (T.BASE, ("float32", 0))), + ("angle_increment", (T.BASE, ("float32", 0))), + ("time_increment", (T.BASE, ("float32", 0))), + ("scan_time", (T.BASE, ("float32", 0))), + ("range_min", (T.BASE, ("float32", 0))), + ("range_max", (T.BASE, ("float32", 0))), + ("ranges", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), + ("intensities", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), ], ), - 'sensor_msgs/msg/MagneticField': ( + "sensor_msgs/msg/MagneticField": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('magnetic_field', (T.NAME, 'geometry_msgs/msg/Vector3')), - ('magnetic_field_covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("magnetic_field", (T.NAME, "geometry_msgs/msg/Vector3")), + ("magnetic_field_covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), ], ), - 'sensor_msgs/msg/MultiDOFJointState': ( + "sensor_msgs/msg/MultiDOFJointState": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('joint_names', (T.SEQUENCE, ((T.BASE, ('string', 0)), 0))), - ('transforms', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Transform'), 0))), - ('twist', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Twist'), 0))), - ('wrench', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Wrench'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("joint_names", (T.SEQUENCE, ((T.BASE, ("string", 0)), 0))), + ("transforms", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Transform"), 0))), + ("twist", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Twist"), 0))), + ("wrench", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Wrench"), 0))), ], ), - 'sensor_msgs/msg/MultiEchoLaserScan': ( + "sensor_msgs/msg/MultiEchoLaserScan": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('angle_min', (T.BASE, ('float32', 0))), - ('angle_max', (T.BASE, ('float32', 0))), - ('angle_increment', (T.BASE, ('float32', 0))), - ('time_increment', (T.BASE, ('float32', 0))), - ('scan_time', (T.BASE, ('float32', 0))), - ('range_min', (T.BASE, ('float32', 0))), - ('range_max', (T.BASE, ('float32', 0))), - ('ranges', (T.SEQUENCE, ((T.NAME, 'sensor_msgs/msg/LaserEcho'), 0))), - ('intensities', (T.SEQUENCE, ((T.NAME, 'sensor_msgs/msg/LaserEcho'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("angle_min", (T.BASE, ("float32", 0))), + ("angle_max", (T.BASE, ("float32", 0))), + ("angle_increment", (T.BASE, ("float32", 0))), + ("time_increment", (T.BASE, ("float32", 0))), + ("scan_time", (T.BASE, ("float32", 0))), + ("range_min", (T.BASE, ("float32", 0))), + ("range_max", (T.BASE, ("float32", 0))), + ("ranges", (T.SEQUENCE, ((T.NAME, "sensor_msgs/msg/LaserEcho"), 0))), + ("intensities", (T.SEQUENCE, ((T.NAME, "sensor_msgs/msg/LaserEcho"), 0))), ], ), - 'sensor_msgs/msg/NavSatStatus': ( + "sensor_msgs/msg/NavSatStatus": ( [ - ('STATUS_UNKNOWN', 'int8', -2), - ('STATUS_NO_FIX', 'int8', -1), - ('STATUS_FIX', 'int8', 0), - ('STATUS_SBAS_FIX', 'int8', 1), - ('STATUS_GBAS_FIX', 'int8', 2), - ('SERVICE_UNKNOWN', 'uint16', 0), - ('SERVICE_GPS', 'uint16', 1), - ('SERVICE_GLONASS', 'uint16', 2), - ('SERVICE_COMPASS', 'uint16', 4), - ('SERVICE_GALILEO', 'uint16', 8), + ("STATUS_UNKNOWN", "int8", -2), + ("STATUS_NO_FIX", "int8", -1), + ("STATUS_FIX", "int8", 0), + ("STATUS_SBAS_FIX", "int8", 1), + ("STATUS_GBAS_FIX", "int8", 2), + ("SERVICE_UNKNOWN", "uint16", 0), + ("SERVICE_GPS", "uint16", 1), + ("SERVICE_GLONASS", "uint16", 2), + ("SERVICE_COMPASS", "uint16", 4), + ("SERVICE_GALILEO", "uint16", 8), ], [ - ('status', (T.BASE, ('int8', 0))), - ('service', (T.BASE, ('uint16', 0))), + ("status", (T.BASE, ("int8", 0))), + ("service", (T.BASE, ("uint16", 0))), ], ), - 'sensor_msgs/msg/NavSatFix': ( + "sensor_msgs/msg/NavSatFix": ( [ - ('COVARIANCE_TYPE_UNKNOWN', 'uint8', 0), - ('COVARIANCE_TYPE_APPROXIMATED', 'uint8', 1), - ('COVARIANCE_TYPE_DIAGONAL_KNOWN', 'uint8', 2), - ('COVARIANCE_TYPE_KNOWN', 'uint8', 3), + ("COVARIANCE_TYPE_UNKNOWN", "uint8", 0), + ("COVARIANCE_TYPE_APPROXIMATED", "uint8", 1), + ("COVARIANCE_TYPE_DIAGONAL_KNOWN", "uint8", 2), + ("COVARIANCE_TYPE_KNOWN", "uint8", 3), ], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('status', (T.NAME, 'sensor_msgs/msg/NavSatStatus')), - ('latitude', (T.BASE, ('float64', 0))), - ('longitude', (T.BASE, ('float64', 0))), - ('altitude', (T.BASE, ('float64', 0))), - ('position_covariance', (T.ARRAY, ((T.BASE, ('float64', 0)), 9))), - ('position_covariance_type', (T.BASE, ('uint8', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("status", (T.NAME, "sensor_msgs/msg/NavSatStatus")), + ("latitude", (T.BASE, ("float64", 0))), + ("longitude", (T.BASE, ("float64", 0))), + ("altitude", (T.BASE, ("float64", 0))), + ("position_covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), + ("position_covariance_type", (T.BASE, ("uint8", 0))), ], ), - 'sensor_msgs/msg/PointCloud': ( + "sensor_msgs/msg/PointCloud": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('points', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point32'), 0))), - ('channels', (T.SEQUENCE, ((T.NAME, 'sensor_msgs/msg/ChannelFloat32'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("points", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point32"), 0))), + ("channels", (T.SEQUENCE, ((T.NAME, "sensor_msgs/msg/ChannelFloat32"), 0))), ], ), - 'sensor_msgs/msg/PointField': ( + "sensor_msgs/msg/PointField": ( [ - ('INT8', 'uint8', 1), - ('UINT8', 'uint8', 2), - ('INT16', 'uint8', 3), - ('UINT16', 'uint8', 4), - ('INT32', 'uint8', 5), - ('UINT32', 'uint8', 6), - ('FLOAT32', 'uint8', 7), - ('FLOAT64', 'uint8', 8), + ("INT8", "uint8", 1), + ("UINT8", "uint8", 2), + ("INT16", "uint8", 3), + ("UINT16", "uint8", 4), + ("INT32", "uint8", 5), + ("UINT32", "uint8", 6), + ("FLOAT32", "uint8", 7), + ("FLOAT64", "uint8", 8), ], [ - ('name', (T.BASE, ('string', 0))), - ('offset', (T.BASE, ('uint32', 0))), - ('datatype', (T.BASE, ('uint8', 0))), - ('count', (T.BASE, ('uint32', 0))), + ("name", (T.BASE, ("string", 0))), + ("offset", (T.BASE, ("uint32", 0))), + ("datatype", (T.BASE, ("uint8", 0))), + ("count", (T.BASE, ("uint32", 0))), ], ), - 'sensor_msgs/msg/PointCloud2': ( + "sensor_msgs/msg/PointCloud2": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('height', (T.BASE, ('uint32', 0))), - ('width', (T.BASE, ('uint32', 0))), - ('fields', (T.SEQUENCE, ((T.NAME, 'sensor_msgs/msg/PointField'), 0))), - ('is_bigendian', (T.BASE, ('bool', 0))), - ('point_step', (T.BASE, ('uint32', 0))), - ('row_step', (T.BASE, ('uint32', 0))), - ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), - ('is_dense', (T.BASE, ('bool', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("height", (T.BASE, ("uint32", 0))), + ("width", (T.BASE, ("uint32", 0))), + ("fields", (T.SEQUENCE, ((T.NAME, "sensor_msgs/msg/PointField"), 0))), + ("is_bigendian", (T.BASE, ("bool", 0))), + ("point_step", (T.BASE, ("uint32", 0))), + ("row_step", (T.BASE, ("uint32", 0))), + ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), + ("is_dense", (T.BASE, ("bool", 0))), ], ), - 'sensor_msgs/msg/Range': ( + "sensor_msgs/msg/Range": ( [ - ('ULTRASOUND', 'uint8', 0), - ('INFRARED', 'uint8', 1), + ("ULTRASOUND", "uint8", 0), + ("INFRARED", "uint8", 1), ], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('radiation_type', (T.BASE, ('uint8', 0))), - ('field_of_view', (T.BASE, ('float32', 0))), - ('min_range', (T.BASE, ('float32', 0))), - ('max_range', (T.BASE, ('float32', 0))), - ('range', (T.BASE, ('float32', 0))), - ('variance', (T.BASE, ('float32', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("radiation_type", (T.BASE, ("uint8", 0))), + ("field_of_view", (T.BASE, ("float32", 0))), + ("min_range", (T.BASE, ("float32", 0))), + ("max_range", (T.BASE, ("float32", 0))), + ("range", (T.BASE, ("float32", 0))), + ("variance", (T.BASE, ("float32", 0))), ], ), - 'sensor_msgs/msg/RelativeHumidity': ( + "sensor_msgs/msg/RelativeHumidity": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('relative_humidity', (T.BASE, ('float64', 0))), - ('variance', (T.BASE, ('float64', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("relative_humidity", (T.BASE, ("float64", 0))), + ("variance", (T.BASE, ("float64", 0))), ], ), - 'sensor_msgs/msg/Temperature': ( + "sensor_msgs/msg/Temperature": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('temperature', (T.BASE, ('float64', 0))), - ('variance', (T.BASE, ('float64', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("temperature", (T.BASE, ("float64", 0))), + ("variance", (T.BASE, ("float64", 0))), ], ), - 'sensor_msgs/msg/TimeReference': ( + "sensor_msgs/msg/TimeReference": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('time_ref', (T.NAME, 'builtin_interfaces/msg/Time')), - ('source', (T.BASE, ('string', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("time_ref", (T.NAME, "builtin_interfaces/msg/Time")), + ("source", (T.BASE, ("string", 0))), ], ), - 'shape_msgs/msg/MeshTriangle': ( + "shape_msgs/msg/MeshTriangle": ( [], [ - ('vertex_indices', (T.ARRAY, ((T.BASE, ('uint32', 0)), 3))), + ("vertex_indices", (T.ARRAY, ((T.BASE, ("uint32", 0)), 3))), ], ), - 'shape_msgs/msg/Mesh': ( + "shape_msgs/msg/Mesh": ( [], [ - ('triangles', (T.SEQUENCE, ((T.NAME, 'shape_msgs/msg/MeshTriangle'), 0))), - ('vertices', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point'), 0))), + ("triangles", (T.SEQUENCE, ((T.NAME, "shape_msgs/msg/MeshTriangle"), 0))), + ("vertices", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point"), 0))), ], ), - 'shape_msgs/msg/Plane': ( + "shape_msgs/msg/Plane": ( [], [ - ('coef', (T.ARRAY, ((T.BASE, ('float64', 0)), 4))), + ("coef", (T.ARRAY, ((T.BASE, ("float64", 0)), 4))), ], ), - 'shape_msgs/msg/SolidPrimitive': ( + "shape_msgs/msg/SolidPrimitive": ( [ - ('BOX', 'uint8', 1), - ('SPHERE', 'uint8', 2), - ('CYLINDER', 'uint8', 3), - ('CONE', 'uint8', 4), - ('PRISM', 'uint8', 5), - ('BOX_X', 'uint8', 0), - ('BOX_Y', 'uint8', 1), - ('BOX_Z', 'uint8', 2), - ('SPHERE_RADIUS', 'uint8', 0), - ('CYLINDER_HEIGHT', 'uint8', 0), - ('CYLINDER_RADIUS', 'uint8', 1), - ('CONE_HEIGHT', 'uint8', 0), - ('CONE_RADIUS', 'uint8', 1), - ('PRISM_HEIGHT', 'uint8', 0), + ("BOX", "uint8", 1), + ("SPHERE", "uint8", 2), + ("CYLINDER", "uint8", 3), + ("CONE", "uint8", 4), + ("PRISM", "uint8", 5), + ("BOX_X", "uint8", 0), + ("BOX_Y", "uint8", 1), + ("BOX_Z", "uint8", 2), + ("SPHERE_RADIUS", "uint8", 0), + ("CYLINDER_HEIGHT", "uint8", 0), + ("CYLINDER_RADIUS", "uint8", 1), + ("CONE_HEIGHT", "uint8", 0), + ("CONE_RADIUS", "uint8", 1), + ("PRISM_HEIGHT", "uint8", 0), ], [ - ('type', (T.BASE, ('uint8', 0))), - ('dimensions', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 3))), - ('polygon', (T.NAME, 'geometry_msgs/msg/Polygon')), + ("type", (T.BASE, ("uint8", 0))), + ("dimensions", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 3))), + ("polygon", (T.NAME, "geometry_msgs/msg/Polygon")), ], ), - 'std_msgs/msg/Bool': ( + "std_msgs/msg/Bool": ( [], [ - ('data', (T.BASE, ('bool', 0))), + ("data", (T.BASE, ("bool", 0))), ], ), - 'std_msgs/msg/Byte': ( + "std_msgs/msg/Byte": ( [], [ - ('data', (T.BASE, ('byte', 0))), + ("data", (T.BASE, ("byte", 0))), ], ), - 'std_msgs/msg/MultiArrayDimension': ( + "std_msgs/msg/MultiArrayDimension": ( [], [ - ('label', (T.BASE, ('string', 0))), - ('size', (T.BASE, ('uint32', 0))), - ('stride', (T.BASE, ('uint32', 0))), + ("label", (T.BASE, ("string", 0))), + ("size", (T.BASE, ("uint32", 0))), + ("stride", (T.BASE, ("uint32", 0))), ], ), - 'std_msgs/msg/MultiArrayLayout': ( + "std_msgs/msg/MultiArrayLayout": ( [], [ - ('dim', (T.SEQUENCE, ((T.NAME, 'std_msgs/msg/MultiArrayDimension'), 0))), - ('data_offset', (T.BASE, ('uint32', 0))), + ("dim", (T.SEQUENCE, ((T.NAME, "std_msgs/msg/MultiArrayDimension"), 0))), + ("data_offset", (T.BASE, ("uint32", 0))), ], ), - 'std_msgs/msg/ByteMultiArray': ( + "std_msgs/msg/ByteMultiArray": ( [], [ - ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), - ('data', (T.SEQUENCE, ((T.BASE, ('byte', 0)), 0))), + ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), + ("data", (T.SEQUENCE, ((T.BASE, ("byte", 0)), 0))), ], ), - 'std_msgs/msg/Char': ( + "std_msgs/msg/Char": ( [], [ - ('data', (T.BASE, ('char', 0))), + ("data", (T.BASE, ("char", 0))), ], ), - 'std_msgs/msg/ColorRGBA': ( + "std_msgs/msg/ColorRGBA": ( [], [ - ('r', (T.BASE, ('float32', 0))), - ('g', (T.BASE, ('float32', 0))), - ('b', (T.BASE, ('float32', 0))), - ('a', (T.BASE, ('float32', 0))), + ("r", (T.BASE, ("float32", 0))), + ("g", (T.BASE, ("float32", 0))), + ("b", (T.BASE, ("float32", 0))), + ("a", (T.BASE, ("float32", 0))), ], ), - 'std_msgs/msg/Empty': ( + "std_msgs/msg/Empty": ( [], [ - ('structure_needs_at_least_one_member', (T.BASE, ('uint8', 0))), + ("structure_needs_at_least_one_member", (T.BASE, ("uint8", 0))), ], ), - 'std_msgs/msg/Float32': ( + "std_msgs/msg/Float32": ( [], [ - ('data', (T.BASE, ('float32', 0))), + ("data", (T.BASE, ("float32", 0))), ], ), - 'std_msgs/msg/Float32MultiArray': ( + "std_msgs/msg/Float32MultiArray": ( [], [ - ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), - ('data', (T.SEQUENCE, ((T.BASE, ('float32', 0)), 0))), + ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), + ("data", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), ], ), - 'std_msgs/msg/Float64': ( + "std_msgs/msg/Float64": ( [], [ - ('data', (T.BASE, ('float64', 0))), + ("data", (T.BASE, ("float64", 0))), ], ), - 'std_msgs/msg/Float64MultiArray': ( + "std_msgs/msg/Float64MultiArray": ( [], [ - ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), - ('data', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), + ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), + ("data", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), ], ), - 'std_msgs/msg/Int16': ( + "std_msgs/msg/Int16": ( [], [ - ('data', (T.BASE, ('int16', 0))), + ("data", (T.BASE, ("int16", 0))), ], ), - 'std_msgs/msg/Int16MultiArray': ( + "std_msgs/msg/Int16MultiArray": ( [], [ - ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), - ('data', (T.SEQUENCE, ((T.BASE, ('int16', 0)), 0))), + ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), + ("data", (T.SEQUENCE, ((T.BASE, ("int16", 0)), 0))), ], ), - 'std_msgs/msg/Int32': ( + "std_msgs/msg/Int32": ( [], [ - ('data', (T.BASE, ('int32', 0))), + ("data", (T.BASE, ("int32", 0))), ], ), - 'std_msgs/msg/Int32MultiArray': ( + "std_msgs/msg/Int32MultiArray": ( [], [ - ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), - ('data', (T.SEQUENCE, ((T.BASE, ('int32', 0)), 0))), + ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), + ("data", (T.SEQUENCE, ((T.BASE, ("int32", 0)), 0))), ], ), - 'std_msgs/msg/Int64': ( + "std_msgs/msg/Int64": ( [], [ - ('data', (T.BASE, ('int64', 0))), + ("data", (T.BASE, ("int64", 0))), ], ), - 'std_msgs/msg/Int64MultiArray': ( + "std_msgs/msg/Int64MultiArray": ( [], [ - ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), - ('data', (T.SEQUENCE, ((T.BASE, ('int64', 0)), 0))), + ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), + ("data", (T.SEQUENCE, ((T.BASE, ("int64", 0)), 0))), ], ), - 'std_msgs/msg/Int8': ( + "std_msgs/msg/Int8": ( [], [ - ('data', (T.BASE, ('int8', 0))), + ("data", (T.BASE, ("int8", 0))), ], ), - 'std_msgs/msg/Int8MultiArray': ( + "std_msgs/msg/Int8MultiArray": ( [], [ - ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), - ('data', (T.SEQUENCE, ((T.BASE, ('int8', 0)), 0))), + ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), + ("data", (T.SEQUENCE, ((T.BASE, ("int8", 0)), 0))), ], ), - 'std_msgs/msg/String': ( + "std_msgs/msg/String": ( [], [ - ('data', (T.BASE, ('string', 0))), + ("data", (T.BASE, ("string", 0))), ], ), - 'std_msgs/msg/UInt16': ( + "std_msgs/msg/UInt16": ( [], [ - ('data', (T.BASE, ('uint16', 0))), + ("data", (T.BASE, ("uint16", 0))), ], ), - 'std_msgs/msg/UInt16MultiArray': ( + "std_msgs/msg/UInt16MultiArray": ( [], [ - ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), - ('data', (T.SEQUENCE, ((T.BASE, ('uint16', 0)), 0))), + ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), + ("data", (T.SEQUENCE, ((T.BASE, ("uint16", 0)), 0))), ], ), - 'std_msgs/msg/UInt32': ( + "std_msgs/msg/UInt32": ( [], [ - ('data', (T.BASE, ('uint32', 0))), + ("data", (T.BASE, ("uint32", 0))), ], ), - 'std_msgs/msg/UInt32MultiArray': ( + "std_msgs/msg/UInt32MultiArray": ( [], [ - ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), - ('data', (T.SEQUENCE, ((T.BASE, ('uint32', 0)), 0))), + ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), + ("data", (T.SEQUENCE, ((T.BASE, ("uint32", 0)), 0))), ], ), - 'std_msgs/msg/UInt64': ( + "std_msgs/msg/UInt64": ( [], [ - ('data', (T.BASE, ('uint64', 0))), + ("data", (T.BASE, ("uint64", 0))), ], ), - 'std_msgs/msg/UInt64MultiArray': ( + "std_msgs/msg/UInt64MultiArray": ( [], [ - ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), - ('data', (T.SEQUENCE, ((T.BASE, ('uint64', 0)), 0))), + ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), + ("data", (T.SEQUENCE, ((T.BASE, ("uint64", 0)), 0))), ], ), - 'std_msgs/msg/UInt8': ( + "std_msgs/msg/UInt8": ( [], [ - ('data', (T.BASE, ('uint8', 0))), + ("data", (T.BASE, ("uint8", 0))), ], ), - 'std_msgs/msg/UInt8MultiArray': ( + "std_msgs/msg/UInt8MultiArray": ( [], [ - ('layout', (T.NAME, 'std_msgs/msg/MultiArrayLayout')), - ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), + ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), + ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), ], ), - 'tf2_msgs/msg/TF2Error': ( + "tf2_msgs/msg/TF2Error": ( [ - ('NO_ERROR', 'uint8', 0), - ('LOOKUP_ERROR', 'uint8', 1), - ('CONNECTIVITY_ERROR', 'uint8', 2), - ('EXTRAPOLATION_ERROR', 'uint8', 3), - ('INVALID_ARGUMENT_ERROR', 'uint8', 4), - ('TIMEOUT_ERROR', 'uint8', 5), - ('TRANSFORM_ERROR', 'uint8', 6), + ("NO_ERROR", "uint8", 0), + ("LOOKUP_ERROR", "uint8", 1), + ("CONNECTIVITY_ERROR", "uint8", 2), + ("EXTRAPOLATION_ERROR", "uint8", 3), + ("INVALID_ARGUMENT_ERROR", "uint8", 4), + ("TIMEOUT_ERROR", "uint8", 5), + ("TRANSFORM_ERROR", "uint8", 6), ], [ - ('error', (T.BASE, ('uint8', 0))), - ('error_string', (T.BASE, ('string', 0))), + ("error", (T.BASE, ("uint8", 0))), + ("error_string", (T.BASE, ("string", 0))), ], ), - 'tf2_msgs/msg/TFMessage': ( + "tf2_msgs/msg/TFMessage": ( [], [ - ('transforms', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/TransformStamped'), 0))), + ("transforms", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/TransformStamped"), 0))), ], ), - 'trajectory_msgs/msg/JointTrajectoryPoint': ( + "trajectory_msgs/msg/JointTrajectoryPoint": ( [], [ - ('positions', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('velocities', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('accelerations', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('effort', (T.SEQUENCE, ((T.BASE, ('float64', 0)), 0))), - ('time_from_start', (T.NAME, 'builtin_interfaces/msg/Duration')), + ("positions", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("velocities", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("accelerations", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("effort", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), + ("time_from_start", (T.NAME, "builtin_interfaces/msg/Duration")), ], ), - 'trajectory_msgs/msg/JointTrajectory': ( + "trajectory_msgs/msg/JointTrajectory": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('joint_names', (T.SEQUENCE, ((T.BASE, ('string', 0)), 0))), - ('points', (T.SEQUENCE, ((T.NAME, 'trajectory_msgs/msg/JointTrajectoryPoint'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("joint_names", (T.SEQUENCE, ((T.BASE, ("string", 0)), 0))), + ("points", (T.SEQUENCE, ((T.NAME, "trajectory_msgs/msg/JointTrajectoryPoint"), 0))), ], ), - 'trajectory_msgs/msg/MultiDOFJointTrajectoryPoint': ( + "trajectory_msgs/msg/MultiDOFJointTrajectoryPoint": ( [], [ - ('transforms', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Transform'), 0))), - ('velocities', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Twist'), 0))), - ('accelerations', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Twist'), 0))), - ('time_from_start', (T.NAME, 'builtin_interfaces/msg/Duration')), + ("transforms", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Transform"), 0))), + ("velocities", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Twist"), 0))), + ("accelerations", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Twist"), 0))), + ("time_from_start", (T.NAME, "builtin_interfaces/msg/Duration")), ], ), - 'trajectory_msgs/msg/MultiDOFJointTrajectory': ( + "trajectory_msgs/msg/MultiDOFJointTrajectory": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('joint_names', (T.SEQUENCE, ((T.BASE, ('string', 0)), 0))), - ('points', (T.SEQUENCE, ((T.NAME, 'trajectory_msgs/msg/MultiDOFJointTrajectoryPoint'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("joint_names", (T.SEQUENCE, ((T.BASE, ("string", 0)), 0))), + ( + "points", + (T.SEQUENCE, ((T.NAME, "trajectory_msgs/msg/MultiDOFJointTrajectoryPoint"), 0)), + ), ], ), - 'vision_msgs/msg/BoundingBox2DArray': ( + "vision_msgs/msg/BoundingBox2DArray": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('boxes', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/BoundingBox2D'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("boxes", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/BoundingBox2D"), 0))), ], ), - 'vision_msgs/msg/BoundingBox3DArray': ( + "vision_msgs/msg/BoundingBox3DArray": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('boxes', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/BoundingBox3D'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("boxes", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/BoundingBox3D"), 0))), ], ), - 'vision_msgs/msg/ObjectHypothesis': ( + "vision_msgs/msg/ObjectHypothesis": ( [], [ - ('class_id', (T.BASE, ('string', 0))), - ('score', (T.BASE, ('float64', 0))), + ("class_id", (T.BASE, ("string", 0))), + ("score", (T.BASE, ("float64", 0))), ], ), - 'vision_msgs/msg/Classification': ( + "vision_msgs/msg/Classification": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('results', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/ObjectHypothesis'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("results", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/ObjectHypothesis"), 0))), ], ), - 'vision_msgs/msg/ObjectHypothesisWithPose': ( + "vision_msgs/msg/ObjectHypothesisWithPose": ( [], [ - ('hypothesis', (T.NAME, 'vision_msgs/msg/ObjectHypothesis')), - ('pose', (T.NAME, 'geometry_msgs/msg/PoseWithCovariance')), + ("hypothesis", (T.NAME, "vision_msgs/msg/ObjectHypothesis")), + ("pose", (T.NAME, "geometry_msgs/msg/PoseWithCovariance")), ], ), - 'vision_msgs/msg/Detection2D': ( + "vision_msgs/msg/Detection2D": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('results', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/ObjectHypothesisWithPose'), 0))), - ('bbox', (T.NAME, 'vision_msgs/msg/BoundingBox2D')), - ('id', (T.BASE, ('string', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("results", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/ObjectHypothesisWithPose"), 0))), + ("bbox", (T.NAME, "vision_msgs/msg/BoundingBox2D")), + ("id", (T.BASE, ("string", 0))), ], ), - 'vision_msgs/msg/Detection2DArray': ( + "vision_msgs/msg/Detection2DArray": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('detections', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/Detection2D'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("detections", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/Detection2D"), 0))), ], ), - 'vision_msgs/msg/Detection3D': ( + "vision_msgs/msg/Detection3D": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('results', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/ObjectHypothesisWithPose'), 0))), - ('bbox', (T.NAME, 'vision_msgs/msg/BoundingBox3D')), - ('id', (T.BASE, ('string', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("results", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/ObjectHypothesisWithPose"), 0))), + ("bbox", (T.NAME, "vision_msgs/msg/BoundingBox3D")), + ("id", (T.BASE, ("string", 0))), ], ), - 'vision_msgs/msg/Detection3DArray': ( + "vision_msgs/msg/Detection3DArray": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('detections', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/Detection3D'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("detections", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/Detection3D"), 0))), ], ), - 'vision_msgs/msg/VisionClass': ( + "vision_msgs/msg/VisionClass": ( [], [ - ('class_id', (T.BASE, ('uint16', 0))), - ('class_name', (T.BASE, ('string', 0))), + ("class_id", (T.BASE, ("uint16", 0))), + ("class_name", (T.BASE, ("string", 0))), ], ), - 'vision_msgs/msg/LabelInfo': ( + "vision_msgs/msg/LabelInfo": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('class_map', (T.SEQUENCE, ((T.NAME, 'vision_msgs/msg/VisionClass'), 0))), - ('threshold', (T.BASE, ('float32', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("class_map", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/VisionClass"), 0))), + ("threshold", (T.BASE, ("float32", 0))), ], ), - 'vision_msgs/msg/VisionInfo': ( + "vision_msgs/msg/VisionInfo": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('method', (T.BASE, ('string', 0))), - ('database_location', (T.BASE, ('string', 0))), - ('database_version', (T.BASE, ('int32', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("method", (T.BASE, ("string", 0))), + ("database_location", (T.BASE, ("string", 0))), + ("database_version", (T.BASE, ("int32", 0))), ], ), - 'visualization_msgs/msg/ImageMarker': ( + "visualization_msgs/msg/ImageMarker": ( [ - ('CIRCLE', 'int32', 0), - ('LINE_STRIP', 'int32', 1), - ('LINE_LIST', 'int32', 2), - ('POLYGON', 'int32', 3), - ('POINTS', 'int32', 4), - ('ADD', 'int32', 0), - ('REMOVE', 'int32', 1), + ("CIRCLE", "int32", 0), + ("LINE_STRIP", "int32", 1), + ("LINE_LIST", "int32", 2), + ("POLYGON", "int32", 3), + ("POINTS", "int32", 4), + ("ADD", "int32", 0), + ("REMOVE", "int32", 1), ], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('ns', (T.BASE, ('string', 0))), - ('id', (T.BASE, ('int32', 0))), - ('type', (T.BASE, ('int32', 0))), - ('action', (T.BASE, ('int32', 0))), - ('position', (T.NAME, 'geometry_msgs/msg/Point')), - ('scale', (T.BASE, ('float32', 0))), - ('outline_color', (T.NAME, 'std_msgs/msg/ColorRGBA')), - ('filled', (T.BASE, ('uint8', 0))), - ('fill_color', (T.NAME, 'std_msgs/msg/ColorRGBA')), - ('lifetime', (T.NAME, 'builtin_interfaces/msg/Duration')), - ('points', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point'), 0))), - ('outline_colors', (T.SEQUENCE, ((T.NAME, 'std_msgs/msg/ColorRGBA'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("ns", (T.BASE, ("string", 0))), + ("id", (T.BASE, ("int32", 0))), + ("type", (T.BASE, ("int32", 0))), + ("action", (T.BASE, ("int32", 0))), + ("position", (T.NAME, "geometry_msgs/msg/Point")), + ("scale", (T.BASE, ("float32", 0))), + ("outline_color", (T.NAME, "std_msgs/msg/ColorRGBA")), + ("filled", (T.BASE, ("uint8", 0))), + ("fill_color", (T.NAME, "std_msgs/msg/ColorRGBA")), + ("lifetime", (T.NAME, "builtin_interfaces/msg/Duration")), + ("points", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point"), 0))), + ("outline_colors", (T.SEQUENCE, ((T.NAME, "std_msgs/msg/ColorRGBA"), 0))), ], ), - 'visualization_msgs/msg/MeshFile': ( + "visualization_msgs/msg/MeshFile": ( [], [ - ('filename', (T.BASE, ('string', 0))), - ('data', (T.SEQUENCE, ((T.BASE, ('uint8', 0)), 0))), + ("filename", (T.BASE, ("string", 0))), + ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), ], ), - 'visualization_msgs/msg/UVCoordinate': ( + "visualization_msgs/msg/UVCoordinate": ( [], [ - ('u', (T.BASE, ('float32', 0))), - ('v', (T.BASE, ('float32', 0))), + ("u", (T.BASE, ("float32", 0))), + ("v", (T.BASE, ("float32", 0))), ], ), - 'visualization_msgs/msg/Marker': ( + "visualization_msgs/msg/Marker": ( [ - ('ARROW', 'int32', 0), - ('CUBE', 'int32', 1), - ('SPHERE', 'int32', 2), - ('CYLINDER', 'int32', 3), - ('LINE_STRIP', 'int32', 4), - ('LINE_LIST', 'int32', 5), - ('CUBE_LIST', 'int32', 6), - ('SPHERE_LIST', 'int32', 7), - ('POINTS', 'int32', 8), - ('TEXT_VIEW_FACING', 'int32', 9), - ('MESH_RESOURCE', 'int32', 10), - ('TRIANGLE_LIST', 'int32', 11), - ('ARROW_STRIP', 'int32', 12), - ('ADD', 'int32', 0), - ('MODIFY', 'int32', 0), - ('DELETE', 'int32', 2), - ('DELETEALL', 'int32', 3), + ("ARROW", "int32", 0), + ("CUBE", "int32", 1), + ("SPHERE", "int32", 2), + ("CYLINDER", "int32", 3), + ("LINE_STRIP", "int32", 4), + ("LINE_LIST", "int32", 5), + ("CUBE_LIST", "int32", 6), + ("SPHERE_LIST", "int32", 7), + ("POINTS", "int32", 8), + ("TEXT_VIEW_FACING", "int32", 9), + ("MESH_RESOURCE", "int32", 10), + ("TRIANGLE_LIST", "int32", 11), + ("ARROW_STRIP", "int32", 12), + ("ADD", "int32", 0), + ("MODIFY", "int32", 0), + ("DELETE", "int32", 2), + ("DELETEALL", "int32", 3), ], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('ns', (T.BASE, ('string', 0))), - ('id', (T.BASE, ('int32', 0))), - ('type', (T.BASE, ('int32', 0))), - ('action', (T.BASE, ('int32', 0))), - ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), - ('scale', (T.NAME, 'geometry_msgs/msg/Vector3')), - ('color', (T.NAME, 'std_msgs/msg/ColorRGBA')), - ('lifetime', (T.NAME, 'builtin_interfaces/msg/Duration')), - ('frame_locked', (T.BASE, ('bool', 0))), - ('points', (T.SEQUENCE, ((T.NAME, 'geometry_msgs/msg/Point'), 0))), - ('colors', (T.SEQUENCE, ((T.NAME, 'std_msgs/msg/ColorRGBA'), 0))), - ('texture_resource', (T.BASE, ('string', 0))), - ('texture', (T.NAME, 'sensor_msgs/msg/CompressedImage')), - ('uv_coordinates', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/UVCoordinate'), 0))), - ('text', (T.BASE, ('string', 0))), - ('mesh_resource', (T.BASE, ('string', 0))), - ('mesh_file', (T.NAME, 'visualization_msgs/msg/MeshFile')), - ('mesh_use_embedded_materials', (T.BASE, ('bool', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("ns", (T.BASE, ("string", 0))), + ("id", (T.BASE, ("int32", 0))), + ("type", (T.BASE, ("int32", 0))), + ("action", (T.BASE, ("int32", 0))), + ("pose", (T.NAME, "geometry_msgs/msg/Pose")), + ("scale", (T.NAME, "geometry_msgs/msg/Vector3")), + ("color", (T.NAME, "std_msgs/msg/ColorRGBA")), + ("lifetime", (T.NAME, "builtin_interfaces/msg/Duration")), + ("frame_locked", (T.BASE, ("bool", 0))), + ("points", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point"), 0))), + ("colors", (T.SEQUENCE, ((T.NAME, "std_msgs/msg/ColorRGBA"), 0))), + ("texture_resource", (T.BASE, ("string", 0))), + ("texture", (T.NAME, "sensor_msgs/msg/CompressedImage")), + ("uv_coordinates", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/UVCoordinate"), 0))), + ("text", (T.BASE, ("string", 0))), + ("mesh_resource", (T.BASE, ("string", 0))), + ("mesh_file", (T.NAME, "visualization_msgs/msg/MeshFile")), + ("mesh_use_embedded_materials", (T.BASE, ("bool", 0))), ], ), - 'visualization_msgs/msg/InteractiveMarkerControl': ( + "visualization_msgs/msg/InteractiveMarkerControl": ( [ - ('INHERIT', 'uint8', 0), - ('FIXED', 'uint8', 1), - ('VIEW_FACING', 'uint8', 2), - ('NONE', 'uint8', 0), - ('MENU', 'uint8', 1), - ('BUTTON', 'uint8', 2), - ('MOVE_AXIS', 'uint8', 3), - ('MOVE_PLANE', 'uint8', 4), - ('ROTATE_AXIS', 'uint8', 5), - ('MOVE_ROTATE', 'uint8', 6), - ('MOVE_3D', 'uint8', 7), - ('ROTATE_3D', 'uint8', 8), - ('MOVE_ROTATE_3D', 'uint8', 9), + ("INHERIT", "uint8", 0), + ("FIXED", "uint8", 1), + ("VIEW_FACING", "uint8", 2), + ("NONE", "uint8", 0), + ("MENU", "uint8", 1), + ("BUTTON", "uint8", 2), + ("MOVE_AXIS", "uint8", 3), + ("MOVE_PLANE", "uint8", 4), + ("ROTATE_AXIS", "uint8", 5), + ("MOVE_ROTATE", "uint8", 6), + ("MOVE_3D", "uint8", 7), + ("ROTATE_3D", "uint8", 8), + ("MOVE_ROTATE_3D", "uint8", 9), ], [ - ('name', (T.BASE, ('string', 0))), - ('orientation', (T.NAME, 'geometry_msgs/msg/Quaternion')), - ('orientation_mode', (T.BASE, ('uint8', 0))), - ('interaction_mode', (T.BASE, ('uint8', 0))), - ('always_visible', (T.BASE, ('bool', 0))), - ('markers', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/Marker'), 0))), - ('independent_marker_orientation', (T.BASE, ('bool', 0))), - ('description', (T.BASE, ('string', 0))), + ("name", (T.BASE, ("string", 0))), + ("orientation", (T.NAME, "geometry_msgs/msg/Quaternion")), + ("orientation_mode", (T.BASE, ("uint8", 0))), + ("interaction_mode", (T.BASE, ("uint8", 0))), + ("always_visible", (T.BASE, ("bool", 0))), + ("markers", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/Marker"), 0))), + ("independent_marker_orientation", (T.BASE, ("bool", 0))), + ("description", (T.BASE, ("string", 0))), ], ), - 'visualization_msgs/msg/MenuEntry': ( + "visualization_msgs/msg/MenuEntry": ( [ - ('FEEDBACK', 'uint8', 0), - ('ROSRUN', 'uint8', 1), - ('ROSLAUNCH', 'uint8', 2), + ("FEEDBACK", "uint8", 0), + ("ROSRUN", "uint8", 1), + ("ROSLAUNCH", "uint8", 2), ], [ - ('id', (T.BASE, ('uint32', 0))), - ('parent_id', (T.BASE, ('uint32', 0))), - ('title', (T.BASE, ('string', 0))), - ('command', (T.BASE, ('string', 0))), - ('command_type', (T.BASE, ('uint8', 0))), + ("id", (T.BASE, ("uint32", 0))), + ("parent_id", (T.BASE, ("uint32", 0))), + ("title", (T.BASE, ("string", 0))), + ("command", (T.BASE, ("string", 0))), + ("command_type", (T.BASE, ("uint8", 0))), ], ), - 'visualization_msgs/msg/InteractiveMarker': ( + "visualization_msgs/msg/InteractiveMarker": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), - ('name', (T.BASE, ('string', 0))), - ('description', (T.BASE, ('string', 0))), - ('scale', (T.BASE, ('float32', 0))), - ('menu_entries', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/MenuEntry'), 0))), - ('controls', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/InteractiveMarkerControl'), 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("pose", (T.NAME, "geometry_msgs/msg/Pose")), + ("name", (T.BASE, ("string", 0))), + ("description", (T.BASE, ("string", 0))), + ("scale", (T.BASE, ("float32", 0))), + ("menu_entries", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/MenuEntry"), 0))), + ( + "controls", + (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/InteractiveMarkerControl"), 0)), + ), ], ), - 'visualization_msgs/msg/InteractiveMarkerFeedback': ( + "visualization_msgs/msg/InteractiveMarkerFeedback": ( [ - ('KEEP_ALIVE', 'uint8', 0), - ('POSE_UPDATE', 'uint8', 1), - ('MENU_SELECT', 'uint8', 2), - ('BUTTON_CLICK', 'uint8', 3), - ('MOUSE_DOWN', 'uint8', 4), - ('MOUSE_UP', 'uint8', 5), + ("KEEP_ALIVE", "uint8", 0), + ("POSE_UPDATE", "uint8", 1), + ("MENU_SELECT", "uint8", 2), + ("BUTTON_CLICK", "uint8", 3), + ("MOUSE_DOWN", "uint8", 4), + ("MOUSE_UP", "uint8", 5), ], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('client_id', (T.BASE, ('string', 0))), - ('marker_name', (T.BASE, ('string', 0))), - ('control_name', (T.BASE, ('string', 0))), - ('event_type', (T.BASE, ('uint8', 0))), - ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), - ('menu_entry_id', (T.BASE, ('uint32', 0))), - ('mouse_point', (T.NAME, 'geometry_msgs/msg/Point')), - ('mouse_point_valid', (T.BASE, ('bool', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("client_id", (T.BASE, ("string", 0))), + ("marker_name", (T.BASE, ("string", 0))), + ("control_name", (T.BASE, ("string", 0))), + ("event_type", (T.BASE, ("uint8", 0))), + ("pose", (T.NAME, "geometry_msgs/msg/Pose")), + ("menu_entry_id", (T.BASE, ("uint32", 0))), + ("mouse_point", (T.NAME, "geometry_msgs/msg/Point")), + ("mouse_point_valid", (T.BASE, ("bool", 0))), ], ), - 'visualization_msgs/msg/InteractiveMarkerInit': ( + "visualization_msgs/msg/InteractiveMarkerInit": ( [], [ - ('server_id', (T.BASE, ('string', 0))), - ('seq_num', (T.BASE, ('uint64', 0))), - ('markers', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/InteractiveMarker'), 0))), + ("server_id", (T.BASE, ("string", 0))), + ("seq_num", (T.BASE, ("uint64", 0))), + ("markers", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/InteractiveMarker"), 0))), ], ), - 'visualization_msgs/msg/InteractiveMarkerPose': ( + "visualization_msgs/msg/InteractiveMarkerPose": ( [], [ - ('header', (T.NAME, 'std_msgs/msg/Header')), - ('pose', (T.NAME, 'geometry_msgs/msg/Pose')), - ('name', (T.BASE, ('string', 0))), + ("header", (T.NAME, "std_msgs/msg/Header")), + ("pose", (T.NAME, "geometry_msgs/msg/Pose")), + ("name", (T.BASE, ("string", 0))), ], ), - 'visualization_msgs/msg/InteractiveMarkerUpdate': ( + "visualization_msgs/msg/InteractiveMarkerUpdate": ( [ - ('KEEP_ALIVE', 'uint8', 0), - ('UPDATE', 'uint8', 1), + ("KEEP_ALIVE", "uint8", 0), + ("UPDATE", "uint8", 1), ], [ - ('server_id', (T.BASE, ('string', 0))), - ('seq_num', (T.BASE, ('uint64', 0))), - ('type', (T.BASE, ('uint8', 0))), - ('markers', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/InteractiveMarker'), 0))), - ('poses', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/InteractiveMarkerPose'), 0))), - ('erases', (T.SEQUENCE, ((T.BASE, ('string', 0)), 0))), + ("server_id", (T.BASE, ("string", 0))), + ("seq_num", (T.BASE, ("uint64", 0))), + ("type", (T.BASE, ("uint8", 0))), + ("markers", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/InteractiveMarker"), 0))), + ("poses", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/InteractiveMarkerPose"), 0))), + ("erases", (T.SEQUENCE, ((T.BASE, ("string", 0)), 0))), ], ), - 'visualization_msgs/msg/MarkerArray': ( + "visualization_msgs/msg/MarkerArray": ( [], [ - ('markers', (T.SEQUENCE, ((T.NAME, 'visualization_msgs/msg/Marker'), 0))), + ("markers", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/Marker"), 0))), ], ), } - diff --git a/packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi index 1eb4aa66ee0..ec2a13773fc 100644 --- a/packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi @@ -1,3 +1,5 @@ -__all__ = ['Duration', 'Time'] -from ..._types import builtin_interfaces__msg__Duration as Duration -from ..._types import builtin_interfaces__msg__Time as Time +__all__ = ["Duration", "Time"] +from ..._types import ( + builtin_interfaces__msg__Duration as Duration, + builtin_interfaces__msg__Time as Time, +) diff --git a/packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi index 63aa855140d..056431b7fa6 100644 --- a/packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi @@ -1,15 +1,32 @@ -__all__ = ['BoundingBox2DArray', 'BoundingBox3DArray', 'EntityMarker', 'EntityMarkers', 'GraspCandidate', 'GraspCandidateArray', 'ImuInfo', 'JointCommand', 'LineSegment3D', 'LineSegments3D', 'MotorCommandArray', 'RobotState', 'TrajectoryStatus', 'VideoStats'] -from ..._types import dimos_msgs__msg__BoundingBox2DArray as BoundingBox2DArray -from ..._types import dimos_msgs__msg__BoundingBox3DArray as BoundingBox3DArray -from ..._types import dimos_msgs__msg__EntityMarker as EntityMarker -from ..._types import dimos_msgs__msg__EntityMarkers as EntityMarkers -from ..._types import dimos_msgs__msg__GraspCandidate as GraspCandidate -from ..._types import dimos_msgs__msg__GraspCandidateArray as GraspCandidateArray -from ..._types import dimos_msgs__msg__ImuInfo as ImuInfo -from ..._types import dimos_msgs__msg__JointCommand as JointCommand -from ..._types import dimos_msgs__msg__LineSegment3D as LineSegment3D -from ..._types import dimos_msgs__msg__LineSegments3D as LineSegments3D -from ..._types import dimos_msgs__msg__MotorCommandArray as MotorCommandArray -from ..._types import dimos_msgs__msg__RobotState as RobotState -from ..._types import dimos_msgs__msg__TrajectoryStatus as TrajectoryStatus -from ..._types import dimos_msgs__msg__VideoStats as VideoStats +__all__ = [ + "BoundingBox2DArray", + "BoundingBox3DArray", + "EntityMarker", + "EntityMarkers", + "GraspCandidate", + "GraspCandidateArray", + "ImuInfo", + "JointCommand", + "LineSegment3D", + "LineSegments3D", + "MotorCommandArray", + "RobotState", + "TrajectoryStatus", + "VideoStats", +] +from ..._types import ( + dimos_msgs__msg__BoundingBox2DArray as BoundingBox2DArray, + dimos_msgs__msg__BoundingBox3DArray as BoundingBox3DArray, + dimos_msgs__msg__EntityMarker as EntityMarker, + dimos_msgs__msg__EntityMarkers as EntityMarkers, + dimos_msgs__msg__GraspCandidate as GraspCandidate, + dimos_msgs__msg__GraspCandidateArray as GraspCandidateArray, + dimos_msgs__msg__ImuInfo as ImuInfo, + dimos_msgs__msg__JointCommand as JointCommand, + dimos_msgs__msg__LineSegment3D as LineSegment3D, + dimos_msgs__msg__LineSegments3D as LineSegments3D, + dimos_msgs__msg__MotorCommandArray as MotorCommandArray, + dimos_msgs__msg__RobotState as RobotState, + dimos_msgs__msg__TrajectoryStatus as TrajectoryStatus, + dimos_msgs__msg__VideoStats as VideoStats, +) diff --git a/packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi index c6eaf3c2003..83a79d0260d 100644 --- a/packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi @@ -1,2 +1,2 @@ -__all__ = ['CompressedVideo'] +__all__ = ["CompressedVideo"] from ..._types import foxglove_msgs__msg__CompressedVideo as CompressedVideo diff --git a/packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi index ca37dc02977..f63131d99af 100644 --- a/packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi @@ -1,34 +1,70 @@ -__all__ = ['Point', 'Quaternion', 'Pose', 'Vector3', 'Accel', 'AccelStamped', 'AccelWithCovariance', 'AccelWithCovarianceStamped', 'Inertia', 'InertiaStamped', 'Point32', 'PointStamped', 'Polygon', 'PolygonInstance', 'PolygonInstanceStamped', 'PolygonStamped', 'Pose2D', 'PoseArray', 'PoseStamped', 'PoseWithCovariance', 'PoseWithCovarianceStamped', 'QuaternionStamped', 'Transform', 'TransformStamped', 'Twist', 'TwistStamped', 'TwistWithCovariance', 'TwistWithCovarianceStamped', 'Vector3Stamped', 'VelocityStamped', 'VelocityWithCovarianceStamped', 'Wrench', 'WrenchStamped'] -from ..._types import geometry_msgs__msg__Point as Point -from ..._types import geometry_msgs__msg__Quaternion as Quaternion -from ..._types import geometry_msgs__msg__Pose as Pose -from ..._types import geometry_msgs__msg__Vector3 as Vector3 -from ..._types import geometry_msgs__msg__Accel as Accel -from ..._types import geometry_msgs__msg__AccelStamped as AccelStamped -from ..._types import geometry_msgs__msg__AccelWithCovariance as AccelWithCovariance -from ..._types import geometry_msgs__msg__AccelWithCovarianceStamped as AccelWithCovarianceStamped -from ..._types import geometry_msgs__msg__Inertia as Inertia -from ..._types import geometry_msgs__msg__InertiaStamped as InertiaStamped -from ..._types import geometry_msgs__msg__Point32 as Point32 -from ..._types import geometry_msgs__msg__PointStamped as PointStamped -from ..._types import geometry_msgs__msg__Polygon as Polygon -from ..._types import geometry_msgs__msg__PolygonInstance as PolygonInstance -from ..._types import geometry_msgs__msg__PolygonInstanceStamped as PolygonInstanceStamped -from ..._types import geometry_msgs__msg__PolygonStamped as PolygonStamped -from ..._types import geometry_msgs__msg__Pose2D as Pose2D -from ..._types import geometry_msgs__msg__PoseArray as PoseArray -from ..._types import geometry_msgs__msg__PoseStamped as PoseStamped -from ..._types import geometry_msgs__msg__PoseWithCovariance as PoseWithCovariance -from ..._types import geometry_msgs__msg__PoseWithCovarianceStamped as PoseWithCovarianceStamped -from ..._types import geometry_msgs__msg__QuaternionStamped as QuaternionStamped -from ..._types import geometry_msgs__msg__Transform as Transform -from ..._types import geometry_msgs__msg__TransformStamped as TransformStamped -from ..._types import geometry_msgs__msg__Twist as Twist -from ..._types import geometry_msgs__msg__TwistStamped as TwistStamped -from ..._types import geometry_msgs__msg__TwistWithCovariance as TwistWithCovariance -from ..._types import geometry_msgs__msg__TwistWithCovarianceStamped as TwistWithCovarianceStamped -from ..._types import geometry_msgs__msg__Vector3Stamped as Vector3Stamped -from ..._types import geometry_msgs__msg__VelocityStamped as VelocityStamped -from ..._types import geometry_msgs__msg__VelocityWithCovarianceStamped as VelocityWithCovarianceStamped -from ..._types import geometry_msgs__msg__Wrench as Wrench -from ..._types import geometry_msgs__msg__WrenchStamped as WrenchStamped +__all__ = [ + "Accel", + "AccelStamped", + "AccelWithCovariance", + "AccelWithCovarianceStamped", + "Inertia", + "InertiaStamped", + "Point", + "Point32", + "PointStamped", + "Polygon", + "PolygonInstance", + "PolygonInstanceStamped", + "PolygonStamped", + "Pose", + "Pose2D", + "PoseArray", + "PoseStamped", + "PoseWithCovariance", + "PoseWithCovarianceStamped", + "Quaternion", + "QuaternionStamped", + "Transform", + "TransformStamped", + "Twist", + "TwistStamped", + "TwistWithCovariance", + "TwistWithCovarianceStamped", + "Vector3", + "Vector3Stamped", + "VelocityStamped", + "VelocityWithCovarianceStamped", + "Wrench", + "WrenchStamped", +] +from ..._types import ( + geometry_msgs__msg__Accel as Accel, + geometry_msgs__msg__AccelStamped as AccelStamped, + geometry_msgs__msg__AccelWithCovariance as AccelWithCovariance, + geometry_msgs__msg__AccelWithCovarianceStamped as AccelWithCovarianceStamped, + geometry_msgs__msg__Inertia as Inertia, + geometry_msgs__msg__InertiaStamped as InertiaStamped, + geometry_msgs__msg__Point as Point, + geometry_msgs__msg__Point32 as Point32, + geometry_msgs__msg__PointStamped as PointStamped, + geometry_msgs__msg__Polygon as Polygon, + geometry_msgs__msg__PolygonInstance as PolygonInstance, + geometry_msgs__msg__PolygonInstanceStamped as PolygonInstanceStamped, + geometry_msgs__msg__PolygonStamped as PolygonStamped, + geometry_msgs__msg__Pose as Pose, + geometry_msgs__msg__Pose2D as Pose2D, + geometry_msgs__msg__PoseArray as PoseArray, + geometry_msgs__msg__PoseStamped as PoseStamped, + geometry_msgs__msg__PoseWithCovariance as PoseWithCovariance, + geometry_msgs__msg__PoseWithCovarianceStamped as PoseWithCovarianceStamped, + geometry_msgs__msg__Quaternion as Quaternion, + geometry_msgs__msg__QuaternionStamped as QuaternionStamped, + geometry_msgs__msg__Transform as Transform, + geometry_msgs__msg__TransformStamped as TransformStamped, + geometry_msgs__msg__Twist as Twist, + geometry_msgs__msg__TwistStamped as TwistStamped, + geometry_msgs__msg__TwistWithCovariance as TwistWithCovariance, + geometry_msgs__msg__TwistWithCovarianceStamped as TwistWithCovarianceStamped, + geometry_msgs__msg__Vector3 as Vector3, + geometry_msgs__msg__Vector3Stamped as Vector3Stamped, + geometry_msgs__msg__VelocityStamped as VelocityStamped, + geometry_msgs__msg__VelocityWithCovarianceStamped as VelocityWithCovarianceStamped, + geometry_msgs__msg__Wrench as Wrench, + geometry_msgs__msg__WrenchStamped as WrenchStamped, +) diff --git a/packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi index a029ed23155..ac4e6d5ffbf 100644 --- a/packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi @@ -1,9 +1,20 @@ -__all__ = ['Goals', 'GridCells', 'MapMetaData', 'OccupancyGrid', 'Odometry', 'Path', 'TrajectoryPoint', 'Trajectory'] -from ..._types import nav_msgs__msg__Goals as Goals -from ..._types import nav_msgs__msg__GridCells as GridCells -from ..._types import nav_msgs__msg__MapMetaData as MapMetaData -from ..._types import nav_msgs__msg__OccupancyGrid as OccupancyGrid -from ..._types import nav_msgs__msg__Odometry as Odometry -from ..._types import nav_msgs__msg__Path as Path -from ..._types import nav_msgs__msg__TrajectoryPoint as TrajectoryPoint -from ..._types import nav_msgs__msg__Trajectory as Trajectory +__all__ = [ + "Goals", + "GridCells", + "MapMetaData", + "OccupancyGrid", + "Odometry", + "Path", + "Trajectory", + "TrajectoryPoint", +] +from ..._types import ( + nav_msgs__msg__Goals as Goals, + nav_msgs__msg__GridCells as GridCells, + nav_msgs__msg__MapMetaData as MapMetaData, + nav_msgs__msg__OccupancyGrid as OccupancyGrid, + nav_msgs__msg__Odometry as Odometry, + nav_msgs__msg__Path as Path, + nav_msgs__msg__Trajectory as Trajectory, + nav_msgs__msg__TrajectoryPoint as TrajectoryPoint, +) diff --git a/packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi index 5a4747315a0..f60aec0a657 100644 --- a/packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi @@ -1,28 +1,58 @@ -__all__ = ['BatteryState', 'RegionOfInterest', 'CameraInfo', 'ChannelFloat32', 'CompressedImage', 'FluidPressure', 'Illuminance', 'Image', 'Imu', 'JointState', 'Joy', 'JoyFeedback', 'JoyFeedbackArray', 'LaserEcho', 'LaserScan', 'MagneticField', 'MultiDOFJointState', 'MultiEchoLaserScan', 'NavSatStatus', 'NavSatFix', 'PointCloud', 'PointField', 'PointCloud2', 'Range', 'RelativeHumidity', 'Temperature', 'TimeReference'] -from ..._types import sensor_msgs__msg__BatteryState as BatteryState -from ..._types import sensor_msgs__msg__RegionOfInterest as RegionOfInterest -from ..._types import sensor_msgs__msg__CameraInfo as CameraInfo -from ..._types import sensor_msgs__msg__ChannelFloat32 as ChannelFloat32 -from ..._types import sensor_msgs__msg__CompressedImage as CompressedImage -from ..._types import sensor_msgs__msg__FluidPressure as FluidPressure -from ..._types import sensor_msgs__msg__Illuminance as Illuminance -from ..._types import sensor_msgs__msg__Image as Image -from ..._types import sensor_msgs__msg__Imu as Imu -from ..._types import sensor_msgs__msg__JointState as JointState -from ..._types import sensor_msgs__msg__Joy as Joy -from ..._types import sensor_msgs__msg__JoyFeedback as JoyFeedback -from ..._types import sensor_msgs__msg__JoyFeedbackArray as JoyFeedbackArray -from ..._types import sensor_msgs__msg__LaserEcho as LaserEcho -from ..._types import sensor_msgs__msg__LaserScan as LaserScan -from ..._types import sensor_msgs__msg__MagneticField as MagneticField -from ..._types import sensor_msgs__msg__MultiDOFJointState as MultiDOFJointState -from ..._types import sensor_msgs__msg__MultiEchoLaserScan as MultiEchoLaserScan -from ..._types import sensor_msgs__msg__NavSatStatus as NavSatStatus -from ..._types import sensor_msgs__msg__NavSatFix as NavSatFix -from ..._types import sensor_msgs__msg__PointCloud as PointCloud -from ..._types import sensor_msgs__msg__PointField as PointField -from ..._types import sensor_msgs__msg__PointCloud2 as PointCloud2 -from ..._types import sensor_msgs__msg__Range as Range -from ..._types import sensor_msgs__msg__RelativeHumidity as RelativeHumidity -from ..._types import sensor_msgs__msg__Temperature as Temperature -from ..._types import sensor_msgs__msg__TimeReference as TimeReference +__all__ = [ + "BatteryState", + "CameraInfo", + "ChannelFloat32", + "CompressedImage", + "FluidPressure", + "Illuminance", + "Image", + "Imu", + "JointState", + "Joy", + "JoyFeedback", + "JoyFeedbackArray", + "LaserEcho", + "LaserScan", + "MagneticField", + "MultiDOFJointState", + "MultiEchoLaserScan", + "NavSatFix", + "NavSatStatus", + "PointCloud", + "PointCloud2", + "PointField", + "Range", + "RegionOfInterest", + "RelativeHumidity", + "Temperature", + "TimeReference", +] +from ..._types import ( + sensor_msgs__msg__BatteryState as BatteryState, + sensor_msgs__msg__CameraInfo as CameraInfo, + sensor_msgs__msg__ChannelFloat32 as ChannelFloat32, + sensor_msgs__msg__CompressedImage as CompressedImage, + sensor_msgs__msg__FluidPressure as FluidPressure, + sensor_msgs__msg__Illuminance as Illuminance, + sensor_msgs__msg__Image as Image, + sensor_msgs__msg__Imu as Imu, + sensor_msgs__msg__JointState as JointState, + sensor_msgs__msg__Joy as Joy, + sensor_msgs__msg__JoyFeedback as JoyFeedback, + sensor_msgs__msg__JoyFeedbackArray as JoyFeedbackArray, + sensor_msgs__msg__LaserEcho as LaserEcho, + sensor_msgs__msg__LaserScan as LaserScan, + sensor_msgs__msg__MagneticField as MagneticField, + sensor_msgs__msg__MultiDOFJointState as MultiDOFJointState, + sensor_msgs__msg__MultiEchoLaserScan as MultiEchoLaserScan, + sensor_msgs__msg__NavSatFix as NavSatFix, + sensor_msgs__msg__NavSatStatus as NavSatStatus, + sensor_msgs__msg__PointCloud as PointCloud, + sensor_msgs__msg__PointCloud2 as PointCloud2, + sensor_msgs__msg__PointField as PointField, + sensor_msgs__msg__Range as Range, + sensor_msgs__msg__RegionOfInterest as RegionOfInterest, + sensor_msgs__msg__RelativeHumidity as RelativeHumidity, + sensor_msgs__msg__Temperature as Temperature, + sensor_msgs__msg__TimeReference as TimeReference, +) diff --git a/packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi index ac6f552be2b..67e96a08cca 100644 --- a/packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi @@ -1,5 +1,7 @@ -__all__ = ['MeshTriangle', 'Mesh', 'Plane', 'SolidPrimitive'] -from ..._types import shape_msgs__msg__MeshTriangle as MeshTriangle -from ..._types import shape_msgs__msg__Mesh as Mesh -from ..._types import shape_msgs__msg__Plane as Plane -from ..._types import shape_msgs__msg__SolidPrimitive as SolidPrimitive +__all__ = ["Mesh", "MeshTriangle", "Plane", "SolidPrimitive"] +from ..._types import ( + shape_msgs__msg__Mesh as Mesh, + shape_msgs__msg__MeshTriangle as MeshTriangle, + shape_msgs__msg__Plane as Plane, + shape_msgs__msg__SolidPrimitive as SolidPrimitive, +) diff --git a/packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi index 11eb8ad20cf..7d3c8665244 100644 --- a/packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi @@ -1,31 +1,64 @@ -__all__ = ['Header', 'Bool', 'Byte', 'MultiArrayDimension', 'MultiArrayLayout', 'ByteMultiArray', 'Char', 'ColorRGBA', 'Empty', 'Float32', 'Float32MultiArray', 'Float64', 'Float64MultiArray', 'Int16', 'Int16MultiArray', 'Int32', 'Int32MultiArray', 'Int64', 'Int64MultiArray', 'Int8', 'Int8MultiArray', 'String', 'UInt16', 'UInt16MultiArray', 'UInt32', 'UInt32MultiArray', 'UInt64', 'UInt64MultiArray', 'UInt8', 'UInt8MultiArray'] -from ..._types import std_msgs__msg__Header as Header -from ..._types import std_msgs__msg__Bool as Bool -from ..._types import std_msgs__msg__Byte as Byte -from ..._types import std_msgs__msg__MultiArrayDimension as MultiArrayDimension -from ..._types import std_msgs__msg__MultiArrayLayout as MultiArrayLayout -from ..._types import std_msgs__msg__ByteMultiArray as ByteMultiArray -from ..._types import std_msgs__msg__Char as Char -from ..._types import std_msgs__msg__ColorRGBA as ColorRGBA -from ..._types import std_msgs__msg__Empty as Empty -from ..._types import std_msgs__msg__Float32 as Float32 -from ..._types import std_msgs__msg__Float32MultiArray as Float32MultiArray -from ..._types import std_msgs__msg__Float64 as Float64 -from ..._types import std_msgs__msg__Float64MultiArray as Float64MultiArray -from ..._types import std_msgs__msg__Int16 as Int16 -from ..._types import std_msgs__msg__Int16MultiArray as Int16MultiArray -from ..._types import std_msgs__msg__Int32 as Int32 -from ..._types import std_msgs__msg__Int32MultiArray as Int32MultiArray -from ..._types import std_msgs__msg__Int64 as Int64 -from ..._types import std_msgs__msg__Int64MultiArray as Int64MultiArray -from ..._types import std_msgs__msg__Int8 as Int8 -from ..._types import std_msgs__msg__Int8MultiArray as Int8MultiArray -from ..._types import std_msgs__msg__String as String -from ..._types import std_msgs__msg__UInt16 as UInt16 -from ..._types import std_msgs__msg__UInt16MultiArray as UInt16MultiArray -from ..._types import std_msgs__msg__UInt32 as UInt32 -from ..._types import std_msgs__msg__UInt32MultiArray as UInt32MultiArray -from ..._types import std_msgs__msg__UInt64 as UInt64 -from ..._types import std_msgs__msg__UInt64MultiArray as UInt64MultiArray -from ..._types import std_msgs__msg__UInt8 as UInt8 -from ..._types import std_msgs__msg__UInt8MultiArray as UInt8MultiArray +__all__ = [ + "Bool", + "Byte", + "ByteMultiArray", + "Char", + "ColorRGBA", + "Empty", + "Float32", + "Float32MultiArray", + "Float64", + "Float64MultiArray", + "Header", + "Int8", + "Int8MultiArray", + "Int16", + "Int16MultiArray", + "Int32", + "Int32MultiArray", + "Int64", + "Int64MultiArray", + "MultiArrayDimension", + "MultiArrayLayout", + "String", + "UInt8", + "UInt8MultiArray", + "UInt16", + "UInt16MultiArray", + "UInt32", + "UInt32MultiArray", + "UInt64", + "UInt64MultiArray", +] +from ..._types import ( + std_msgs__msg__Bool as Bool, + std_msgs__msg__Byte as Byte, + std_msgs__msg__ByteMultiArray as ByteMultiArray, + std_msgs__msg__Char as Char, + std_msgs__msg__ColorRGBA as ColorRGBA, + std_msgs__msg__Empty as Empty, + std_msgs__msg__Float32 as Float32, + std_msgs__msg__Float32MultiArray as Float32MultiArray, + std_msgs__msg__Float64 as Float64, + std_msgs__msg__Float64MultiArray as Float64MultiArray, + std_msgs__msg__Header as Header, + std_msgs__msg__Int8 as Int8, + std_msgs__msg__Int8MultiArray as Int8MultiArray, + std_msgs__msg__Int16 as Int16, + std_msgs__msg__Int16MultiArray as Int16MultiArray, + std_msgs__msg__Int32 as Int32, + std_msgs__msg__Int32MultiArray as Int32MultiArray, + std_msgs__msg__Int64 as Int64, + std_msgs__msg__Int64MultiArray as Int64MultiArray, + std_msgs__msg__MultiArrayDimension as MultiArrayDimension, + std_msgs__msg__MultiArrayLayout as MultiArrayLayout, + std_msgs__msg__String as String, + std_msgs__msg__UInt8 as UInt8, + std_msgs__msg__UInt8MultiArray as UInt8MultiArray, + std_msgs__msg__UInt16 as UInt16, + std_msgs__msg__UInt16MultiArray as UInt16MultiArray, + std_msgs__msg__UInt32 as UInt32, + std_msgs__msg__UInt32MultiArray as UInt32MultiArray, + std_msgs__msg__UInt64 as UInt64, + std_msgs__msg__UInt64MultiArray as UInt64MultiArray, +) diff --git a/packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi index 39fa6b49941..4d4ff1cbc49 100644 --- a/packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi @@ -1,3 +1,2 @@ -__all__ = ['TF2Error', 'TFMessage'] -from ..._types import tf2_msgs__msg__TF2Error as TF2Error -from ..._types import tf2_msgs__msg__TFMessage as TFMessage +__all__ = ["TF2Error", "TFMessage"] +from ..._types import tf2_msgs__msg__TF2Error as TF2Error, tf2_msgs__msg__TFMessage as TFMessage diff --git a/packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi index 7a0c966c2be..14bcc8808b1 100644 --- a/packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi @@ -1,5 +1,12 @@ -__all__ = ['JointTrajectoryPoint', 'JointTrajectory', 'MultiDOFJointTrajectoryPoint', 'MultiDOFJointTrajectory'] -from ..._types import trajectory_msgs__msg__JointTrajectoryPoint as JointTrajectoryPoint -from ..._types import trajectory_msgs__msg__JointTrajectory as JointTrajectory -from ..._types import trajectory_msgs__msg__MultiDOFJointTrajectoryPoint as MultiDOFJointTrajectoryPoint -from ..._types import trajectory_msgs__msg__MultiDOFJointTrajectory as MultiDOFJointTrajectory +__all__ = [ + "JointTrajectory", + "JointTrajectoryPoint", + "MultiDOFJointTrajectory", + "MultiDOFJointTrajectoryPoint", +] +from ..._types import ( + trajectory_msgs__msg__JointTrajectory as JointTrajectory, + trajectory_msgs__msg__JointTrajectoryPoint as JointTrajectoryPoint, + trajectory_msgs__msg__MultiDOFJointTrajectory as MultiDOFJointTrajectory, + trajectory_msgs__msg__MultiDOFJointTrajectoryPoint as MultiDOFJointTrajectoryPoint, +) diff --git a/packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi index f4f3271f588..b33ed8f8f1c 100644 --- a/packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi @@ -1,17 +1,36 @@ -__all__ = ['Point2D', 'Pose2D', 'BoundingBox2D', 'BoundingBox3D', 'BoundingBox2DArray', 'BoundingBox3DArray', 'ObjectHypothesis', 'Classification', 'ObjectHypothesisWithPose', 'Detection2D', 'Detection2DArray', 'Detection3D', 'Detection3DArray', 'VisionClass', 'LabelInfo', 'VisionInfo'] -from ..._types import vision_msgs__msg__Point2D as Point2D -from ..._types import vision_msgs__msg__Pose2D as Pose2D -from ..._types import vision_msgs__msg__BoundingBox2D as BoundingBox2D -from ..._types import vision_msgs__msg__BoundingBox3D as BoundingBox3D -from ..._types import vision_msgs__msg__BoundingBox2DArray as BoundingBox2DArray -from ..._types import vision_msgs__msg__BoundingBox3DArray as BoundingBox3DArray -from ..._types import vision_msgs__msg__ObjectHypothesis as ObjectHypothesis -from ..._types import vision_msgs__msg__Classification as Classification -from ..._types import vision_msgs__msg__ObjectHypothesisWithPose as ObjectHypothesisWithPose -from ..._types import vision_msgs__msg__Detection2D as Detection2D -from ..._types import vision_msgs__msg__Detection2DArray as Detection2DArray -from ..._types import vision_msgs__msg__Detection3D as Detection3D -from ..._types import vision_msgs__msg__Detection3DArray as Detection3DArray -from ..._types import vision_msgs__msg__VisionClass as VisionClass -from ..._types import vision_msgs__msg__LabelInfo as LabelInfo -from ..._types import vision_msgs__msg__VisionInfo as VisionInfo +__all__ = [ + "BoundingBox2D", + "BoundingBox2DArray", + "BoundingBox3D", + "BoundingBox3DArray", + "Classification", + "Detection2D", + "Detection2DArray", + "Detection3D", + "Detection3DArray", + "LabelInfo", + "ObjectHypothesis", + "ObjectHypothesisWithPose", + "Point2D", + "Pose2D", + "VisionClass", + "VisionInfo", +] +from ..._types import ( + vision_msgs__msg__BoundingBox2D as BoundingBox2D, + vision_msgs__msg__BoundingBox2DArray as BoundingBox2DArray, + vision_msgs__msg__BoundingBox3D as BoundingBox3D, + vision_msgs__msg__BoundingBox3DArray as BoundingBox3DArray, + vision_msgs__msg__Classification as Classification, + vision_msgs__msg__Detection2D as Detection2D, + vision_msgs__msg__Detection2DArray as Detection2DArray, + vision_msgs__msg__Detection3D as Detection3D, + vision_msgs__msg__Detection3DArray as Detection3DArray, + vision_msgs__msg__LabelInfo as LabelInfo, + vision_msgs__msg__ObjectHypothesis as ObjectHypothesis, + vision_msgs__msg__ObjectHypothesisWithPose as ObjectHypothesisWithPose, + vision_msgs__msg__Point2D as Point2D, + vision_msgs__msg__Pose2D as Pose2D, + vision_msgs__msg__VisionClass as VisionClass, + vision_msgs__msg__VisionInfo as VisionInfo, +) diff --git a/packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi index c36ca599c65..11bb9bcc2c1 100644 --- a/packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi +++ b/packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi @@ -1,13 +1,28 @@ -__all__ = ['ImageMarker', 'MeshFile', 'UVCoordinate', 'Marker', 'InteractiveMarkerControl', 'MenuEntry', 'InteractiveMarker', 'InteractiveMarkerFeedback', 'InteractiveMarkerInit', 'InteractiveMarkerPose', 'InteractiveMarkerUpdate', 'MarkerArray'] -from ..._types import visualization_msgs__msg__ImageMarker as ImageMarker -from ..._types import visualization_msgs__msg__MeshFile as MeshFile -from ..._types import visualization_msgs__msg__UVCoordinate as UVCoordinate -from ..._types import visualization_msgs__msg__Marker as Marker -from ..._types import visualization_msgs__msg__InteractiveMarkerControl as InteractiveMarkerControl -from ..._types import visualization_msgs__msg__MenuEntry as MenuEntry -from ..._types import visualization_msgs__msg__InteractiveMarker as InteractiveMarker -from ..._types import visualization_msgs__msg__InteractiveMarkerFeedback as InteractiveMarkerFeedback -from ..._types import visualization_msgs__msg__InteractiveMarkerInit as InteractiveMarkerInit -from ..._types import visualization_msgs__msg__InteractiveMarkerPose as InteractiveMarkerPose -from ..._types import visualization_msgs__msg__InteractiveMarkerUpdate as InteractiveMarkerUpdate -from ..._types import visualization_msgs__msg__MarkerArray as MarkerArray +__all__ = [ + "ImageMarker", + "InteractiveMarker", + "InteractiveMarkerControl", + "InteractiveMarkerFeedback", + "InteractiveMarkerInit", + "InteractiveMarkerPose", + "InteractiveMarkerUpdate", + "Marker", + "MarkerArray", + "MenuEntry", + "MeshFile", + "UVCoordinate", +] +from ..._types import ( + visualization_msgs__msg__ImageMarker as ImageMarker, + visualization_msgs__msg__InteractiveMarker as InteractiveMarker, + visualization_msgs__msg__InteractiveMarkerControl as InteractiveMarkerControl, + visualization_msgs__msg__InteractiveMarkerFeedback as InteractiveMarkerFeedback, + visualization_msgs__msg__InteractiveMarkerInit as InteractiveMarkerInit, + visualization_msgs__msg__InteractiveMarkerPose as InteractiveMarkerPose, + visualization_msgs__msg__InteractiveMarkerUpdate as InteractiveMarkerUpdate, + visualization_msgs__msg__Marker as Marker, + visualization_msgs__msg__MarkerArray as MarkerArray, + visualization_msgs__msg__MenuEntry as MenuEntry, + visualization_msgs__msg__MeshFile as MeshFile, + visualization_msgs__msg__UVCoordinate as UVCoordinate, +) diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json index 70536616bd2..a82249ec698 100644 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json +++ b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json @@ -1 +1,14 @@ -["builtin_interfaces", "std_msgs", "geometry_msgs", "vision_msgs", "dimos_msgs", "foxglove_msgs", "nav_msgs", "sensor_msgs", "shape_msgs", "tf2_msgs", "trajectory_msgs", "visualization_msgs"] +[ + "builtin_interfaces", + "std_msgs", + "geometry_msgs", + "vision_msgs", + "dimos_msgs", + "foxglove_msgs", + "nav_msgs", + "sensor_msgs", + "shape_msgs", + "tf2_msgs", + "trajectory_msgs", + "visualization_msgs" +] diff --git a/scripts/test_external_native_messages.sh b/scripts/test_external_native_messages.sh index e033384ab7d..d66ea16137d 100644 --- a/scripts/test_external_native_messages.sh +++ b/scripts/test_external_native_messages.sh @@ -1,30 +1,13 @@ #!/usr/bin/env bash set -euo pipefail cd "$(dirname "$0")/.." -# Run test_message_packages.sh first: it adds application_note locally and installs packages. -application="$PWD/build/message-codegen/external-app" -native_demo="$PWD/build/message-codegen/external-native" -mkdir -p "$native_demo/rust/src" "$native_demo/evidence" -cp examples/message-codegen/external-native/relay.rs "$native_demo/rust/src/main.rs" -cat > "$native_demo/rust/Cargo.toml" < Date: Fri, 9 Oct 2026 11:54:35 -0700 Subject: [PATCH 06/11] test: constrain native CDR expected failures and sync package metadata --- docs/development/message-limitations.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/development/message-limitations.md b/docs/development/message-limitations.md index 09888949b42..4597fbdd1b8 100644 --- a/docs/development/message-limitations.md +++ b/docs/development/message-limitations.md @@ -19,6 +19,8 @@ unintended values. The assertions remain in `dimos/message_codegen/test_python_source.py`. Only the exact failing parameters carry `xfail(strict=True)` with these identifiers. An unexpected pass fails the check and requires reviewing the pin and limitation. +Wire-rejection cases accept only the missing-exception assertion failure; unsupported +schema cases accept only `NotImplementedError`. Unrelated exceptions fail normally. Run the original assertions without expected-failure handling using: ```sh From 447fe4bbbdf7ad715364a632b84a257b5a6ca260 Mon Sep 17 00:00:00 2001 From: cc Date: Fri, 9 Oct 2026 12:07:22 -0700 Subject: [PATCH 07/11] build: smoke-test native source message wheels with matching backend --- .github/scripts/message_wheel_smoke.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/scripts/message_wheel_smoke.py b/.github/scripts/message_wheel_smoke.py index 2b8199e3ac7..4caca8ca5e4 100644 --- a/.github/scripts/message_wheel_smoke.py +++ b/.github/scripts/message_wheel_smoke.py @@ -20,14 +20,18 @@ import dimos_generated as messages from dimos_generated_schemas.provider import package_root +from dimos_message_build.registry import decode, encode assert messages.__dimos_version__ == "0.1.0" -header = messages.std_msgs.msg.Header() -assert type(header).decode(header.encode()).encode() == header.encode() +header = messages.std_msgs.msg.Header( + stamp=messages.builtin_interfaces.msg.Time(sec=17, nanosec=23), frame_id="wheel" +) +assert decode(encode(header), type(header)) == header root = Path(package_root()) metadata = json.loads((root / "message-package.json").read_text()) assert metadata["shared"] assert "std_msgs/msg/Header" in metadata["owned"] assert (root / "schemas/std_msgs/msg/Header.msg").is_file() -assert (root / "lib/cmake/dimos_generated/dimos_generatedConfig.cmake").is_file() +assert (root / "cpp/CMakeLists.txt").is_file() +assert (root / "cpp/std_msgs/msg/Header.msg").is_file() assert (root / "rust/Cargo.toml").is_file() From d05563808229840b2ba37b0ece40e68c79d8655d Mon Sep 17 00:00:00 2001 From: cc Date: Fri, 9 Oct 2026 12:30:18 -0700 Subject: [PATCH 08/11] fix: repair native CDR consumers and CI build prerequisites --- dimos/message_codegen/native_sources.json | 36 ++++++++++++++----- docs/development/message-limitations.md | 2 +- .../message-codegen/demo_habitat_native.py | 2 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/dimos/message_codegen/native_sources.json b/dimos/message_codegen/native_sources.json index 5f8f498f348..1aaf4afc6c4 100644 --- a/dimos/message_codegen/native_sources.json +++ b/dimos/message_codegen/native_sources.json @@ -2,39 +2,57 @@ "repositories": { "ament_package": { "url": "https://github.com/ament/ament_package.git", - "revision": "ee3c5eda4fbc4df2c7a135d0ac1385e4a53fa0ee" + "revision": "ee3c5eda4fbc4df2c7a135d0ac1385e4a53fa0ee", + "archive_url": "https://codeload.github.com/ament/ament_package/tar.gz/ee3c5eda4fbc4df2c7a135d0ac1385e4a53fa0ee", + "archive_sha256": "19dd626283a9f5dcfed5039ecd0ab149daa5e658a970bf607ed5bd053d54e629" }, "ament_cmake": { "url": "https://github.com/ament/ament_cmake.git", - "revision": "5741cff5b9f83253bf3521bd8f44108fde3504ad" + "revision": "5741cff5b9f83253bf3521bd8f44108fde3504ad", + "archive_url": "https://codeload.github.com/ament/ament_cmake/tar.gz/5741cff5b9f83253bf3521bd8f44108fde3504ad", + "archive_sha256": "7172066ce00a4521205b74f70bfeb975345789ce1a69901e7a8da9dc45e22fcb" }, "ament_cmake_ros": { "url": "https://github.com/ros2/ament_cmake_ros.git", - "revision": "5b77a227b940a25be5224d78d37591c8baccd756" + "revision": "5b77a227b940a25be5224d78d37591c8baccd756", + "archive_url": "https://codeload.github.com/ros2/ament_cmake_ros/tar.gz/5b77a227b940a25be5224d78d37591c8baccd756", + "archive_sha256": "d063e9cc5c68d12d33597f0ac5bb9568710848ad08741b019a5436eb52c43988" }, "rcutils": { "url": "https://github.com/ros2/rcutils.git", - "revision": "26413034bab69688475f230ea7723e534ec3f8cd" + "revision": "26413034bab69688475f230ea7723e534ec3f8cd", + "archive_url": "https://codeload.github.com/ros2/rcutils/tar.gz/26413034bab69688475f230ea7723e534ec3f8cd", + "archive_sha256": "e71a0fd5fe8c42ae2f92ec1076d2fdf3e753034f9200fa7a4f14bc93f90e22b2" }, "rmw": { "url": "https://github.com/ros2/rmw.git", - "revision": "8cb94a87cf3f4049abe2d563af893517bf336930" + "revision": "8cb94a87cf3f4049abe2d563af893517bf336930", + "archive_url": "https://codeload.github.com/ros2/rmw/tar.gz/8cb94a87cf3f4049abe2d563af893517bf336930", + "archive_sha256": "d0d43d3f19b125b1abc1e26c412a674cca4d20ab88bd9ba5496cf5a336d25f8e" }, "rosidl_dynamic_typesupport": { "url": "https://github.com/ros2/rosidl_dynamic_typesupport.git", - "revision": "cb8c54d12c678daa70410bb0626ed8626f561e45" + "revision": "cb8c54d12c678daa70410bb0626ed8626f561e45", + "archive_url": "https://codeload.github.com/ros2/rosidl_dynamic_typesupport/tar.gz/cb8c54d12c678daa70410bb0626ed8626f561e45", + "archive_sha256": "c9d30f03eaad34657ce94ffe95faec445d46dccdb2372d66d06d382abc504a76" }, "ament_index": { "url": "https://github.com/ament/ament_index.git", - "revision": "2ccdcb8fd19a364fc793273b5793459207a440b9" + "revision": "2ccdcb8fd19a364fc793273b5793459207a440b9", + "archive_url": "https://codeload.github.com/ament/ament_index/tar.gz/2ccdcb8fd19a364fc793273b5793459207a440b9", + "archive_sha256": "54ca269d31fc6b8f650ce262f5781f8805cc7c8750467f8dfaf6a16cbd9f8dbd" }, "rosidl": { "url": "https://github.com/ros2/rosidl.git", - "revision": "85fa592b698b0f665e3120f48fac0d35e2f7d8a4" + "revision": "85fa592b698b0f665e3120f48fac0d35e2f7d8a4", + "archive_url": "https://codeload.github.com/ros2/rosidl/tar.gz/85fa592b698b0f665e3120f48fac0d35e2f7d8a4", + "archive_sha256": "ba5369bca27297f606bf3396a9e066140d07ce754d8659159148102b089e9510" }, "rosidl_typesupport_fastrtps": { "url": "https://github.com/ros2/rosidl_typesupport_fastrtps.git", - "revision": "b883555055cce17982a22172a42ef557ef40bac5" + "revision": "b883555055cce17982a22172a42ef557ef40bac5", + "archive_url": "https://codeload.github.com/ros2/rosidl_typesupport_fastrtps/tar.gz/b883555055cce17982a22172a42ef557ef40bac5", + "archive_sha256": "4bb21020ab28a249890339301efb8e200af8330a6dee6e13ecd9388981cba83d" } }, "packages": [ diff --git a/docs/development/message-limitations.md b/docs/development/message-limitations.md index 4597fbdd1b8..a339456cace 100644 --- a/docs/development/message-limitations.md +++ b/docs/development/message-limitations.md @@ -23,7 +23,7 @@ Wire-rejection cases accept only the missing-exception assertion failure; unsupp schema cases accept only `NotImplementedError`. Unrelated exceptions fail normally. Run the original assertions without expected-failure handling using: -```sh +```sh expected-error python -m pytest --noconftest -o addopts='' --runxfail \ dimos/message_codegen/test_python_source.py ``` diff --git a/examples/message-codegen/demo_habitat_native.py b/examples/message-codegen/demo_habitat_native.py index 5bf92641d03..02a81c6d126 100644 --- a/examples/message-codegen/demo_habitat_native.py +++ b/examples/message-codegen/demo_habitat_native.py @@ -77,7 +77,7 @@ ), } for name, (message_type, payload) in payloads.items(): - value = message_type.decode(payload) + value = cdr_decode(payload, message_type) header = value.transforms[0].header if name == "tf" else value.header assert header.stamp.sec == 12 and header.stamp.nanosec == 250000000 (output / (name + ".cdr")).write_bytes(payload) From b654a4bdf9085e7df388409c05dfe6f67330f0fd Mon Sep 17 00:00:00 2001 From: cc Date: Fri, 9 Oct 2026 12:39:53 -0700 Subject: [PATCH 09/11] fix: preserve the shared native source lock contract --- dimos/message_codegen/native_sources.json | 36 ++++++----------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/dimos/message_codegen/native_sources.json b/dimos/message_codegen/native_sources.json index 1aaf4afc6c4..5f8f498f348 100644 --- a/dimos/message_codegen/native_sources.json +++ b/dimos/message_codegen/native_sources.json @@ -2,57 +2,39 @@ "repositories": { "ament_package": { "url": "https://github.com/ament/ament_package.git", - "revision": "ee3c5eda4fbc4df2c7a135d0ac1385e4a53fa0ee", - "archive_url": "https://codeload.github.com/ament/ament_package/tar.gz/ee3c5eda4fbc4df2c7a135d0ac1385e4a53fa0ee", - "archive_sha256": "19dd626283a9f5dcfed5039ecd0ab149daa5e658a970bf607ed5bd053d54e629" + "revision": "ee3c5eda4fbc4df2c7a135d0ac1385e4a53fa0ee" }, "ament_cmake": { "url": "https://github.com/ament/ament_cmake.git", - "revision": "5741cff5b9f83253bf3521bd8f44108fde3504ad", - "archive_url": "https://codeload.github.com/ament/ament_cmake/tar.gz/5741cff5b9f83253bf3521bd8f44108fde3504ad", - "archive_sha256": "7172066ce00a4521205b74f70bfeb975345789ce1a69901e7a8da9dc45e22fcb" + "revision": "5741cff5b9f83253bf3521bd8f44108fde3504ad" }, "ament_cmake_ros": { "url": "https://github.com/ros2/ament_cmake_ros.git", - "revision": "5b77a227b940a25be5224d78d37591c8baccd756", - "archive_url": "https://codeload.github.com/ros2/ament_cmake_ros/tar.gz/5b77a227b940a25be5224d78d37591c8baccd756", - "archive_sha256": "d063e9cc5c68d12d33597f0ac5bb9568710848ad08741b019a5436eb52c43988" + "revision": "5b77a227b940a25be5224d78d37591c8baccd756" }, "rcutils": { "url": "https://github.com/ros2/rcutils.git", - "revision": "26413034bab69688475f230ea7723e534ec3f8cd", - "archive_url": "https://codeload.github.com/ros2/rcutils/tar.gz/26413034bab69688475f230ea7723e534ec3f8cd", - "archive_sha256": "e71a0fd5fe8c42ae2f92ec1076d2fdf3e753034f9200fa7a4f14bc93f90e22b2" + "revision": "26413034bab69688475f230ea7723e534ec3f8cd" }, "rmw": { "url": "https://github.com/ros2/rmw.git", - "revision": "8cb94a87cf3f4049abe2d563af893517bf336930", - "archive_url": "https://codeload.github.com/ros2/rmw/tar.gz/8cb94a87cf3f4049abe2d563af893517bf336930", - "archive_sha256": "d0d43d3f19b125b1abc1e26c412a674cca4d20ab88bd9ba5496cf5a336d25f8e" + "revision": "8cb94a87cf3f4049abe2d563af893517bf336930" }, "rosidl_dynamic_typesupport": { "url": "https://github.com/ros2/rosidl_dynamic_typesupport.git", - "revision": "cb8c54d12c678daa70410bb0626ed8626f561e45", - "archive_url": "https://codeload.github.com/ros2/rosidl_dynamic_typesupport/tar.gz/cb8c54d12c678daa70410bb0626ed8626f561e45", - "archive_sha256": "c9d30f03eaad34657ce94ffe95faec445d46dccdb2372d66d06d382abc504a76" + "revision": "cb8c54d12c678daa70410bb0626ed8626f561e45" }, "ament_index": { "url": "https://github.com/ament/ament_index.git", - "revision": "2ccdcb8fd19a364fc793273b5793459207a440b9", - "archive_url": "https://codeload.github.com/ament/ament_index/tar.gz/2ccdcb8fd19a364fc793273b5793459207a440b9", - "archive_sha256": "54ca269d31fc6b8f650ce262f5781f8805cc7c8750467f8dfaf6a16cbd9f8dbd" + "revision": "2ccdcb8fd19a364fc793273b5793459207a440b9" }, "rosidl": { "url": "https://github.com/ros2/rosidl.git", - "revision": "85fa592b698b0f665e3120f48fac0d35e2f7d8a4", - "archive_url": "https://codeload.github.com/ros2/rosidl/tar.gz/85fa592b698b0f665e3120f48fac0d35e2f7d8a4", - "archive_sha256": "ba5369bca27297f606bf3396a9e066140d07ce754d8659159148102b089e9510" + "revision": "85fa592b698b0f665e3120f48fac0d35e2f7d8a4" }, "rosidl_typesupport_fastrtps": { "url": "https://github.com/ros2/rosidl_typesupport_fastrtps.git", - "revision": "b883555055cce17982a22172a42ef557ef40bac5", - "archive_url": "https://codeload.github.com/ros2/rosidl_typesupport_fastrtps/tar.gz/b883555055cce17982a22172a42ef557ef40bac5", - "archive_sha256": "4bb21020ab28a249890339301efb8e200af8330a6dee6e13ecd9388981cba83d" + "revision": "b883555055cce17982a22172a42ef557ef40bac5" } }, "packages": [ From 5ec4c99455c86a57922fb39945aa1445435fd460 Mon Sep 17 00:00:00 2001 From: cc Date: Fri, 9 Oct 2026 13:07:48 -0700 Subject: [PATCH 10/11] test(messages): migrate remaining native codec assertions and examples --- dimos/mapping/voxels/test_grid.py | 1 + .../dannav/holonomic_tc/test_dan_holonomic_tc.py | 1 + dimos/navigation/movement_manager/test_movement_manager.py | 1 + examples/message-codegen/demo_aruco_detection.py | 6 +++--- examples/message-codegen/demo_bbox_navigation.py | 2 +- examples/message-codegen/demo_blueprint.py | 4 ++-- examples/message-codegen/demo_blueprint_recording.py | 1 + examples/message-codegen/demo_camera_bridge.py | 3 ++- examples/message-codegen/demo_camera_mux_cdr.py | 2 +- examples/message-codegen/demo_command_center.py | 2 +- examples/message-codegen/demo_coordinator_joints.py | 4 ++-- examples/message-codegen/demo_detection_bbox.py | 4 ++-- examples/message-codegen/demo_detection_projection.py | 2 +- examples/message-codegen/demo_export_detection_fixture.py | 4 ++-- examples/message-codegen/demo_g1_messages.py | 3 ++- examples/message-codegen/demo_galaxea_messages.py | 3 ++- examples/message-codegen/demo_go2_command_cdr.py | 4 ++-- examples/message-codegen/demo_grasp_proposals.py | 2 +- examples/message-codegen/demo_holonomic_path.py | 2 +- examples/message-codegen/demo_keyboard_cdr.py | 6 +++--- examples/message-codegen/demo_marker_messages.py | 4 ++-- examples/message-codegen/demo_mls_transformer.py | 6 +++--- examples/message-codegen/demo_movement.py | 4 ++-- examples/message-codegen/demo_native.py | 2 +- examples/message-codegen/demo_navigation_skill.py | 2 +- examples/message-codegen/demo_odometry_history.py | 6 +++--- examples/message-codegen/demo_phone_cdr.py | 2 +- examples/message-codegen/demo_planning_backends.py | 2 +- examples/message-codegen/demo_pubsub.py | 7 ++++--- examples/message-codegen/demo_self_filter.py | 2 +- examples/message-codegen/demo_storage_replay.py | 1 + examples/message-codegen/demo_video_stats.py | 2 +- examples/message-codegen/demo_viewer_controls.py | 2 +- examples/message-codegen/demo_visual_servo.py | 2 +- examples/message-codegen/demo_vl_images.py | 4 ++-- 35 files changed, 57 insertions(+), 48 deletions(-) diff --git a/dimos/mapping/voxels/test_grid.py b/dimos/mapping/voxels/test_grid.py index 8ad8731f056..14b95205a08 100644 --- a/dimos/mapping/voxels/test_grid.py +++ b/dimos/mapping/voxels/test_grid.py @@ -15,6 +15,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/navigation/experimental/dannav/holonomic_tc/test_dan_holonomic_tc.py b/dimos/navigation/experimental/dannav/holonomic_tc/test_dan_holonomic_tc.py index 31b600bb71d..e22f80538c2 100644 --- a/dimos/navigation/experimental/dannav/holonomic_tc/test_dan_holonomic_tc.py +++ b/dimos/navigation/experimental/dannav/holonomic_tc/test_dan_holonomic_tc.py @@ -28,6 +28,7 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist from dimos_generated.nav_msgs.msg import Path from dimos_generated.std_msgs.msg import Bool, Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.core.stream import Stream, Transport diff --git a/dimos/navigation/movement_manager/test_movement_manager.py b/dimos/navigation/movement_manager/test_movement_manager.py index 497e77b0500..09170aadf01 100644 --- a/dimos/navigation/movement_manager/test_movement_manager.py +++ b/dimos/navigation/movement_manager/test_movement_manager.py @@ -21,6 +21,7 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Point, PointStamped, Twist, Vector3 +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.constants import DEFAULT_THREAD_JOIN_TIMEOUT diff --git a/examples/message-codegen/demo_aruco_detection.py b/examples/message-codegen/demo_aruco_detection.py index 22bb6aa2e9a..d326114e5a7 100644 --- a/examples/message-codegen/demo_aruco_detection.py +++ b/examples/message-codegen/demo_aruco_detection.py @@ -66,7 +66,7 @@ def main() -> None: aruco_dictionary="DICT_4X4_50", ) assert len(found) == 1 - wire = cdr_decode(found[0].to_detection3d_msg().encode(), Detection3D) + wire = cdr_decode(cdr_encode(found[0].to_detection3d_msg()), Detection3D) assert wire.id == "7" assert wire.results[0].hypothesis.class_id == "DICT_4X4_50:7" assert wire.header.stamp == header.stamp @@ -83,14 +83,14 @@ def main() -> None: emit_empty_frames=True, ) arrays = list(MarkersPerFrame()(detector(iter([observation])))) - decoded_array = cdr_decode(arrays[0].data.encode(), Detection3DArray) + decoded_array = cdr_decode(cdr_encode(arrays[0].data), Detection3DArray) assert len(decoded_array.detections) == 1 assert decoded_array.header.stamp == image.header.stamp print("Memory stream: image → marker observation → generated CDR array") publisher = MarkerTfModule() transforms: list[TFMessage] = [] unsubscribe = publisher.tf.subscribe( - lambda msg: transforms.append(cdr_decode(msg.encode(), TFMessage)) + lambda msg: transforms.append(cdr_decode(cdr_encode(msg), TFMessage)) ) try: publisher._process_detections(decoded_array) diff --git a/examples/message-codegen/demo_bbox_navigation.py b/examples/message-codegen/demo_bbox_navigation.py index 249c64e9948..b2fab33cf34 100644 --- a/examples/message-codegen/demo_bbox_navigation.py +++ b/examples/message-codegen/demo_bbox_navigation.py @@ -43,7 +43,7 @@ def main() -> None: received = Event() unsubscribe = module.goal_request.subscribe( lambda value: ( - goals.append(cdr_decode(value.encode(), PoseStamped)), + goals.append(cdr_decode(cdr_encode(value), PoseStamped)), received.set(), ) ) diff --git a/examples/message-codegen/demo_blueprint.py b/examples/message-codegen/demo_blueprint.py index 8b9cd373a6f..0df46e565f6 100644 --- a/examples/message-codegen/demo_blueprint.py +++ b/examples/message-codegen/demo_blueprint.py @@ -130,9 +130,9 @@ def exchange(self, sample: int) -> str: start=Point(x=sample, y=0.0, z=0.0), end=Point(y=2, x=0.0, z=0.0), weight=sample + 2 ) ] - if self._lines.encode() != cdr_encode(expected): + if cdr_encode(self._lines) != cdr_encode(expected): raise ValueError("Native custom message reply differs from the expected edits") - if self._image.encode() != cdr_encode(image): + if cdr_encode(self._image) != cdr_encode(image): raise ValueError("Native image reply changed pixels or metadata") return ( f"sample {sample}: Python weight={sample} → C++ {sample + 1} → Rust {sample + 2}; " diff --git a/examples/message-codegen/demo_blueprint_recording.py b/examples/message-codegen/demo_blueprint_recording.py index 82986eb6dd2..8d05adfb276 100644 --- a/examples/message-codegen/demo_blueprint_recording.py +++ b/examples/message-codegen/demo_blueprint_recording.py @@ -28,6 +28,7 @@ from dimos_generated.dimos_msgs.msg import LineSegments3D from dimos_generated.geometry_msgs.msg import PoseStamped from dimos_generated.sensor_msgs.msg import Image +from dimos_message_build.registry import encode as cdr_encode from mcap.reader import make_reader import numpy as np from rosbags.typesys import Stores, get_types_from_msg, get_typestore diff --git a/examples/message-codegen/demo_camera_bridge.py b/examples/message-codegen/demo_camera_bridge.py index dd4bc5af19a..973d3fd4af6 100644 --- a/examples/message-codegen/demo_camera_bridge.py +++ b/examples/message-codegen/demo_camera_bridge.py @@ -28,6 +28,7 @@ ObjectHypothesis, ObjectHypothesisWithPose, ) +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import rerun as rr @@ -118,7 +119,7 @@ def main() -> None: try: for name, value in messages: bridge._on_message( - type(value).decode(value.encode()), SimpleNamespace(name="/camera/" + name) + cdr_decode(cdr_encode(value), type(value)), SimpleNamespace(name="/camera/" + name) ) print(f"CDR {type(value).__name__} → world/camera/{name}") finally: diff --git a/examples/message-codegen/demo_camera_mux_cdr.py b/examples/message-codegen/demo_camera_mux_cdr.py index 2cb52fcc6c3..e97679179da 100644 --- a/examples/message-codegen/demo_camera_mux_cdr.py +++ b/examples/message-codegen/demo_camera_mux_cdr.py @@ -48,7 +48,7 @@ def main() -> None: header=Header(stamp=time_from_nanoseconds(stamp_ns + index), frame_id=camera), ) mux._on_cam(camera, cdr_decode(cdr_encode(image), Image)) - output = cdr_decode(mux.mux_image.publish.call_args.args[0].encode(), Image) + output = cdr_decode(cdr_encode(mux.mux_image.publish.call_args.args[0]), Image) assert output.width == 100 and output.height == 36 assert to_nanoseconds(output.header.stamp) == stamp_ns + 1 assert output.header.frame_id == "camera_mux" diff --git a/examples/message-codegen/demo_command_center.py b/examples/message-codegen/demo_command_center.py index 609167c72a9..284aab0203d 100644 --- a/examples/message-codegen/demo_command_center.py +++ b/examples/message-codegen/demo_command_center.py @@ -31,7 +31,7 @@ def main() -> None: module = WebsocketVisModule() goals: list[PoseStamped] = [] unsubscribe = module.goal_request.subscribe( - lambda value: goals.append(cdr_decode(value.encode(), PoseStamped)) + lambda value: goals.append(cdr_decode(cdr_encode(value), PoseStamped)) ) try: module._create_server() diff --git a/examples/message-codegen/demo_coordinator_joints.py b/examples/message-codegen/demo_coordinator_joints.py index c21fbf2fa19..fe5eb508291 100644 --- a/examples/message-codegen/demo_coordinator_joints.py +++ b/examples/message-codegen/demo_coordinator_joints.py @@ -18,7 +18,7 @@ import threading from dimos_generated.sensor_msgs.msg import JointState -from dimos_message_build.registry import decode as cdr_decode +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.control.components import HardwareComponent, HardwareType from dimos.control.coordinator import ControlCoordinator @@ -72,7 +72,7 @@ def receive(port: str, message: JointState) -> None: assert list(complete["right_arm_joints"].position) == [0.3, 0.4] assert len(complete["coordinator_joint_state"].position) == 4 for port, message in complete.items(): - assert cdr_decode(message.encode(), JointState) == message + assert cdr_decode(cdr_encode(message), JointState) == message print( f"{port}: frame={message.header.frame_id}, names={list(message.name)}, q={list(message.position)}, stamp={to_nanoseconds(message.header.stamp)}" ) diff --git a/examples/message-codegen/demo_detection_bbox.py b/examples/message-codegen/demo_detection_bbox.py index 70ba3abf48d..74f1df382fa 100644 --- a/examples/message-codegen/demo_detection_bbox.py +++ b/examples/message-codegen/demo_detection_bbox.py @@ -20,7 +20,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection2DArray -from dimos_message_build.registry import decode as cdr_decode +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.image import image_from_array, image_view @@ -46,7 +46,7 @@ def main() -> None: image=source, ) collection = ImageDetections2D(image=source, detections=[detection]) - array = cdr_decode(collection.to_ros_detection2d_array().encode(), Detection2DArray) + array = cdr_decode(cdr_encode(collection.to_ros_detection2d_array()), Detection2DArray) wire = array.detections[0] assert array.header == source.header assert wire.header == source.header diff --git a/examples/message-codegen/demo_detection_projection.py b/examples/message-codegen/demo_detection_projection.py index b33c55d32d4..aed4e012103 100644 --- a/examples/message-codegen/demo_detection_projection.py +++ b/examples/message-codegen/demo_detection_projection.py @@ -69,7 +69,7 @@ def main() -> None: ) result = Detection3DPC.from_depth(detection, depth, camera, transform, filters=[]) assert result is not None - pose = cdr_decode(result.pose.encode(), PoseStamped) + pose = cdr_decode(cdr_encode(result.pose), PoseStamped) assert pose.header.stamp == header.stamp assert pose.header.frame_id == "world" assert (pose.pose.position.x, pose.pose.position.y, pose.pose.position.z) == (11.5, 1.5, 2) diff --git a/examples/message-codegen/demo_export_detection_fixture.py b/examples/message-codegen/demo_export_detection_fixture.py index 5088404599e..ccdcdc51e31 100644 --- a/examples/message-codegen/demo_export_detection_fixture.py +++ b/examples/message-codegen/demo_export_detection_fixture.py @@ -25,7 +25,7 @@ from dimos_generated.geometry_msgs.msg import PoseStamped from dimos_generated.sensor_msgs.msg import Image, PointCloud2 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import encode as cdr_encode +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from numpy.core.multiarray import _reconstruct @@ -146,7 +146,7 @@ def nearest(kind: str, target: float) -> tuple[float, Path, Any]: else: msg = pose_from_webrtc_odometry(value) data = cdr_encode(msg) - assert type(msg).decode(data).encode() == data + assert cdr_encode(cdr_decode(data, type(msg))) == data name = f"{seek}-{kind}.cdr" (out / name).write_bytes(data) entry["streams"][kind] = { diff --git a/examples/message-codegen/demo_g1_messages.py b/examples/message-codegen/demo_g1_messages.py index 61ef5e7ea46..4815ea28616 100644 --- a/examples/message-codegen/demo_g1_messages.py +++ b/examples/message-codegen/demo_g1_messages.py @@ -19,6 +19,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.time import to_nanoseconds from dimos.robot.unitree.g1.wholebody_connection import G1LowStateSnapshot, G1WholeBodyConnection @@ -52,7 +53,7 @@ def main() -> None: assert list(state.position) == [index * 0.1] * 29 assert orientation.orientation.w == 0.8 and orientation.orientation.z == 0.6 for message in (state, orientation): - assert type(message).decode(message.encode()) == message + assert cdr_decode(cdr_encode(message), type(message)) == message print( f"G1 sample {index}: joints={len(state.name)}, q0={state.position[0]:.1f}, IMU xyzw=(0,0,0.6,0.8), stamp={to_nanoseconds(state.header.stamp)}" ) diff --git a/examples/message-codegen/demo_galaxea_messages.py b/examples/message-codegen/demo_galaxea_messages.py index 63735db466f..5424c32c5ec 100644 --- a/examples/message-codegen/demo_galaxea_messages.py +++ b/examples/message-codegen/demo_galaxea_messages.py @@ -22,6 +22,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.time import to_nanoseconds from dimos.robot.galaxea.r1pro.connection import R1ProConnection @@ -67,7 +68,7 @@ def receive(name: str, message: Any) -> None: assert all(to_nanoseconds(edge.header.stamp) == stamp for edge in tf.transforms) assert math.isclose(pose.pose.orientation.z, math.sin(index * 0.01)) for message in (pose, odometry, tf): - assert type(message).decode(message.encode()) == message + assert cdr_decode(cdr_encode(message), type(message)) == message print( f"tick {index}: x={pose.pose.position.x:.6f}, y={pose.pose.position.y:.6f}, stamp={stamp}" ) diff --git a/examples/message-codegen/demo_go2_command_cdr.py b/examples/message-codegen/demo_go2_command_cdr.py index 0451f7e2a24..434221c9f34 100644 --- a/examples/message-codegen/demo_go2_command_cdr.py +++ b/examples/message-codegen/demo_go2_command_cdr.py @@ -42,10 +42,10 @@ def main() -> None: ) module._on_cmd_vel_in(cdr_decode(cdr_encode(message), TwistStamped)) assert module.tele_cmd_vel.publish.call_count == 2 - command = cdr_decode(module.tele_cmd_vel.publish.call_args.args[0].encode(), Twist) + command = cdr_decode(cdr_encode(module.tele_cmd_vel.publish.call_args.args[0]), Twist) assert command.linear.x == 1.5 and command.angular.z == -2 module._handle_nav_goal({"x": 2.5, "y": -1, "nonce": 1}) - goal = cdr_decode(module.goal_request.publish.call_args.args[0].encode(), PoseStamped) + goal = cdr_decode(cdr_encode(module.goal_request.publish.call_args.args[0]), PoseStamped) assert goal.header.frame_id == "world" and goal.pose.position.x == 2.5 module._estopped = True module._on_cmd_vel_in(message) diff --git a/examples/message-codegen/demo_grasp_proposals.py b/examples/message-codegen/demo_grasp_proposals.py index e93fd4fd2ed..cdfeb4af32d 100644 --- a/examples/message-codegen/demo_grasp_proposals.py +++ b/examples/message-codegen/demo_grasp_proposals.py @@ -39,7 +39,7 @@ def main() -> None: provider = HeuristicGraspModule() try: proposals = provider.propose_grasps(cdr_decode(cdr_encode(cloud), PointCloud2)) - payload = proposals.encode() + payload = cdr_encode(proposals) received = cdr_decode(payload, GraspCandidateArray) assert received.header == cloud.header assert len(received.candidates) == 1 diff --git a/examples/message-codegen/demo_holonomic_path.py b/examples/message-codegen/demo_holonomic_path.py index 0ee291088ac..22b102655bf 100644 --- a/examples/message-codegen/demo_holonomic_path.py +++ b/examples/message-codegen/demo_holonomic_path.py @@ -82,7 +82,7 @@ def odometry(tick: int) -> PoseStamped: f"Local planner committed {len(committed.poses)} resampled poses; duplicate replan held" ) core.handle_odom(odometry(0)) - core.start_planning(cdr_decode(committed.encode(), Path)) + core.start_planning(cdr_decode(cdr_encode(committed), Path)) for tick in range(300): if stopped: break diff --git a/examples/message-codegen/demo_keyboard_cdr.py b/examples/message-codegen/demo_keyboard_cdr.py index d7b75d39dcb..e877f7639d6 100644 --- a/examples/message-codegen/demo_keyboard_cdr.py +++ b/examples/message-codegen/demo_keyboard_cdr.py @@ -16,7 +16,7 @@ from dimos_generated.geometry_msgs.msg import Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Float32 -from dimos_message_build.registry import decode as cdr_decode +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pygame from dimos.teleop.keyboard.keyboard_teleop_module import KeyboardTeleopModule @@ -28,10 +28,10 @@ def main() -> None: gripper: list[Float32] = [] subscriptions = [ module.ee_twist_command.subscribe( - lambda msg: commands.append(cdr_decode(msg.encode(), TwistStamped)) + lambda msg: commands.append(cdr_decode(cdr_encode(msg), TwistStamped)) ), module.gripper_command.subscribe( - lambda msg: gripper.append(cdr_decode(msg.encode(), Float32)) + lambda msg: gripper.append(cdr_decode(cdr_encode(msg), Float32)) ), ] try: diff --git a/examples/message-codegen/demo_marker_messages.py b/examples/message-codegen/demo_marker_messages.py index ade184d7ddb..eb5dd055a0a 100644 --- a/examples/message-codegen/demo_marker_messages.py +++ b/examples/message-codegen/demo_marker_messages.py @@ -18,7 +18,7 @@ from dimos_generated.geometry_msgs.msg import Vector3 from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection3DArray -from dimos_message_build.registry import decode as cdr_decode +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.image import image_from_array @@ -50,7 +50,7 @@ def main() -> None: for identifier in (7, 42) ] message = ImageDetections3D(image, markers).to_ros_detection3d_array() - decoded = cdr_decode(message.encode(), Detection3DArray) + decoded = cdr_decode(cdr_encode(message), Detection3DArray) assert decoded.header.stamp == image.header.stamp for marker in decoded.detections: assert marker.results[0].hypothesis.class_id == f"DICT_APRILTAG_36h11:{marker.id}" diff --git a/examples/message-codegen/demo_mls_transformer.py b/examples/message-codegen/demo_mls_transformer.py index 20c20f1ca5e..3fdcf27ecb4 100644 --- a/examples/message-codegen/demo_mls_transformer.py +++ b/examples/message-codegen/demo_mls_transformer.py @@ -71,7 +71,7 @@ def main() -> None: relay._tf = tf poses: list[PoseStamped] = [] unsubscribe = relay.start_pose.subscribe( - lambda value: poses.append(cdr_decode(value.encode(), PoseStamped)) + lambda value: poses.append(cdr_decode(cdr_encode(value), PoseStamped)) ) try: relay._on_tf(TFMessage(transforms=[edge])) @@ -92,13 +92,13 @@ def main() -> None: ) ray_input = obs.derive(data=cloud, pose_tuple=(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)) [mapped] = list(RayTraceMap(voxel_size=0.2)(iter([ray_input]))) - mapped_cloud = cdr_decode(mapped.data.encode(), PointCloud2) + mapped_cloud = cdr_decode(cdr_encode(mapped.data), PointCloud2) assert mapped_cloud.header.stamp.nanosec == 123456789 print( f"Ray-traced CDR local map: {mapped_cloud.width * mapped_cloud.height} points, frame={mapped_cloud.header.frame_id}" ) [result] = list(MLSPlan(goal=(2.0, 2.0, 0.0), voxel_size=0.2, robot_height=1.0)(iter([obs]))) - path = cdr_decode(result.data.encode(), Path) + path = cdr_decode(cdr_encode(result.data), Path) assert result.tags["planned"] and len(path.poses) >= 2 assert path.header.stamp.nanosec == 123456789 print( diff --git a/examples/message-codegen/demo_movement.py b/examples/message-codegen/demo_movement.py index 03bbe703c5e..25a75eb9bf3 100644 --- a/examples/message-codegen/demo_movement.py +++ b/examples/message-codegen/demo_movement.py @@ -27,8 +27,8 @@ def main() -> None: goals: list[PointStamped] = [] commands: list[Twist] = [] unsubs = [ - manager.goal.subscribe(lambda msg: goals.append(cdr_decode(msg.encode(), PointStamped))), - manager.cmd_vel.subscribe(lambda msg: commands.append(cdr_decode(msg.encode(), Twist))), + manager.goal.subscribe(lambda msg: goals.append(cdr_decode(cdr_encode(msg), PointStamped))), + manager.cmd_vel.subscribe(lambda msg: commands.append(cdr_decode(cdr_encode(msg), Twist))), ] try: clicked = PointStamped( diff --git a/examples/message-codegen/demo_native.py b/examples/message-codegen/demo_native.py index 228208b6be4..c6f9f74ab27 100644 --- a/examples/message-codegen/demo_native.py +++ b/examples/message-codegen/demo_native.py @@ -180,7 +180,7 @@ def demonstrate(backend: str, cpp: Path, rust: Path, evidence: Path) -> None: assert decoded_lines.header.frame_id == "map" assert decoded_lines.segments[0].start.x == 1 assert decoded_lines.segments[0].end.y == 2 - assert received["image"].encode() == cdr_encode(image) + assert cdr_encode(received["image"]) == cdr_encode(image) print(f"{backend}: Python weight=4 → C++ weight=5 → Rust weight=6 → Python verified") print(f"{backend}: {len(image.data):,} image bytes and source nanoseconds={stamp} match") diff --git a/examples/message-codegen/demo_navigation_skill.py b/examples/message-codegen/demo_navigation_skill.py index f0561757c78..8af4ea89d55 100644 --- a/examples/message-codegen/demo_navigation_skill.py +++ b/examples/message-codegen/demo_navigation_skill.py @@ -48,7 +48,7 @@ def main() -> None: location = memory.tag_location.call_args.args[0] memory.query_tagged_location.return_value = location print(skill._navigate_by_tagged_location("desk")) - goal = cdr_decode(navigator.set_goal.call_args.args[0].encode(), PoseStamped) + goal = cdr_decode(cdr_encode(navigator.set_goal.call_args.args[0]), PoseStamped) np.testing.assert_allclose( quaternion_euler(goal.pose.orientation), (0.2, -0.3, math.pi / 2) ) diff --git a/examples/message-codegen/demo_odometry_history.py b/examples/message-codegen/demo_odometry_history.py index 7885b155da7..a3b1e756b38 100644 --- a/examples/message-codegen/demo_odometry_history.py +++ b/examples/message-codegen/demo_odometry_history.py @@ -45,9 +45,9 @@ async def main() -> None: commands: list[Twist] = [] arrivals: list[Bool] = [] paths: list[Path] = [] - follower.nav_cmd_vel.subscribe(lambda msg: commands.append(cdr_decode(msg.encode(), Twist))) - follower.goal_reached.subscribe(lambda msg: arrivals.append(cdr_decode(msg.encode(), Bool))) - history.odom_hist.subscribe(lambda msg: paths.append(cdr_decode(msg.encode(), Path))) + follower.nav_cmd_vel.subscribe(lambda msg: commands.append(cdr_decode(cdr_encode(msg), Twist))) + follower.goal_reached.subscribe(lambda msg: arrivals.append(cdr_decode(cdr_encode(msg), Bool))) + history.odom_hist.subscribe(lambda msg: paths.append(cdr_decode(cdr_encode(msg), Path))) header = Header(stamp=Time(sec=1700000000, nanosec=123456789), frame_id="map") reference = Path( header=header, diff --git a/examples/message-codegen/demo_phone_cdr.py b/examples/message-codegen/demo_phone_cdr.py index 6658fa2b7ff..8dcd43485c3 100644 --- a/examples/message-codegen/demo_phone_cdr.py +++ b/examples/message-codegen/demo_phone_cdr.py @@ -56,7 +56,7 @@ def main() -> None: assert message.header.frame_id == "phone" assert message.header.stamp.sec > 0 print( - f"Browser → {message.msg_name}: stamp={message.header.stamp.sec}s + " + f"Browser → {message.__msgtype__}: stamp={message.header.stamp.sec}s + " f"{message.header.stamp.nanosec}ns", flush=True, ) diff --git a/examples/message-codegen/demo_planning_backends.py b/examples/message-codegen/demo_planning_backends.py index 888067f2865..731f53b2fa4 100644 --- a/examples/message-codegen/demo_planning_backends.py +++ b/examples/message-codegen/demo_planning_backends.py @@ -90,7 +90,7 @@ def main() -> None: print(f"Drake model joints: {world.get_prepared_model().joint_space.names}") print(f"RRT result: {result.status.name}; interpolated waypoints={len(path_points)}") for index, point in enumerate(path_points): - decoded = cdr_decode(point.encode(), JointState) + decoded = cdr_decode(cdr_encode(point), JointState) assert decoded == point assert world.check_config_collision_free(decoded) with world.scratch_context() as context: diff --git a/examples/message-codegen/demo_pubsub.py b/examples/message-codegen/demo_pubsub.py index 50403a013c4..936e060e227 100644 --- a/examples/message-codegen/demo_pubsub.py +++ b/examples/message-codegen/demo_pubsub.py @@ -27,6 +27,7 @@ from dimos_generated.geometry_msgs.msg import Point from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import encode as cdr_encode import numpy as np from dimos.core.transport import LCMTransport, PubSubTransport, SHMTransport, ZenohTransport @@ -111,16 +112,16 @@ def demonstrate(backend: str) -> None: peer.start() peers.append(peer) decoded = exchange(peers[0], peers[1], message) - assert decoded.encode() == message.encode() + assert cdr_encode(decoded) == cdr_encode(message) if isinstance(decoded, LineSegments3D): print( - f"{backend}: {decoded.msg_name}, frame={decoded.header.frame_id}, " + f"{backend}: {decoded.__msgtype__}, frame={decoded.header.frame_id}, " f"segment weight={decoded.segments[0].weight}" ) else: assert isinstance(decoded, Image) print( - f"{backend}: {decoded.msg_name}, {len(decoded.data):,} pixel bytes match, " + f"{backend}: {decoded.__msgtype__}, {len(decoded.data):,} pixel bytes match, " f"source nanoseconds={to_nanoseconds(decoded.header.stamp)}" ) diff --git a/examples/message-codegen/demo_self_filter.py b/examples/message-codegen/demo_self_filter.py index f0c5cf08843..038966e212c 100644 --- a/examples/message-codegen/demo_self_filter.py +++ b/examples/message-codegen/demo_self_filter.py @@ -63,7 +63,7 @@ def main() -> None: ) result = module.filter_cloud(cdr_decode(cdr_encode(source), PointCloud2)) assert result is not None - filtered, mask = (cdr_decode(value.encode(), PointCloud2) for value in result) + filtered, mask = (cdr_decode(cdr_encode(value), PointCloud2) for value in result) np.testing.assert_allclose(pointcloud_xyz(filtered), [[5.0, 0, 0]]) assert filtered.header == source.header assert mask.header.stamp == stamp and mask.header.frame_id == "world" diff --git a/examples/message-codegen/demo_storage_replay.py b/examples/message-codegen/demo_storage_replay.py index ef37885d8dd..2ddee7645b3 100644 --- a/examples/message-codegen/demo_storage_replay.py +++ b/examples/message-codegen/demo_storage_replay.py @@ -23,6 +23,7 @@ from dimos_generated.dimos_msgs.msg import LineSegment3D, LineSegments3D from dimos_generated.geometry_msgs.msg import Point from dimos_generated.std_msgs.msg import Header +from dimos_message_build.registry import encode as cdr_encode, schema as cdr_schema from dimos.memory.codecs.base import codec_for, codec_id from dimos.memory.replay_module import replay_module diff --git a/examples/message-codegen/demo_video_stats.py b/examples/message-codegen/demo_video_stats.py index c2e27387da3..277c438c6c7 100644 --- a/examples/message-codegen/demo_video_stats.py +++ b/examples/message-codegen/demo_video_stats.py @@ -45,7 +45,7 @@ def main() -> None: restored = store.stream("video_stats").first().data assert restored == message print( - f"Recorded {restored.msg_name}: {restored.width}x{restored.height}, {restored.fps} fps" + f"Recorded {restored.__msgtype__}: {restored.width}x{restored.height}, {restored.fps} fps" ) print(f"Exact dropped-frame counter: {restored.frames_dropped}") print(f"Source stamp: {restored.header.stamp.sec}s + {restored.header.stamp.nanosec}ns") diff --git a/examples/message-codegen/demo_viewer_controls.py b/examples/message-codegen/demo_viewer_controls.py index ecdfbc246e9..7eb11133d60 100644 --- a/examples/message-codegen/demo_viewer_controls.py +++ b/examples/message-codegen/demo_viewer_controls.py @@ -41,7 +41,7 @@ def receive_velocity(message: Twist) -> None: subscriptions = [ server.clicked_point.subscribe( - lambda message: points.append(cdr_decode(message.encode(), PointStamped)) + lambda message: points.append(cdr_decode(cdr_encode(message), PointStamped)) ), server.tele_cmd_vel.subscribe(receive_velocity), ] diff --git a/examples/message-codegen/demo_visual_servo.py b/examples/message-codegen/demo_visual_servo.py index 856e19546d3..b54f842252a 100644 --- a/examples/message-codegen/demo_visual_servo.py +++ b/examples/message-codegen/demo_visual_servo.py @@ -46,7 +46,7 @@ def main() -> None: ("right of center", (370, 0, 470, 100), (0.36, -0.2)), ): command = controller.compute_twist(bbox, camera.width) - decoded = cdr_decode(command.encode(), Twist) + decoded = cdr_decode(cdr_encode(command), Twist) assert abs(decoded.linear.x - expected[0]) < 1e-9 assert abs(decoded.angular.z - expected[1]) < 1e-9 print(f"{label}: linear={decoded.linear.x:.2f} m/s, angular={decoded.angular.z:.2f} rad/s") diff --git a/examples/message-codegen/demo_vl_images.py b/examples/message-codegen/demo_vl_images.py index 5706ed921ac..81a67727832 100644 --- a/examples/message-codegen/demo_vl_images.py +++ b/examples/message-codegen/demo_vl_images.py @@ -18,7 +18,7 @@ from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection2DArray -from dimos_message_build.registry import decode as cdr_decode +from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.models.vl.base import VlModel @@ -43,7 +43,7 @@ def main() -> None: resized, scale = model._prepare_image(image) assert (resized.width, resized.height, scale) == (30, 20, 0.5) detections = model.query_detections(image, "target") - wire = cdr_decode(detections.to_ros_detection2d_array().encode(), Detection2DArray) + wire = cdr_decode(cdr_encode(detections.to_ros_detection2d_array()), Detection2DArray) assert wire.header == image.header and len(wire.detections) == 1 print("Generated image: 60x40 → 30x20, scale=0.5") print("Fixed model response → one generated CDR detection; source header preserved") From a1c7ab8aeaabe87fa046fdb402e8f71b27110bbe Mon Sep 17 00:00:00 2001 From: cc Date: Thu, 15 Oct 2026 00:25:41 -0700 Subject: [PATCH 11/11] fix(cdr): preserve retirement scope with published generator sources --- .github/scripts/check_sdist.py | 7 + .github/scripts/message_wheel_smoke.py | 10 +- dimos/agents/mcp/test_generated_image.py | 1 - dimos/agents/test_generated_vlm.py | 1 - dimos/cli/spy/test_spy.py | 1 - dimos/e2e_tests/lcm_spy.py | 1 - .../isolated_python/test_generated_example.py | 1 - dimos/experimental/memory/rust_recorder.py | 1 - .../security_demo/security_module.py | 1 - .../camera/gstreamer/test_generated_frames.py | 1 - .../grasping/grasp_gen_x/test_module.py | 1 - .../test_generated_visualizations.py | 1 - .../pointclouds/test_generated_occupancy.py | 1 - dimos/mapping/test_generated_costmapper.py | 1 - dimos/mapping/voxels/test_grid.py | 1 - dimos/memory/codecs/test_codecs.py | 1 - dimos/memory/store/test_mcap.py | 1 - dimos/message_codegen/native_sources.json | 281 -- dimos/message_codegen/py.typed | 0 .../templates/native-support.cmake | 61 - .../message_codegen/test_native_libraries.py | 259 -- dimos/models/vl/test_generated_images.py | 1 - dimos/msgs/geometry_msgs/test_Quaternion.py | 1 - dimos/msgs/geometry_msgs/test_Transform.py | 1 - dimos/msgs/geometry_msgs/test_Twist.py | 1 - dimos/msgs/geometry_msgs/test_Vector3.py | 1 - dimos/msgs/geometry_msgs/tool_publish.py | 1 - .../manipulation_msgs/test_grasp_candidate.py | 1 - dimos/msgs/sensor_msgs/test_image.py | 1 - dimos/msgs/test_camera_info.py | 1 - dimos/msgs/test_geometry.py | 1 - dimos/msgs/test_msg_construction.py | 1 - dimos/msgs/test_occupancy.py | 1 - dimos/msgs/test_pointcloud.py | 1 - .../holonomic_tc/test_dan_holonomic_tc.py | 1 - .../test_generated_frontiers.py | 1 - .../patrolling/test_generated_patrol.py | 1 - .../test_generated_navigation.py | 1 - .../test_generated_pipeline.py | 1 - .../movement_manager/test_movement_manager.py | 1 - dimos/perception/detection/conftest.py | 1 - .../type/detection2d/test_generated_bbox.py | 1 - .../detection3d/test_generated_filters.py | 1 - .../detection3d/test_generated_projection.py | 1 - .../experimental/test_generated_tracker.py | 1 - .../fiducial/test_generated_marker_detect.py | 1 - .../memory/test_generated_inventory.py | 11 +- .../pubsub/benchmark/test_replay_bench.py | 1 - dimos/protocol/pubsub/impl/jpeg_lcm.py | 1 - dimos/protocol/pubsub/impl/jpeg_shm.py | 1 - dimos/protocol/pubsub/impl/test_jpeg_cdr.py | 1 - .../pubsub/impl/webrtc/test_transport.py | 1 - dimos/protocol/tf/test_static_tf_publisher.py | 1 - .../diy/alfred/test_generated_effector.py | 1 - dimos/robot/diy/alfred/test_mount_tf.py | 1 - .../g1/debug/demo_arrow_control_cmd_vel.py | 1 - dimos/robot/unitree/go2/dds/ros.py | 1 - .../unitree/go2/dds/test_generated_codecs.py | 1 - dimos/robot/unitree/type/test_lidar.py | 1 - .../unitree/type/test_pose_conversion.py | 1 - dimos/simulation/dimsim/cdr_schemas.py | 1 - dimos/teleop/hosted/arm_command.py | 1 - dimos/teleop/hosted/hosted_stats.py | 1 - dimos/teleop/hosted/test_hosted_stats.py | 1 - dimos/teleop/phone/phone_teleop_module.py | 1 - dimos/teleop/phone/test_phone_cdr.py | 5 - dimos/teleop/utils/test_video_stats.py | 5 - .../rerun/test_generated_entity_bridge.py | 1 - dimos/web/test_cockpit.py | 1 - docs/development/message-alignment.md | 5 +- docs/development/message-limitations.md | 141 - .../message-codegen/demo_aruco_detection.py | 31 +- .../message-codegen/demo_base_transport.py | 20 +- .../message-codegen/demo_bbox_navigation.py | 44 +- examples/message-codegen/demo_blueprint.py | 28 +- .../demo_blueprint_recording.py | 1 - .../message-codegen/demo_camera_bridge.py | 48 +- .../message-codegen/demo_camera_mux_cdr.py | 5 +- .../message-codegen/demo_cloud_filters.py | 41 +- .../message-codegen/demo_command_center.py | 47 +- .../demo_coordinator_joints.py | 3 +- .../message-codegen/demo_detection_bbox.py | 3 +- .../demo_detection_projection.py | 27 +- .../demo_export_detection_fixture.py | 7 +- examples/message-codegen/demo_frontiers.py | 21 +- examples/message-codegen/demo_g1_messages.py | 3 +- .../message-codegen/demo_galaxea_messages.py | 10 +- .../message-codegen/demo_go2_command_cdr.py | 11 +- .../message-codegen/demo_grasp_proposals.py | 7 +- examples/message-codegen/demo_grid_path.py | 27 +- .../message-codegen/demo_habitat_native.py | 21 +- .../message-codegen/demo_holonomic_path.py | 30 +- .../demo_holonomic_tracking.py | 23 +- examples/message-codegen/demo_hosted_map.py | 27 +- examples/message-codegen/demo_keyboard_cdr.py | 13 +- examples/message-codegen/demo_lidar.cpp | 6 +- examples/message-codegen/demo_live_bridge.py | 5 +- .../message-codegen/demo_marker_messages.py | 5 +- .../message-codegen/demo_message_helpers.py | 24 +- .../message-codegen/demo_mls_transformer.py | 48 +- examples/message-codegen/demo_movement.py | 25 +- examples/message-codegen/demo_native.py | 14 +- examples/message-codegen/demo_navigation.py | 47 +- .../demo_navigation_recording.py | 21 +- .../message-codegen/demo_navigation_skill.py | 10 +- examples/message-codegen/demo_occupancy.py | 5 +- .../message-codegen/demo_odometry_history.py | 64 +- .../message-codegen/demo_path_following.py | 25 +- examples/message-codegen/demo_patrol.py | 18 +- .../message-codegen/demo_person_follow.py | 27 +- examples/message-codegen/demo_phone_cdr.py | 5 +- .../message-codegen/demo_planning_backends.py | 31 +- .../message-codegen/demo_planning_joints.py | 19 +- examples/message-codegen/demo_pointcloud.py | 10 +- examples/message-codegen/demo_pubsub.py | 18 +- examples/message-codegen/demo_robot_tf.py | 3 +- examples/message-codegen/demo_ros_bridge.py | 21 +- examples/message-codegen/demo_self_filter.py | 12 +- .../message-codegen/demo_storage_replay.py | 1 - examples/message-codegen/demo_video_stats.py | 5 +- .../message-codegen/demo_viewer_controls.py | 11 +- examples/message-codegen/demo_visual_servo.py | 24 +- examples/message-codegen/demo_vl_images.py | 8 +- examples/message-codegen/demo_vlm_image.py | 3 +- .../demo_whole_body_transport.py | 23 +- .../message-codegen/external-app/relay.cpp | 10 +- .../message-codegen/external-native/relay.cpp | 3 +- .../message-codegen/user-story/demo_module.py | 6 +- examples/message-project/demo_blueprint.py | 1 - .../src/dimos_generated/_types.pyi | 2991 ----------------- .../builtin_interfaces/msg/__init__.pyi | 5 - .../dimos_msgs/msg/__init__.pyi | 32 - .../foxglove_msgs/msg/__init__.pyi | 2 - .../geometry_msgs/msg/__init__.pyi | 70 - .../dimos_generated/nav_msgs/msg/__init__.pyi | 20 - .../sensor_msgs/msg/__init__.pyi | 58 - .../shape_msgs/msg/__init__.pyi | 7 - .../dimos_generated/std_msgs/msg/__init__.pyi | 64 - .../dimos_generated/tf2_msgs/msg/__init__.pyi | 2 - .../trajectory_msgs/msg/__init__.pyi | 12 - .../vision_msgs/msg/__init__.pyi | 36 - .../visualization_msgs/msg/__init__.pyi | 28 - .../cpp/builtin_interfaces/CMakeLists.txt | 12 - .../cpp/builtin_interfaces/package.xml | 1 - .../package/cpp/dimos_msgs/CMakeLists.txt | 16 - .../package/cpp/dimos_msgs/package.xml | 1 - .../package/cpp/foxglove_msgs/CMakeLists.txt | 13 - .../package/cpp/foxglove_msgs/package.xml | 1 - .../package/cpp/geometry_msgs/CMakeLists.txt | 13 - .../package/cpp/geometry_msgs/package.xml | 1 - .../package/cpp/nav_msgs/CMakeLists.txt | 15 - .../package/cpp/nav_msgs/package.xml | 1 - .../package/cpp/packages.json | 14 - .../package/cpp/sensor_msgs/CMakeLists.txt | 15 - .../package/cpp/sensor_msgs/package.xml | 1 - .../package/cpp/shape_msgs/CMakeLists.txt | 13 - .../package/cpp/shape_msgs/package.xml | 1 - .../package/cpp/std_msgs/CMakeLists.txt | 13 - .../package/cpp/std_msgs/msg/Empty.msg | 0 .../package/cpp/std_msgs/package.xml | 1 - .../package/cpp/tf2_msgs/CMakeLists.txt | 13 - .../package/cpp/tf2_msgs/package.xml | 1 - .../cpp/trajectory_msgs/CMakeLists.txt | 15 - .../package/cpp/trajectory_msgs/package.xml | 1 - .../package/cpp/vision_msgs/CMakeLists.txt | 14 - .../package/cpp/vision_msgs/package.xml | 1 - .../cpp/visualization_msgs/CMakeLists.txt | 16 - .../cpp/visualization_msgs/package.xml | 1 - scripts/test_message_user_story.sh | 63 +- 169 files changed, 315 insertions(+), 5170 deletions(-) delete mode 100644 dimos/message_codegen/native_sources.json delete mode 100644 dimos/message_codegen/py.typed delete mode 100644 dimos/message_codegen/templates/native-support.cmake delete mode 100644 dimos/message_codegen/test_native_libraries.py delete mode 100644 docs/development/message-limitations.md delete mode 100644 packages/dimos-generated/src/dimos_generated/_types.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/package.xml delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/package.xml delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/package.xml delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/package.xml delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/package.xml delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/package.xml delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/package.xml delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/msg/Empty.msg delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/package.xml delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/package.xml delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/package.xml delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/package.xml delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/CMakeLists.txt delete mode 100644 packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/package.xml diff --git a/.github/scripts/check_sdist.py b/.github/scripts/check_sdist.py index 248e62baae5..f2099cf0817 100755 --- a/.github/scripts/check_sdist.py +++ b/.github/scripts/check_sdist.py @@ -44,6 +44,13 @@ def main(sdist: str) -> None: generated = sorted(n for n in names if "node_modules" in n.split("/")) if generated: problems.append(f"{len(generated)} node_modules entries, e.g. {generated[0]}") + stale_builds = sorted( + n + for n in names + if n.startswith(("dimos/message_codegen/build/", "dimos/message_codegen/dist/")) + ) + if stale_builds: + problems.append(f"{len(stale_builds)} nested message build entries, e.g. {stale_builds[0]}") total_mb = sum(m.size for m in members) / 1e6 if total_mb > MAX_UNCOMPRESSED_MB: problems.append(f"{total_mb:.1f} MB uncompressed exceeds {MAX_UNCOMPRESSED_MB} MB") diff --git a/.github/scripts/message_wheel_smoke.py b/.github/scripts/message_wheel_smoke.py index 4caca8ca5e4..2b8199e3ac7 100644 --- a/.github/scripts/message_wheel_smoke.py +++ b/.github/scripts/message_wheel_smoke.py @@ -20,18 +20,14 @@ import dimos_generated as messages from dimos_generated_schemas.provider import package_root -from dimos_message_build.registry import decode, encode assert messages.__dimos_version__ == "0.1.0" -header = messages.std_msgs.msg.Header( - stamp=messages.builtin_interfaces.msg.Time(sec=17, nanosec=23), frame_id="wheel" -) -assert decode(encode(header), type(header)) == header +header = messages.std_msgs.msg.Header() +assert type(header).decode(header.encode()).encode() == header.encode() root = Path(package_root()) metadata = json.loads((root / "message-package.json").read_text()) assert metadata["shared"] assert "std_msgs/msg/Header" in metadata["owned"] assert (root / "schemas/std_msgs/msg/Header.msg").is_file() -assert (root / "cpp/CMakeLists.txt").is_file() -assert (root / "cpp/std_msgs/msg/Header.msg").is_file() +assert (root / "lib/cmake/dimos_generated/dimos_generatedConfig.cmake").is_file() assert (root / "rust/Cargo.toml").is_file() diff --git a/dimos/agents/mcp/test_generated_image.py b/dimos/agents/mcp/test_generated_image.py index f23d8881df5..457002e0d91 100644 --- a/dimos/agents/mcp/test_generated_image.py +++ b/dimos/agents/mcp/test_generated_image.py @@ -20,7 +20,6 @@ import cv2 from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import Image -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.agents.mcp.mcp_client import _append_image_to_history diff --git a/dimos/agents/test_generated_vlm.py b/dimos/agents/test_generated_vlm.py index d3ca3e13121..cac403becfb 100644 --- a/dimos/agents/test_generated_vlm.py +++ b/dimos/agents/test_generated_vlm.py @@ -19,7 +19,6 @@ import cv2 from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import Image -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from langchain_core.messages import AIMessage, HumanMessage import numpy as np import pytest diff --git a/dimos/cli/spy/test_spy.py b/dimos/cli/spy/test_spy.py index 83bf45f05d7..cf6fc2c2ce7 100644 --- a/dimos/cli/spy/test_spy.py +++ b/dimos/cli/spy/test_spy.py @@ -28,7 +28,6 @@ from dimos_cdrgen.registry import encode as cdr_encode from dimos_generated.geometry_msgs.msg import Vector3 -from dimos_message_build.registry import encode as cdr_encode import pytest from dimos.cli.spy.core import ( diff --git a/dimos/e2e_tests/lcm_spy.py b/dimos/e2e_tests/lcm_spy.py index c505d428baf..6d6b919a5d3 100644 --- a/dimos/e2e_tests/lcm_spy.py +++ b/dimos/e2e_tests/lcm_spy.py @@ -21,7 +21,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import PoseStamped -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.core.global_config import global_config from dimos.core.transport_factory import transport_topic diff --git a/dimos/experimental/isolated_python/test_generated_example.py b/dimos/experimental/isolated_python/test_generated_example.py index 377ec046deb..35c01af79d9 100644 --- a/dimos/experimental/isolated_python/test_generated_example.py +++ b/dimos/experimental/isolated_python/test_generated_example.py @@ -19,7 +19,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.std_msgs.msg import Int32 -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.experimental.isolated_python.bootstrap import load_class from dimos.experimental.isolated_python.example.contract import ExampleExternal diff --git a/dimos/experimental/memory/rust_recorder.py b/dimos/experimental/memory/rust_recorder.py index 790e4f2fe3d..a0bf80ea748 100644 --- a/dimos/experimental/memory/rust_recorder.py +++ b/dimos/experimental/memory/rust_recorder.py @@ -23,7 +23,6 @@ from dimos_cdrgen.registry import schema as cdr_schema from dimos_generated.std_msgs.msg import String from dimos_generated.tf2_msgs.msg import TFMessage -from dimos_message_build.registry import schema as cdr_schema from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator from dimos.constants import DIMOS_PROJECT_ROOT diff --git a/dimos/experimental/security_demo/security_module.py b/dimos/experimental/security_demo/security_module.py index 5be3b88b1ab..f40c40810da 100644 --- a/dimos/experimental/security_demo/security_module.py +++ b/dimos/experimental/security_demo/security_module.py @@ -48,7 +48,6 @@ from dimos_generated.geometry_msgs.msg import Vector3 -from dimos_generated.geometry_msgs.msg import Vector3 if TYPE_CHECKING: from dimos.perception.detection.type.detection2d.bbox import Detection2DBBox diff --git a/dimos/hardware/sensors/camera/gstreamer/test_generated_frames.py b/dimos/hardware/sensors/camera/gstreamer/test_generated_frames.py index 45d31a5e07c..af1b107373c 100644 --- a/dimos/hardware/sensors/camera/gstreamer/test_generated_frames.py +++ b/dimos/hardware/sensors/camera/gstreamer/test_generated_frames.py @@ -20,7 +20,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import Image -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/manipulation/grasping/grasp_gen_x/test_module.py b/dimos/manipulation/grasping/grasp_gen_x/test_module.py index 6bf10a9f9f0..e13f04e36e1 100644 --- a/dimos/manipulation/grasping/grasp_gen_x/test_module.py +++ b/dimos/manipulation/grasping/grasp_gen_x/test_module.py @@ -27,7 +27,6 @@ from dimos_generated.dimos_msgs.msg import GraspCandidate, GraspCandidateArray from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/mapping/occupancy/test_generated_visualizations.py b/dimos/mapping/occupancy/test_generated_visualizations.py index f3fffc3f2e9..b96a44bb826 100644 --- a/dimos/mapping/occupancy/test_generated_visualizations.py +++ b/dimos/mapping/occupancy/test_generated_visualizations.py @@ -23,7 +23,6 @@ from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid, Path from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/mapping/pointclouds/test_generated_occupancy.py b/dimos/mapping/pointclouds/test_generated_occupancy.py index d6b248e295a..2069f38e375 100644 --- a/dimos/mapping/pointclouds/test_generated_occupancy.py +++ b/dimos/mapping/pointclouds/test_generated_occupancy.py @@ -22,7 +22,6 @@ from dimos_generated.nav_msgs.msg import OccupancyGrid from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from numpy.typing import NDArray import pytest diff --git a/dimos/mapping/test_generated_costmapper.py b/dimos/mapping/test_generated_costmapper.py index 36db39639ea..bae0adcdf20 100644 --- a/dimos/mapping/test_generated_costmapper.py +++ b/dimos/mapping/test_generated_costmapper.py @@ -19,7 +19,6 @@ from dimos_generated.geometry_msgs.msg import Point, Pose from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.mapping.costmapper import CostMapper diff --git a/dimos/mapping/voxels/test_grid.py b/dimos/mapping/voxels/test_grid.py index 14b95205a08..8ad8731f056 100644 --- a/dimos/mapping/voxels/test_grid.py +++ b/dimos/mapping/voxels/test_grid.py @@ -15,7 +15,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/memory/codecs/test_codecs.py b/dimos/memory/codecs/test_codecs.py index 2d6c1b4641d..fde098a5d82 100644 --- a/dimos/memory/codecs/test_codecs.py +++ b/dimos/memory/codecs/test_codecs.py @@ -19,7 +19,6 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.sensor_msgs.msg import CompressedImage, Image from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import encode as cdr_encode import numpy as np import pytest diff --git a/dimos/memory/store/test_mcap.py b/dimos/memory/store/test_mcap.py index 0aafdc17d00..6bf674b51c9 100644 --- a/dimos/memory/store/test_mcap.py +++ b/dimos/memory/store/test_mcap.py @@ -17,7 +17,6 @@ from dimos_generated.geometry_msgs.msg import Quaternion, Vector3 from dimos_generated.sensor_msgs.msg import CompressedImage, Imu from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import encode as cdr_encode, schema as cdr_schema from mcap.writer import Writer import numpy as np import pytest diff --git a/dimos/message_codegen/native_sources.json b/dimos/message_codegen/native_sources.json deleted file mode 100644 index 5f8f498f348..00000000000 --- a/dimos/message_codegen/native_sources.json +++ /dev/null @@ -1,281 +0,0 @@ -{ - "repositories": { - "ament_package": { - "url": "https://github.com/ament/ament_package.git", - "revision": "ee3c5eda4fbc4df2c7a135d0ac1385e4a53fa0ee" - }, - "ament_cmake": { - "url": "https://github.com/ament/ament_cmake.git", - "revision": "5741cff5b9f83253bf3521bd8f44108fde3504ad" - }, - "ament_cmake_ros": { - "url": "https://github.com/ros2/ament_cmake_ros.git", - "revision": "5b77a227b940a25be5224d78d37591c8baccd756" - }, - "rcutils": { - "url": "https://github.com/ros2/rcutils.git", - "revision": "26413034bab69688475f230ea7723e534ec3f8cd" - }, - "rmw": { - "url": "https://github.com/ros2/rmw.git", - "revision": "8cb94a87cf3f4049abe2d563af893517bf336930" - }, - "rosidl_dynamic_typesupport": { - "url": "https://github.com/ros2/rosidl_dynamic_typesupport.git", - "revision": "cb8c54d12c678daa70410bb0626ed8626f561e45" - }, - "ament_index": { - "url": "https://github.com/ament/ament_index.git", - "revision": "2ccdcb8fd19a364fc793273b5793459207a440b9" - }, - "rosidl": { - "url": "https://github.com/ros2/rosidl.git", - "revision": "85fa592b698b0f665e3120f48fac0d35e2f7d8a4" - }, - "rosidl_typesupport_fastrtps": { - "url": "https://github.com/ros2/rosidl_typesupport_fastrtps.git", - "revision": "b883555055cce17982a22172a42ef557ef40bac5" - } - }, - "packages": [ - { - "name": "ament_package", - "repository": "ament_package", - "directory": ".", - "python": true - }, - { - "name": "ament_cmake_core", - "repository": "ament_cmake", - "directory": "ament_cmake_core", - "python": false - }, - { - "name": "ament_cmake_libraries", - "repository": "ament_cmake", - "directory": "ament_cmake_libraries", - "python": false - }, - { - "name": "ament_cmake_export_dependencies", - "repository": "ament_cmake", - "directory": "ament_cmake_export_dependencies", - "python": false - }, - { - "name": "ament_cmake_export_definitions", - "repository": "ament_cmake", - "directory": "ament_cmake_export_definitions", - "python": false - }, - { - "name": "ament_cmake_export_include_directories", - "repository": "ament_cmake", - "directory": "ament_cmake_export_include_directories", - "python": false - }, - { - "name": "ament_cmake_export_libraries", - "repository": "ament_cmake", - "directory": "ament_cmake_export_libraries", - "python": false - }, - { - "name": "ament_cmake_export_interfaces", - "repository": "ament_cmake", - "directory": "ament_cmake_export_interfaces", - "python": false - }, - { - "name": "ament_cmake_export_link_flags", - "repository": "ament_cmake", - "directory": "ament_cmake_export_link_flags", - "python": false - }, - { - "name": "ament_cmake_export_targets", - "repository": "ament_cmake", - "directory": "ament_cmake_export_targets", - "python": false - }, - { - "name": "ament_cmake_gen_version_h", - "repository": "ament_cmake", - "directory": "ament_cmake_gen_version_h", - "python": false - }, - { - "name": "ament_cmake_python", - "repository": "ament_cmake", - "directory": "ament_cmake_python", - "python": false - }, - { - "name": "ament_cmake_include_directories", - "repository": "ament_cmake", - "directory": "ament_cmake_include_directories", - "python": false - }, - { - "name": "ament_cmake_target_dependencies", - "repository": "ament_cmake", - "directory": "ament_cmake_target_dependencies", - "python": false - }, - { - "name": "ament_cmake_test", - "repository": "ament_cmake", - "directory": "ament_cmake_test", - "python": false - }, - { - "name": "ament_cmake_version", - "repository": "ament_cmake", - "directory": "ament_cmake_version", - "python": false - }, - { - "name": "ament_cmake", - "repository": "ament_cmake", - "directory": "ament_cmake", - "python": false - }, - { - "name": "rosidl_cli", - "repository": "rosidl", - "directory": "rosidl_cli", - "python": true - }, - { - "name": "rosidl_adapter", - "repository": "rosidl", - "directory": "rosidl_adapter", - "python": false - }, - { - "name": "rosidl_parser", - "repository": "rosidl", - "directory": "rosidl_parser", - "python": false - }, - { - "name": "rosidl_pycommon", - "repository": "rosidl", - "directory": "rosidl_pycommon", - "python": true - }, - { - "name": "rosidl_cmake", - "repository": "rosidl", - "directory": "rosidl_cmake", - "python": false - }, - { - "name": "ament_cmake_gtest", - "repository": "ament_cmake", - "directory": "ament_cmake_gtest", - "python": false - }, - { - "name": "ament_cmake_gmock", - "repository": "ament_cmake", - "directory": "ament_cmake_gmock", - "python": false - }, - { - "name": "ament_cmake_pytest", - "repository": "ament_cmake", - "directory": "ament_cmake_pytest", - "python": false - }, - { - "name": "domain_coordinator", - "repository": "ament_cmake_ros", - "directory": "domain_coordinator", - "python": true - }, - { - "name": "ament_cmake_ros", - "repository": "ament_cmake_ros", - "directory": "ament_cmake_ros", - "python": false - }, - { - "name": "ament_index_python", - "repository": "ament_index", - "directory": "ament_index_python", - "python": true - }, - { - "name": "rosidl_generator_type_description", - "repository": "rosidl", - "directory": "rosidl_generator_type_description", - "python": false - }, - { - "name": "rosidl_typesupport_interface", - "repository": "rosidl", - "directory": "rosidl_typesupport_interface", - "python": false - }, - { - "name": "rcutils", - "repository": "rcutils", - "directory": ".", - "python": false - }, - { - "name": "rosidl_generator_c", - "repository": "rosidl", - "directory": "rosidl_generator_c", - "python": false - }, - { - "name": "rosidl_runtime_c", - "repository": "rosidl", - "directory": "rosidl_runtime_c", - "python": false - }, - { - "name": "rosidl_runtime_cpp", - "repository": "rosidl", - "directory": "rosidl_runtime_cpp", - "python": false - }, - { - "name": "rosidl_generator_cpp", - "repository": "rosidl", - "directory": "rosidl_generator_cpp", - "python": false - }, - { - "name": "fastrtps_cmake_module", - "repository": "rosidl_typesupport_fastrtps", - "directory": "fastrtps_cmake_module", - "python": false - }, - { - "name": "rosidl_dynamic_typesupport", - "repository": "rosidl_dynamic_typesupport", - "directory": ".", - "python": false - }, - { - "name": "rmw", - "repository": "rmw", - "directory": "rmw", - "python": false - }, - { - "name": "rosidl_typesupport_fastrtps_cpp", - "repository": "rosidl_typesupport_fastrtps", - "directory": "rosidl_typesupport_fastrtps_cpp", - "python": false - } - ], - "fastcdr": { - "url": "https://github.com/eProsima/Fast-CDR/archive/refs/tags/v2.4.0.tar.gz", - "sha256": "79d8466107dd6b7d1defe961c4aa31735038937cf9dd1175cf6b0da0df2209ab", - "version": "2.4.0" - } -} diff --git a/dimos/message_codegen/py.typed b/dimos/message_codegen/py.typed deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/dimos/message_codegen/templates/native-support.cmake b/dimos/message_codegen/templates/native-support.cmake deleted file mode 100644 index c507cd6e37d..00000000000 --- a/dimos/message_codegen/templates/native-support.cmake +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2026 Dimensional Inc. -# SPDX-License-Identifier: Apache-2.0 -cmake_minimum_required(VERSION 3.20) -project(dimos_native_dependencies NONE) -include(FetchContent) -include(ExternalProject) -find_package(Python3 REQUIRED COMPONENTS Interpreter) -if(NOT DIMOS_SUPPORT_PREFIX) - set(DIMOS_SUPPORT_PREFIX "${CMAKE_BINARY_DIR}/install") -endif() -set(_python_path "${DIMOS_SUPPORT_PREFIX}/lib/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}/site-packages") -set(_environment "PYTHONPATH=${_python_path}" "AMENT_PREFIX_PATH=${DIMOS_SUPPORT_PREFIX}" "CMAKE_PREFIX_PATH=${DIMOS_SUPPORT_PREFIX}") -file(READ "${CMAKE_CURRENT_LIST_DIR}/native_sources.json" _lock) -string(JSON _count LENGTH "${_lock}" repositories) -math(EXPR _last "${_count}-1") -foreach(_i RANGE ${_last}) - string(JSON _name MEMBER "${_lock}" repositories ${_i}) - string(JSON _url GET "${_lock}" repositories ${_name} url) - string(JSON _revision GET "${_lock}" repositories ${_name} revision) - FetchContent_Declare(${_name} GIT_REPOSITORY "${_url}" GIT_TAG "${_revision}" - SOURCE_SUBDIR _dimos_fetch_sources_only) - FetchContent_MakeAvailable(${_name}) -endforeach() -string(JSON _url GET "${_lock}" fastcdr url) -string(JSON _hash GET "${_lock}" fastcdr sha256) -FetchContent_Declare(fastcdr URL "${_url}" URL_HASH "SHA256=${_hash}" SOURCE_SUBDIR _dimos_fetch_sources_only) -FetchContent_MakeAvailable(fastcdr) -ExternalProject_Add(support_fastcdr SOURCE_DIR "${fastcdr_SOURCE_DIR}" DOWNLOAD_COMMAND "" - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${DIMOS_SUPPORT_PREFIX} -DBUILD_TESTING=OFF - -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_RPATH=$ORIGIN) -set(_previous support_fastcdr) -string(JSON _count LENGTH "${_lock}" packages) -math(EXPR _last "${_count}-1") -foreach(_i RANGE ${_last}) - string(JSON _name GET "${_lock}" packages ${_i} name) - string(JSON _repository GET "${_lock}" packages ${_i} repository) - string(JSON _directory GET "${_lock}" packages ${_i} directory) - string(JSON _python GET "${_lock}" packages ${_i} python) - set(_source "${${_repository}_SOURCE_DIR}/${_directory}") - if(_python) - ExternalProject_Add(support_${_name} SOURCE_DIR "${_source}" DOWNLOAD_COMMAND "" - CONFIGURE_COMMAND "" BUILD_COMMAND "" - INSTALL_COMMAND "${CMAKE_COMMAND}" -E env ${_environment} - "${Python3_EXECUTABLE}" -m pip install --no-deps --no-build-isolation - --prefix "${DIMOS_SUPPORT_PREFIX}" "" - DEPENDS ${_previous}) - else() - ExternalProject_Add(support_${_name} SOURCE_DIR "${_source}" DOWNLOAD_COMMAND "" - CONFIGURE_COMMAND "${CMAKE_COMMAND}" -E env ${_environment} - "${CMAKE_COMMAND}" -S "" -B "" - -DCMAKE_INSTALL_PREFIX=${DIMOS_SUPPORT_PREFIX} - -DCMAKE_PREFIX_PATH=${DIMOS_SUPPORT_PREFIX} - -DPython3_EXECUTABLE=${Python3_EXECUTABLE} - -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release - -DCMAKE_INSTALL_RPATH=$ORIGIN - BUILD_COMMAND "${CMAKE_COMMAND}" -E env ${_environment} "${CMAKE_COMMAND}" --build "" --parallel 2 - INSTALL_COMMAND "${CMAKE_COMMAND}" -E env ${_environment} "${CMAKE_COMMAND}" --install "" - DEPENDS ${_previous}) - endif() - set(_previous support_${_name}) -endforeach() diff --git a/dimos/message_codegen/test_native_libraries.py b/dimos/message_codegen/test_native_libraries.py deleted file mode 100644 index 9771af35936..00000000000 --- a/dimos/message_codegen/test_native_libraries.py +++ /dev/null @@ -1,259 +0,0 @@ -# Copyright 2026 Dimensional Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Acceptance of native library identities and explicit unsupported semantics.""" - -import json -from pathlib import Path -import pickle -import subprocess -import sys - -import numpy as np -import pytest - -from dimos.message_codegen import native_build, registry -from dimos.message_codegen.generate import generate -from dimos.message_codegen.native_build import complete, save_complete, source_digest, stage_module -from dimos.message_codegen.project import Project, prepare - - -@pytest.fixture -def frozen_registry(monkeypatch): - previous = sys.modules.get("rosbags.usertypes") - monkeypatch.setattr(registry, "_store", None) - monkeypatch.setattr(registry, "_packages", {}) - monkeypatch.setattr(registry, "_unsupported", set()) - monkeypatch.setattr(registry, "_schemas", {}) - monkeypatch.setattr(registry, "providers", lambda: ()) - try: - yield - finally: - if previous is None: - sys.modules.pop("rosbags.usertypes", None) - else: - sys.modules["rosbags.usertypes"] = previous - - -def package(tmp_path, name, definition): - source = tmp_path / "interfaces" / "accept_msgs" / "msg" / f"{name}.msg" - source.parent.mkdir(parents=True, exist_ok=True) - source.write_text(definition) - output = tmp_path / "output" - generate( - [tmp_path / "interfaces"], - output, - [f"accept_msgs/msg/{name}"], - module="accept_messages", - shared=True, - languages=("python",), - ) - return output - - -def test_frozen_native_classes_roundtrip_and_pickle(tmp_path, frozen_registry): - root = package(tmp_path, "Reading", "std_msgs/Header header\nfloat64 value\n") - store = registry.initialize((root,)) - header = store.types["std_msgs/msg/Header"]( - store.types["builtin_interfaces/msg/Time"](1, 2), "map" - ) - cls = store.types["accept_msgs/msg/Reading"] - value = cls(header, 1.5) - assert not hasattr(value, "encode") - assert type(pickle.loads(pickle.dumps(value)).header) is type(header) - assert type(registry.decode(registry.encode(value), value.__msgtype__).header) is type(header) - assert registry.initialize((root,)).types[header.__msgtype__] is type(header) - - -def test_late_registration_fails_without_replacing_existing_classes(tmp_path, frozen_registry): - root = package(tmp_path / "one", "Reading", "float64 value\n") - store = registry.initialize((root,)) - value = store.types["accept_msgs/msg/Reading"](1.5) - newer = package(tmp_path / "two", "Other", "int32 value\n") - with pytest.raises(RuntimeError, match="frozen"): - registry.initialize((newer,)) - assert type(pickle.loads(pickle.dumps(value))) is type(value) - - -def test_schema_tampering_fails_before_registration(tmp_path, frozen_registry): - root = package(tmp_path, "Reading", "float64 value\n") - (root / "schemas.json").write_text(json.dumps({"accept_msgs/msg/Reading": "int32 value\n"})) - with pytest.raises(ValueError, match="digest"): - registry.initialize((root,)) - assert registry._store is None - - -def test_unsupported_native_python_bounds_are_not_silently_accepted(tmp_path, frozen_registry): - root = package(tmp_path, "Limited", "float64[<=3] values\n") - store = registry.initialize((root,)) - value = store.types["accept_msgs/msg/Limited"](np.array([1.0, 2.0, 3.0, 4.0])) - with pytest.raises(NotImplementedError, match="bounds"): - registry.encode(value) - wire = bytes(store.serialize_cdr(value, value.__msgtype__)) - with pytest.raises(NotImplementedError, match="bounds"): - registry.decode(wire, value.__msgtype__) - - -def test_native_python_defaults_are_explicit_not_rewritten(tmp_path, frozen_registry): - root = package(tmp_path, "Reading", "float64 value 1.5\n") - cls = registry.initialize((root,)).types["accept_msgs/msg/Reading"] - with pytest.raises(TypeError): - cls() - assert cls(1.5).value == 1.5 - assert json.loads((root / "message-package.json").read_text())[ - "types_with_declared_defaults" - ] == ["accept_msgs/msg/Reading"] - - -def test_selected_language_cache_invalidates_on_selection_edit_delete_and_rename( - tmp_path, monkeypatch -): - (tmp_path / "pyproject.toml").write_text( - '[project]\nname="accept-messages"\nversion="0.1.0"\n[tool.dimos.messages]\ndependencies={}\n' - ) - source = tmp_path / "interfaces/accept_msgs/msg/Reading.msg" - source.parent.mkdir(parents=True) - source.write_text("float64 value\n") - config = Project.load(tmp_path) - - def no_tools(*args, **kwargs): - raise AssertionError("Source packaging invoked an external build") - - monkeypatch.setattr(subprocess, "run", no_tools) - output = prepare(config) - stamp = (output / "generation.json").stat().st_mtime_ns - assert prepare(config) == output - assert (output / "generation.json").stat().st_mtime_ns == stamp - assert not (output / "cpp").exists() - assert not (output / "rust").exists() - prepare(config, ("rust",)) - assert (output / "rust/build.rs").is_file() - assert not (output / "python").exists() - source.rename(source.with_name("Renamed.msg")) - source.with_name("Renamed.msg").write_text("int32 other\n") - prepare(config) - assert not (output / "schemas/accept_msgs/msg/Reading.msg").exists() - assert (output / "schemas/accept_msgs/msg/Renamed.msg").read_text() == "int32 other\n" - source.with_name("Renamed.msg").unlink() - with pytest.raises(ValueError, match="No messages"): - prepare(config) - assert (output / "schemas/accept_msgs/msg/Renamed.msg").is_file() - - -def test_cpp_and_rust_bounded_strings_fail_explicitly(tmp_path): - source = tmp_path / "interfaces/accept_msgs/msg/Limited.msg" - source.parent.mkdir(parents=True) - source.write_text("string<=3 value\n") - for language in ["cpp", "rust"]: - with pytest.raises(NotImplementedError, match="Unsupported native"): - generate( - [tmp_path / "interfaces"], - tmp_path / language, - ["accept_msgs/msg/Limited"], - languages=(language,), - ) - - -def test_source_cache_tracks_edits_renames_and_deletions_without_build_outputs(tmp_path): - source = tmp_path / "module" - source.mkdir() - file = source / "main.cpp" - file.write_text("int main() { return 0; }\n") - digest = source_digest(source) - staged, executable = stage_module(source, source / "build/app", tmp_path / "cache") - assert (staged / "main.cpp").read_bytes() == file.read_bytes() - assert executable == staged / "build/app" - (source / "build").mkdir() - (source / "build/app").write_text("built executable") - assert source_digest(source) == digest - assert stage_module(source, source / "build/app", tmp_path / "cache")[0] == staged - file.rename(file.with_name("renamed.cpp")) - renamed = source_digest(source) - assert renamed != digest - file.with_name("renamed.cpp").write_text("int main() { return 1; }\n") - assert source_digest(source) != renamed - file.with_name("renamed.cpp").unlink() - assert source_digest(source) != digest - - -def test_native_cache_rejects_deleted_or_modified_artifacts(tmp_path): - prefix = tmp_path / "install" - prefix.mkdir() - library = prefix / "library.so" - library.write_bytes(b"original library") - marker = tmp_path / "complete.json" - save_complete(prefix, marker) - assert complete(prefix, marker) - library.write_bytes(b"changed library") - assert not complete(prefix, marker) - library.unlink() - assert not complete(prefix, marker) - - -def test_native_build_rejects_changed_schema_before_preparing_support(tmp_path, monkeypatch): - root = package(tmp_path, "Reading", "float64 value\n") - (root / "schemas/accept_msgs/msg/Reading.msg").write_text("int32 value\n") - - def no_build(*args, **kwargs): - raise AssertionError("Invalid schema started native preparation") - - monkeypatch.setattr(native_build, "prepare_support", no_build) - with pytest.raises(ValueError, match="schema mismatch"): - native_build.prepare_cpp(root, cache=tmp_path / "cache") - assert not (tmp_path / "cache").exists() - - -def test_cache_identity_tracks_selected_compilers_and_cmake(monkeypatch): - monkeypatch.setenv("CXX", "selected-cxx --target=test") - monkeypatch.setenv("CC", "selected-cc") - monkeypatch.setattr(native_build.shutil, "which", lambda name: "/tools/" + name) - monkeypatch.setattr(native_build, "find_spec", lambda name: True) - monkeypatch.setattr(native_build.metadata, "version", lambda name: "1.0") - versions = {"selected-cxx": "CXX 1", "selected-cc": "CC 1", "cmake": "CMake 1"} - commands = [] - - def compiler_output(command, **kwargs): - commands.append(command) - return "test-target" if command[-1] == "-dumpmachine" else versions[command[0]] - - monkeypatch.setattr(native_build.subprocess, "check_output", compiler_output) - first = native_build._toolchain_key() - assert ["selected-cxx", "--target=test", "--version"] in commands - assert ["selected-cc", "--version"] in commands - versions["selected-cxx"] = "CXX 2" - second = native_build._toolchain_key() - assert second != first - versions["selected-cc"] = "CC 2" - third = native_build._toolchain_key() - assert third != second - versions["cmake"] = "CMake 2" - assert native_build._toolchain_key() != third - - -@pytest.mark.parametrize("language", ["cpp", "rust"]) -@pytest.mark.xfail( - strict=True, - raises=NotImplementedError, - reason="CDR-L09: docs/development/message-limitations.md#cdr-l09", -) -def test_original_bounded_telemetry_fixture_generates_native_sources(tmp_path, language): - root = Path(__file__).resolve().parents[2] - names = generate( - [root / "examples/message-codegen"], - tmp_path / language, - ["demo_msgs/msg/Telemetry"], - "legacy_telemetry", - languages=(language,), - ) - assert "demo_msgs/msg/Telemetry" in names diff --git a/dimos/models/vl/test_generated_images.py b/dimos/models/vl/test_generated_images.py index a81f3377849..2795ed5fbf2 100644 --- a/dimos/models/vl/test_generated_images.py +++ b/dimos/models/vl/test_generated_images.py @@ -21,7 +21,6 @@ from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection2DArray -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/msgs/geometry_msgs/test_Quaternion.py b/dimos/msgs/geometry_msgs/test_Quaternion.py index c3bcd85fbcd..fcf4d78771f 100644 --- a/dimos/msgs/geometry_msgs/test_Quaternion.py +++ b/dimos/msgs/geometry_msgs/test_Quaternion.py @@ -14,7 +14,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Quaternion, Vector3 -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/msgs/geometry_msgs/test_Transform.py b/dimos/msgs/geometry_msgs/test_Transform.py index f5a17f1e792..f830ebb46ba 100644 --- a/dimos/msgs/geometry_msgs/test_Transform.py +++ b/dimos/msgs/geometry_msgs/test_Transform.py @@ -26,7 +26,6 @@ Vector3, ) from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest from rosbags.typesys import Stores, get_typestore diff --git a/dimos/msgs/geometry_msgs/test_Twist.py b/dimos/msgs/geometry_msgs/test_Twist.py index 4563457f0ea..0dc7b6c95bf 100644 --- a/dimos/msgs/geometry_msgs/test_Twist.py +++ b/dimos/msgs/geometry_msgs/test_Twist.py @@ -16,7 +16,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Quaternion, Twist, Vector3 -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from rosbags.typesys import Stores, get_typestore diff --git a/dimos/msgs/geometry_msgs/test_Vector3.py b/dimos/msgs/geometry_msgs/test_Vector3.py index 6ac52681719..2f7f85001c1 100644 --- a/dimos/msgs/geometry_msgs/test_Vector3.py +++ b/dimos/msgs/geometry_msgs/test_Vector3.py @@ -14,7 +14,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Vector3 -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/msgs/geometry_msgs/tool_publish.py b/dimos/msgs/geometry_msgs/tool_publish.py index fb42e6acc5e..592e54b1d4f 100644 --- a/dimos/msgs/geometry_msgs/tool_publish.py +++ b/dimos/msgs/geometry_msgs/tool_publish.py @@ -16,7 +16,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Vector3 -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import lcm diff --git a/dimos/msgs/manipulation_msgs/test_grasp_candidate.py b/dimos/msgs/manipulation_msgs/test_grasp_candidate.py index 47a146c9fdc..8313f74b512 100644 --- a/dimos/msgs/manipulation_msgs/test_grasp_candidate.py +++ b/dimos/msgs/manipulation_msgs/test_grasp_candidate.py @@ -16,7 +16,6 @@ from dimos_generated.dimos_msgs.msg import GraspCandidate, GraspCandidateArray from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.time import time_from_seconds diff --git a/dimos/msgs/sensor_msgs/test_image.py b/dimos/msgs/sensor_msgs/test_image.py index b34783f1fed..9c258b86a88 100644 --- a/dimos/msgs/sensor_msgs/test_image.py +++ b/dimos/msgs/sensor_msgs/test_image.py @@ -20,7 +20,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from PIL import Image as PILImage import pytest diff --git a/dimos/msgs/test_camera_info.py b/dimos/msgs/test_camera_info.py index 8e933b03dfc..81dcbd8955a 100644 --- a/dimos/msgs/test_camera_info.py +++ b/dimos/msgs/test_camera_info.py @@ -21,7 +21,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import CameraInfo from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest import yaml diff --git a/dimos/msgs/test_geometry.py b/dimos/msgs/test_geometry.py index aa82c94d678..08dfff82c9b 100644 --- a/dimos/msgs/test_geometry.py +++ b/dimos/msgs/test_geometry.py @@ -33,7 +33,6 @@ ) from dimos_generated.nav_msgs.msg import Odometry from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/msgs/test_msg_construction.py b/dimos/msgs/test_msg_construction.py index aa298354a21..6a265928fcf 100644 --- a/dimos/msgs/test_msg_construction.py +++ b/dimos/msgs/test_msg_construction.py @@ -41,7 +41,6 @@ from dimos_generated.nav_msgs.msg import Odometry, Path from dimos_generated.sensor_msgs.msg import JointState, Joy from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest from rosbags.serde.errors import SerdeError diff --git a/dimos/msgs/test_occupancy.py b/dimos/msgs/test_occupancy.py index f676a5e3a23..dabeecee18a 100644 --- a/dimos/msgs/test_occupancy.py +++ b/dimos/msgs/test_occupancy.py @@ -19,7 +19,6 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from PIL import Image import pytest diff --git a/dimos/msgs/test_pointcloud.py b/dimos/msgs/test_pointcloud.py index 20a9f8befce..a349c0800f7 100644 --- a/dimos/msgs/test_pointcloud.py +++ b/dimos/msgs/test_pointcloud.py @@ -23,7 +23,6 @@ from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 from dimos_generated.sensor_msgs.msg import PointCloud2, PointField from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/navigation/experimental/dannav/holonomic_tc/test_dan_holonomic_tc.py b/dimos/navigation/experimental/dannav/holonomic_tc/test_dan_holonomic_tc.py index e22f80538c2..31b600bb71d 100644 --- a/dimos/navigation/experimental/dannav/holonomic_tc/test_dan_holonomic_tc.py +++ b/dimos/navigation/experimental/dannav/holonomic_tc/test_dan_holonomic_tc.py @@ -28,7 +28,6 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist from dimos_generated.nav_msgs.msg import Path from dimos_generated.std_msgs.msg import Bool, Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.core.stream import Stream, Transport diff --git a/dimos/navigation/experimental/frontier_exploration/test_generated_frontiers.py b/dimos/navigation/experimental/frontier_exploration/test_generated_frontiers.py index eab92abf972..88635ce5745 100644 --- a/dimos/navigation/experimental/frontier_exploration/test_generated_frontiers.py +++ b/dimos/navigation/experimental/frontier_exploration/test_generated_frontiers.py @@ -19,7 +19,6 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/navigation/experimental/patrolling/test_generated_patrol.py b/dimos/navigation/experimental/patrolling/test_generated_patrol.py index ce4c2cbdb8b..588af6ebf9f 100644 --- a/dimos/navigation/experimental/patrolling/test_generated_patrol.py +++ b/dimos/navigation/experimental/patrolling/test_generated_patrol.py @@ -20,7 +20,6 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/navigation/go2/replanning_a_star/test_generated_navigation.py b/dimos/navigation/go2/replanning_a_star/test_generated_navigation.py index 4be7f99f14d..340bdcc1417 100644 --- a/dimos/navigation/go2/replanning_a_star/test_generated_navigation.py +++ b/dimos/navigation/go2/replanning_a_star/test_generated_navigation.py @@ -20,7 +20,6 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist, Vector3 from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid, Path from dimos_generated.std_msgs.msg import Bool, Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.core.global_config import GlobalConfig diff --git a/dimos/navigation/go2/replanning_a_star/test_generated_pipeline.py b/dimos/navigation/go2/replanning_a_star/test_generated_pipeline.py index 000ff679237..bd9e60eec0e 100644 --- a/dimos/navigation/go2/replanning_a_star/test_generated_pipeline.py +++ b/dimos/navigation/go2/replanning_a_star/test_generated_pipeline.py @@ -22,7 +22,6 @@ from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid, Path from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/navigation/movement_manager/test_movement_manager.py b/dimos/navigation/movement_manager/test_movement_manager.py index 09170aadf01..497e77b0500 100644 --- a/dimos/navigation/movement_manager/test_movement_manager.py +++ b/dimos/navigation/movement_manager/test_movement_manager.py @@ -21,7 +21,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Point, PointStamped, Twist, Vector3 -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.constants import DEFAULT_THREAD_JOIN_TIMEOUT diff --git a/dimos/perception/detection/conftest.py b/dimos/perception/detection/conftest.py index 9acde8afcfe..16bb8ec8d6b 100644 --- a/dimos/perception/detection/conftest.py +++ b/dimos/perception/detection/conftest.py @@ -23,7 +23,6 @@ from dimos_generated.sensor_msgs.msg import CameraInfo, Image, PointCloud2 from dimos_generated.vision_msgs.msg import Detection2DArray from dimos_generated.visualization_msgs.msg import MarkerArray -from dimos_message_build.registry import decode as cdr_decode import pytest from dimos.core.transport import LCMTransport diff --git a/dimos/perception/detection/type/detection2d/test_generated_bbox.py b/dimos/perception/detection/type/detection2d/test_generated_bbox.py index 3000158328e..393b33a5fee 100644 --- a/dimos/perception/detection/type/detection2d/test_generated_bbox.py +++ b/dimos/perception/detection/type/detection2d/test_generated_bbox.py @@ -16,7 +16,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection2D, Detection2DArray -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.image import image_from_array, image_view diff --git a/dimos/perception/detection/type/detection3d/test_generated_filters.py b/dimos/perception/detection/type/detection3d/test_generated_filters.py index c6b12c60cba..b3a679652be 100644 --- a/dimos/perception/detection/type/detection3d/test_generated_filters.py +++ b/dimos/perception/detection/type/detection3d/test_generated_filters.py @@ -19,7 +19,6 @@ from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 from dimos_generated.sensor_msgs.msg import CameraInfo, PointCloud2, PointField, RegionOfInterest from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/perception/detection/type/detection3d/test_generated_projection.py b/dimos/perception/detection/type/detection3d/test_generated_projection.py index 5405da85802..8a2aea7cf0d 100644 --- a/dimos/perception/detection/type/detection3d/test_generated_projection.py +++ b/dimos/perception/detection/type/detection3d/test_generated_projection.py @@ -25,7 +25,6 @@ ) from dimos_generated.sensor_msgs.msg import CameraInfo, RegionOfInterest from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/perception/experimental/test_generated_tracker.py b/dimos/perception/experimental/test_generated_tracker.py index 0e2e2bba577..b8f486bc196 100644 --- a/dimos/perception/experimental/test_generated_tracker.py +++ b/dimos/perception/experimental/test_generated_tracker.py @@ -26,7 +26,6 @@ Point2D, Pose2D, ) -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/perception/fiducial/test_generated_marker_detect.py b/dimos/perception/fiducial/test_generated_marker_detect.py index 50ea5b68e53..d614d485a91 100644 --- a/dimos/perception/fiducial/test_generated_marker_detect.py +++ b/dimos/perception/fiducial/test_generated_marker_detect.py @@ -19,7 +19,6 @@ from dimos_generated.sensor_msgs.msg import CameraInfo, Image, RegionOfInterest from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection3D -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/perception/memory/test_generated_inventory.py b/dimos/perception/memory/test_generated_inventory.py index 9b0924e1830..8c3223fc4b8 100644 --- a/dimos/perception/memory/test_generated_inventory.py +++ b/dimos/perception/memory/test_generated_inventory.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 from dimos_generated.std_msgs.msg import Header import numpy as np @@ -57,15 +56,11 @@ def test_generated_support_merge_preserves_colors_and_source_time(): def test_generated_support_projection_reads_nested_transform_and_intrinsics(): - calibration = camera_info_from_intrinsics( - 10, 20, 5, 6, 100, 100, header=Header(stamp=Time(sec=0, nanosec=0), frame_id="") - ) + calibration = camera_info_from_intrinsics(10, 20, 5, 6, 100, 100, header=Header()) transform = TransformStamped( - header=Header(frame_id="optical", stamp=Time(sec=0, nanosec=0)), + header=Header(frame_id="optical"), child_frame_id="world", - transform=Transform( - translation=Vector3(x=-1, y=0.0, z=0.0), rotation=Quaternion(w=1, x=0.0, y=0.0, z=0.0) - ), + transform=Transform(translation=Vector3(x=-1), rotation=Quaternion(w=1)), ) assert _pixel_bbox(np.array([[1, 0, 2], [2, 1, 2]]), calibration, transform) == (5, 6, 10, 16) diff --git a/dimos/protocol/pubsub/benchmark/test_replay_bench.py b/dimos/protocol/pubsub/benchmark/test_replay_bench.py index 68ca0148034..7823d8107d6 100644 --- a/dimos/protocol/pubsub/benchmark/test_replay_bench.py +++ b/dimos/protocol/pubsub/benchmark/test_replay_bench.py @@ -23,7 +23,6 @@ from dimos_cdrgen.registry import encode as cdr_encode from dimos_generated.sensor_msgs.msg import CompressedImage, Image from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import encode as cdr_encode import numpy as np import pytest diff --git a/dimos/protocol/pubsub/impl/jpeg_lcm.py b/dimos/protocol/pubsub/impl/jpeg_lcm.py index c2eb0df435b..7dc46e22092 100644 --- a/dimos/protocol/pubsub/impl/jpeg_lcm.py +++ b/dimos/protocol/pubsub/impl/jpeg_lcm.py @@ -23,7 +23,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import CompressedImage, Image -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.image import compressed_image_from_image, image_from_compressed from dimos.protocol.pubsub.encoders import DecodingError, PubSubEncoderMixin, TypedTopicProto diff --git a/dimos/protocol/pubsub/impl/jpeg_shm.py b/dimos/protocol/pubsub/impl/jpeg_shm.py index c914f1bc545..ee4a1f7be8f 100644 --- a/dimos/protocol/pubsub/impl/jpeg_shm.py +++ b/dimos/protocol/pubsub/impl/jpeg_shm.py @@ -16,7 +16,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.sensor_msgs.msg import CompressedImage, Image -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.image import compressed_image_from_image, image_from_compressed from dimos.protocol.pubsub.encoders import PubSubEncoderMixin diff --git a/dimos/protocol/pubsub/impl/test_jpeg_cdr.py b/dimos/protocol/pubsub/impl/test_jpeg_cdr.py index a97d2ce9651..effabf17d4c 100644 --- a/dimos/protocol/pubsub/impl/test_jpeg_cdr.py +++ b/dimos/protocol/pubsub/impl/test_jpeg_cdr.py @@ -22,7 +22,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import CompressedImage, Image from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest diff --git a/dimos/protocol/pubsub/impl/webrtc/test_transport.py b/dimos/protocol/pubsub/impl/webrtc/test_transport.py index 3a88a7f14bc..901ec3bcbae 100644 --- a/dimos/protocol/pubsub/impl/webrtc/test_transport.py +++ b/dimos/protocol/pubsub/impl/webrtc/test_transport.py @@ -21,7 +21,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Point, TwistStamped, Vector3 -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from pydantic import ValidationError import pytest diff --git a/dimos/protocol/tf/test_static_tf_publisher.py b/dimos/protocol/tf/test_static_tf_publisher.py index d83c083c945..90316e4717e 100644 --- a/dimos/protocol/tf/test_static_tf_publisher.py +++ b/dimos/protocol/tf/test_static_tf_publisher.py @@ -18,7 +18,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.tf2_msgs.msg import TFMessage -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.msgs.geometry import compose_transforms diff --git a/dimos/robot/diy/alfred/test_generated_effector.py b/dimos/robot/diy/alfred/test_generated_effector.py index 692adf84569..d81168e2784 100644 --- a/dimos/robot/diy/alfred/test_generated_effector.py +++ b/dimos/robot/diy/alfred/test_generated_effector.py @@ -17,7 +17,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.nav_msgs.msg import Odometry -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.msgs.geometry import yaw diff --git a/dimos/robot/diy/alfred/test_mount_tf.py b/dimos/robot/diy/alfred/test_mount_tf.py index 5b799aafa38..609f8f9a521 100644 --- a/dimos/robot/diy/alfred/test_mount_tf.py +++ b/dimos/robot/diy/alfred/test_mount_tf.py @@ -16,7 +16,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.tf2_msgs.msg import TFMessage -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.robot.diy.alfred import mount_tf diff --git a/dimos/robot/unitree/g1/debug/demo_arrow_control_cmd_vel.py b/dimos/robot/unitree/g1/debug/demo_arrow_control_cmd_vel.py index 19162634f7d..6b156f3d4a4 100644 --- a/dimos/robot/unitree/g1/debug/demo_arrow_control_cmd_vel.py +++ b/dimos/robot/unitree/g1/debug/demo_arrow_control_cmd_vel.py @@ -22,7 +22,6 @@ from dimos_cdrgen.registry import encode as cdr_encode from dimos_generated.geometry_msgs.msg import Twist, Vector3 -from dimos_message_build.registry import encode as cdr_encode import lcm from dimos.core.transport import LCMTransport diff --git a/dimos/robot/unitree/go2/dds/ros.py b/dimos/robot/unitree/go2/dds/ros.py index 20205e6c477..b9ea5d53d90 100644 --- a/dimos/robot/unitree/go2/dds/ros.py +++ b/dimos/robot/unitree/go2/dds/ros.py @@ -26,7 +26,6 @@ from dimos_generated.geometry_msgs.msg import Quaternion from dimos_generated.nav_msgs.msg import Odometry from dimos_generated.sensor_msgs.msg import CompressedImage, Imu, PointCloud2 -from dimos_message_build.registry import decode as cdr_decode import numpy as np from dimos.robot.unitree.go2.dds import cdr diff --git a/dimos/robot/unitree/go2/dds/test_generated_codecs.py b/dimos/robot/unitree/go2/dds/test_generated_codecs.py index 0d9327ca2e6..2e39b2b1993 100644 --- a/dimos/robot/unitree/go2/dds/test_generated_codecs.py +++ b/dimos/robot/unitree/go2/dds/test_generated_codecs.py @@ -29,7 +29,6 @@ from dimos_generated.nav_msgs.msg import Odometry from dimos_generated.sensor_msgs.msg import CompressedImage, Imu, PointCloud2, PointField from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import encode as cdr_encode import numpy as np import pytest from rosbags.typesys import Stores, get_typestore diff --git a/dimos/robot/unitree/type/test_lidar.py b/dimos/robot/unitree/type/test_lidar.py index 2bbf7429d95..9d8faecddee 100644 --- a/dimos/robot/unitree/type/test_lidar.py +++ b/dimos/robot/unitree/type/test_lidar.py @@ -20,7 +20,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import pytest import reactivex as rx diff --git a/dimos/robot/unitree/type/test_pose_conversion.py b/dimos/robot/unitree/type/test_pose_conversion.py index 5dda53c7355..5c1a7571c06 100644 --- a/dimos/robot/unitree/type/test_pose_conversion.py +++ b/dimos/robot/unitree/type/test_pose_conversion.py @@ -18,7 +18,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import PoseStamped from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.robot.unitree.type.odometry import pose_from_webrtc_odometry, raw_odometry_msg_sample diff --git a/dimos/simulation/dimsim/cdr_schemas.py b/dimos/simulation/dimsim/cdr_schemas.py index efb519eebe6..4ee6402b1b2 100644 --- a/dimos/simulation/dimsim/cdr_schemas.py +++ b/dimos/simulation/dimsim/cdr_schemas.py @@ -22,7 +22,6 @@ from dimos_cdrgen.registry import schema as cdr_schema from dimos_generated.geometry_msgs.msg import PoseStamped, Twist from dimos_generated.sensor_msgs.msg import Image, PointCloud2 -from dimos_message_build.registry import schema as cdr_schema from dimos.constants import DIMOS_PROJECT_ROOT diff --git a/dimos/teleop/hosted/arm_command.py b/dimos/teleop/hosted/arm_command.py index e4e2ba46333..06fea2a3bfd 100644 --- a/dimos/teleop/hosted/arm_command.py +++ b/dimos/teleop/hosted/arm_command.py @@ -27,7 +27,6 @@ from dimos_cdrgen.registry import decode as cdr_decode from dimos_generated.geometry_msgs.msg import PoseStamped, Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Float32, Header -from dimos_message_build.registry import decode as cdr_decode from reactivex.disposable import Disposable from dimos.control.coordinator import ControlCoordinator diff --git a/dimos/teleop/hosted/hosted_stats.py b/dimos/teleop/hosted/hosted_stats.py index 07a240683f4..dcb73b889c3 100644 --- a/dimos/teleop/hosted/hosted_stats.py +++ b/dimos/teleop/hosted/hosted_stats.py @@ -31,7 +31,6 @@ from dimos_cdrgen.registry import decode as cdr_decode from dimos_generated.dimos_msgs.msg import VideoStats from dimos_generated.geometry_msgs.msg import TwistStamped -from dimos_message_build.registry import decode as cdr_decode from reactivex.disposable import Disposable from dimos.core.core import rpc diff --git a/dimos/teleop/hosted/test_hosted_stats.py b/dimos/teleop/hosted/test_hosted_stats.py index b7007a690b5..262770eef13 100644 --- a/dimos/teleop/hosted/test_hosted_stats.py +++ b/dimos/teleop/hosted/test_hosted_stats.py @@ -24,7 +24,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, encode as cdr_encode from dimos_generated.geometry_msgs.msg import Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pytest from dimos.core.module import Module diff --git a/dimos/teleop/phone/phone_teleop_module.py b/dimos/teleop/phone/phone_teleop_module.py index 5217e77ccee..654c78e9ffe 100644 --- a/dimos/teleop/phone/phone_teleop_module.py +++ b/dimos/teleop/phone/phone_teleop_module.py @@ -30,7 +30,6 @@ from dimos_cdrgen.registry import decode as cdr_decode, schema as cdr_schema from dimos_generated.geometry_msgs.msg import Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Bool, Header -from dimos_message_build.registry import decode as cdr_decode, schema as cdr_schema from fastapi import WebSocket, WebSocketDisconnect from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles diff --git a/dimos/teleop/phone/test_phone_cdr.py b/dimos/teleop/phone/test_phone_cdr.py index 160489c6eee..7595def569c 100644 --- a/dimos/teleop/phone/test_phone_cdr.py +++ b/dimos/teleop/phone/test_phone_cdr.py @@ -24,11 +24,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Bool, Header -from dimos_message_build.registry import ( - decode as cdr_decode, - encode as cdr_encode, - schema as cdr_schema, -) from fastapi.testclient import TestClient import pytest diff --git a/dimos/teleop/utils/test_video_stats.py b/dimos/teleop/utils/test_video_stats.py index 4cfd3b2926a..b622a602282 100644 --- a/dimos/teleop/utils/test_video_stats.py +++ b/dimos/teleop/utils/test_video_stats.py @@ -22,11 +22,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.dimos_msgs.msg import VideoStats from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import ( - decode as cdr_decode, - encode as cdr_encode, - schema as cdr_schema, -) import pytest from dimos.memory.store.sqlite import SqliteStore diff --git a/dimos/visualization/rerun/test_generated_entity_bridge.py b/dimos/visualization/rerun/test_generated_entity_bridge.py index 51055074a22..ab7a6265912 100644 --- a/dimos/visualization/rerun/test_generated_entity_bridge.py +++ b/dimos/visualization/rerun/test_generated_entity_bridge.py @@ -17,7 +17,6 @@ from dimos_generated.dimos_msgs.msg import EntityMarker, EntityMarkers from dimos_generated.geometry_msgs.msg import Point from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import encode as cdr_encode, schema as cdr_schema import numpy as np import rerun as rr from rosbags.typesys import Stores, get_types_from_msg, get_typestore diff --git a/dimos/web/test_cockpit.py b/dimos/web/test_cockpit.py index 4e2e6bcaaae..365ade1f2e9 100644 --- a/dimos/web/test_cockpit.py +++ b/dimos/web/test_cockpit.py @@ -29,7 +29,6 @@ from dimos_generated.tf2_msgs.msg import TFMessage from dimos_generated.trajectory_msgs.msg import JointTrajectory from dimos_generated.visualization_msgs.msg import MarkerArray -from dimos_message_build.registry import schema as cdr_schema from langchain_core.messages import BaseMessage import pytest diff --git a/docs/development/message-alignment.md b/docs/development/message-alignment.md index 442582ddad1..5a309a750b3 100644 --- a/docs/development/message-alignment.md +++ b/docs/development/message-alignment.md @@ -1,12 +1,11 @@ # Verify prepared built-in inputs and artifacts -PR1 owns the generic source-package hooks, dependency ownership and pinned source -preparation. PR2 owns `packages/dimos-generated/custom`, `catalog.json`, +The published `dimos-cdrgen` package owns generic source-package hooks, dependency +ownership and source preparation. DimOS owns `packages/dimos-generated/custom`, `catalog.json`, `schema-sources.json`, package metadata and thin preparation/release entrypoints. There is no committed generated snapshot or bulk upstream catalog. ```sh skip -python scripts/prepare_message_parser.py python -m scripts.prepare_builtin_sources python -m scripts.generate_builtin_messages python -m scripts.generate_builtin_messages --check diff --git a/docs/development/message-limitations.md b/docs/development/message-limitations.md deleted file mode 100644 index a339456cace..00000000000 --- a/docs/development/message-limitations.md +++ /dev/null @@ -1,141 +0,0 @@ -# Native CDR proposal: accepted limitations - -The proposal directly uses rosbags 0.11.0 for Python, upstream ROSIDL/FastRTPS -with Fast CDR 2.4.0 for C++, and ros2msg 0.5.3 with re_cdr 0.1.0 for Rust. -On 2026-10-09 the user provisionally accepted the limitations below as non-blockers -for continuing this proposal. This is a scope decision, not evidence that malformed -input is safe or correctly decoded. No upstream patch or owned field codec was -added to conceal these behaviors. - -Use schema-matched CDR from trusted producers and recordings. The Python decoder -is **not a validation boundary for hostile or malformed input**. A trusted producer -can still have bugs; round-trip tests and transport authentication do not establish -parser safety. No denial-of-service or corruption of valid payloads was demonstrated -by the small cases below; malformed inputs can nevertheless become plausible, -unintended values. - -## The original 13 strict acceptance failures - -The assertions remain in `dimos/message_codegen/test_python_source.py`. Only the -exact failing parameters carry `xfail(strict=True)` with these identifiers. An -unexpected pass fails the check and requires reviewing the pin and limitation. -Wire-rejection cases accept only the missing-exception assertion failure; unsupported -schema cases accept only `NotImplementedError`. Unrelated exceptions fail normally. -Run the original assertions without expected-failure handling using: - -```sh expected-error -python -m pytest --noconftest -o addopts='' --runxfail \ - dimos/message_codegen/test_python_source.py -``` - -With the accepted pin, this strict run has **8 passed, 13 failed**; the ordinary -run has **8 passed, 13 xfailed, 0 failed**. This distinction must remain visible in -validation reports. It is not an all-correct decoder result. - -### CDR-L01 - -**Exact-consumption policy: 3 cases.** A valid `Bool` followed by one, two or three -zero bytes is accepted, and those bytes disappear on re-encoding. Our original -rule required consuming the entire payload. Rosbags explicitly tolerates up to -three trailing bytes; framing and padding policies vary, so these tests do not -prove every padded sample is invalid CDR. The decoded boolean is unchanged. -Four extra bytes are still rejected in the ordinary, non-optimized test run. - -### CDR-L02 - -**String wire validity: 2 cases, little and big endian.** A declared string length -of zero, with no terminator, becomes an empty string. Ordinary CDR string lengths -include the NUL terminator. Re-encoding creates length one plus NUL. Some native -libraries also tolerate a zero-length null-string form; this tolerance does not -satisfy the original assertion. - -### CDR-L03 - -**String wire validity: 2 cases, little and big endian.** Length two with payload -`ab` and no NUL decodes as `a`. The decoder discards the final byte without -checking that it is a terminator. This is demonstrated truncation of malformed -input, not demonstrated corruption of a valid encoded string. - -### CDR-L04 - -**String wire validity: 2 cases, little and big endian.** Declared length -`0xffffffff` with only one NUL byte becomes an empty string. The upstream decoder -reads that length as signed `-1`; its returned body position is three although -five bytes were supplied. This demonstrates malformed/truncated-input acceptance, -not a demonstrated four-gigabyte allocation or denial-of-service. - -### CDR-L05 - -**Representation mismatch: 1 case.** Header `00 03 00 00` followed by byte `01` -is accepted as `Bool(True)`. Identifier `0003` means parameter-list CDR little -endian; it is not an unknown identifier, but this body is not a valid parameter -list and the proposal expects plain CDR (`0000` or `0001`). Rosbags interprets it -as plain little-endian CDR instead of rejecting the representation. - -### CDR-L06 - -**Boolean wire validity: 1 original case.** Boolean byte `02` becomes `True`, and -re-encoding changes it to `01`. The invalid value is normalized silently. -The separate existing array regression in `test_definitions.py` exercises the -same limitation in both byte orders: **2 additional explicit xfails**, not two -additional categories. Its valid padding and NaN checks remain ordinary tests. - -### CDR-L07 - -**Bounded-schema support: 1 case.** A valid `shape_msgs/msg/SolidPrimitive` with -three dimensions cannot encode/decode through the Python registry: it raises -`NotImplementedError`. This is a functionality gap. Valid bounded messages do -**not** currently work merely because the types can be constructed. - -### CDR-L08 - -**Bounded-schema error contract: 1 case.** The same type with four dimensions is -also rejected as unsupported, rather than with the assertion's expected bound -validation `ValueError`. It fails closed; this case does not demonstrate an -oversized value being accepted. No bound is silently truncated or removed. - -### CDR-L09 - -The original bounded `demo_msgs/msg/Telemetry` generation is retained as two -strict expected failures (C++ and Rust) in `test_native_libraries.py`. Its `.msg` -source is unchanged. These are additional manifestations of unsupported bounded -strings, not part of the original 13 Python decoder assertions. The built-in -catalog also has two endian-specific `CDR-L07` xfails for `SolidPrimitive`. - -## Other native API and schema limits - -Python encode/decode rejects every closure containing a bounded string or bounded -sequence. C++/Rust generation rejects bounded-string closures; Rust wide-string -mapping is also unvalidated and rejected. These failures remain errors at the -public boundary. The legacy `demo_msgs/msg/Telemetry` fixture contains both a -bounded string and bounded sequence. Its full three-language/default conformance -and derived viewer/package demos cannot be claimed as passing; its original -schema and assertions remain available for later library work. - -Python/Rust construction requires explicit fields. Python native classes do not -apply `.msg` defaults; Rust's upstream floating-default generation is disabled. -These are separate from the 13 wire/bounds cases. Native NumPy arrays and nested -values retain their library ownership/equality behavior; helpers supply explicit -copy/read-only-view contracts. Former pybind container methods are not the native -value API. Rosbags initializes Python classes and codecs in memory from installed -schemas; Python import does not compile native code or download dependencies. -Use the single frozen registry within a runtime process. Independent rosbags -reference stores replace its process-global `usertypes` module and can invalidate -ordinary pickle identities; run independent reference decoders in separate -processes. Oracle tests restore that global module after each case. - -C++ distribution is source-only with explicit, on-demand native preparation. -Prebuilt SDK products are out of scope. M20 SDK access, host multicast, Foxglove -sign-in and human visual acceptance are separate limits, not covered by these -expected failures. No benchmark acceptance is implied. - -## Source references and future changes - -- [Rosbags type system](https://ternaris.gitlab.io/rosbags/topics/typesys.html) -- [Rosbags decoder implementation](https://gitlab.com/ternaris/rosbags/-/blob/v0.11.0/src/rosbags/typesys/store.py) -- [OMG CDR string encoding](https://www.omg.org/cgi-bin/doc?formal%2F01-09-52.pdf=) -- [OMG representation identifiers](https://www.omg.org/spec/DDSI-RTPS/2.2/PDF) - -A future upstream version, finite boundary checks or a narrower contract requires -reviewing each expected failure explicitly. Do not broad-skip the suite, silently -relax its assertions, or add a new field codec to make the status green. diff --git a/examples/message-codegen/demo_aruco_detection.py b/examples/message-codegen/demo_aruco_detection.py index d326114e5a7..5cdb47d58e3 100644 --- a/examples/message-codegen/demo_aruco_detection.py +++ b/examples/message-codegen/demo_aruco_detection.py @@ -17,11 +17,10 @@ import cv2 from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 -from dimos_generated.sensor_msgs.msg import CameraInfo, Image, RegionOfInterest +from dimos_generated.sensor_msgs.msg import CameraInfo, Image from dimos_generated.std_msgs.msg import Header from dimos_generated.tf2_msgs.msg import TFMessage from dimos_generated.vision_msgs.msg import Detection3D, Detection3DArray -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.memory.type.observation import Observation @@ -37,26 +36,12 @@ def main() -> None: pixels[100:300, 100:300] = cv2.aruco.generateImageMarker(dictionary, 7, 200) header = Header(frame_id="camera", stamp=Time(sec=1700000000, nanosec=123456789)) image = image_from_array(pixels, encoding="mono8", header=header) - image = cdr_decode(cdr_encode(image), Image) - camera = CameraInfo( - width=400, - height=400, - k=np.array([400, 0, 200, 0, 400, 200, 0, 0, 1], dtype=np.float64), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - distortion_model="", - d=np.array([], dtype=np.float64), - r=np.zeros(9, dtype=np.float64), - p=np.zeros(12, dtype=np.float64), - binning_x=0, - binning_y=0, - roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), - ) + image = Image.decode(image.encode()) + camera = CameraInfo(width=400, height=400, k=[400, 0, 200, 0, 400, 200, 0, 0, 1]) tf = TransformStamped( - header=Header(frame_id="world", stamp=Time(sec=0, nanosec=0)), + header=Header(frame_id="world"), child_frame_id="camera", - transform=Transform( - translation=Vector3(x=2, y=0.0, z=0.0), rotation=Quaternion(w=1, x=0.0, y=0.0, z=0.0) - ), + transform=Transform(translation=Vector3(x=2), rotation=Quaternion(w=1)), ) found = detect_markers_in_image( image, @@ -66,7 +51,7 @@ def main() -> None: aruco_dictionary="DICT_4X4_50", ) assert len(found) == 1 - wire = cdr_decode(cdr_encode(found[0].to_detection3d_msg()), Detection3D) + wire = Detection3D.decode(found[0].to_detection3d_msg().encode()) assert wire.id == "7" assert wire.results[0].hypothesis.class_id == "DICT_4X4_50:7" assert wire.header.stamp == header.stamp @@ -83,14 +68,14 @@ def main() -> None: emit_empty_frames=True, ) arrays = list(MarkersPerFrame()(detector(iter([observation])))) - decoded_array = cdr_decode(cdr_encode(arrays[0].data), Detection3DArray) + decoded_array = Detection3DArray.decode(arrays[0].data.encode()) assert len(decoded_array.detections) == 1 assert decoded_array.header.stamp == image.header.stamp print("Memory stream: image → marker observation → generated CDR array") publisher = MarkerTfModule() transforms: list[TFMessage] = [] unsubscribe = publisher.tf.subscribe( - lambda msg: transforms.append(cdr_decode(cdr_encode(msg), TFMessage)) + lambda msg: transforms.append(TFMessage.decode(msg.encode())) ) try: publisher._process_detections(decoded_array) diff --git a/examples/message-codegen/demo_base_transport.py b/examples/message-codegen/demo_base_transport.py index 0a202253f76..057b10ecd8f 100644 --- a/examples/message-codegen/demo_base_transport.py +++ b/examples/message-codegen/demo_base_transport.py @@ -22,9 +22,7 @@ import uuid from demo_pubsub import free_port -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist, Vector3 -from dimos_generated.std_msgs.msg import Header from dimos.core.transport import LCMTransport, PubSubTransport, ZenohTransport from dimos.hardware.drive_trains.transport.adapter import TransportTwistAdapter @@ -70,20 +68,14 @@ def transport(topic: str, message_type: type, peer: int = 0) -> Any: def collect(message: Twist) -> None: received.append(message) - ( - stopped - if message - == Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) - else moving - ).set() + (stopped if message == Twist() else moving).set() stack.callback(commands.subscribe(collect)) source = PoseStamped( pose=Pose( - position=Point(x=2.0, y=-1.0, z=0.0), - orientation=Quaternion(z=math.sqrt(0.5), w=math.sqrt(0.5), x=0.0, y=0.0), - ), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + position=Point(x=2.0, y=-1.0), + orientation=Quaternion(z=math.sqrt(0.5), w=math.sqrt(0.5)), + ) ) def feedback_received() -> bool: @@ -101,9 +93,7 @@ def send_command() -> None: assert adapter.write_velocities([0.5, -0.2, 0.3]) retry_until(moving, send_command, timeout=5) - assert received[0] == Twist( - linear=Vector3(x=0.5, y=-0.2, z=0.0), angular=Vector3(z=0.3, x=0.0, y=0.0) - ) + assert received[0] == Twist(linear=Vector3(x=0.5, y=-0.2), angular=Vector3(z=0.3)) adapter.write_enable(False) assert stopped.wait(5), "Disabling the adapter did not deliver a generated stop command" assert adapter.read_velocities() == [0.0, 0.0, 0.0] diff --git a/examples/message-codegen/demo_bbox_navigation.py b/examples/message-codegen/demo_bbox_navigation.py index b2fab33cf34..5137c1642d4 100644 --- a/examples/message-codegen/demo_bbox_navigation.py +++ b/examples/message-codegen/demo_bbox_navigation.py @@ -17,7 +17,7 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import PoseStamped -from dimos_generated.sensor_msgs.msg import CameraInfo, RegionOfInterest +from dimos_generated.sensor_msgs.msg import CameraInfo from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import ( BoundingBox2D, @@ -26,8 +26,6 @@ Point2D, Pose2D, ) -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode -import numpy as np from dimos.core.transport import LCMTransport from dimos.navigation.bbox_navigation import BBoxNavigationModule @@ -42,46 +40,22 @@ def main() -> None: ready = Event() received = Event() unsubscribe = module.goal_request.subscribe( - lambda value: ( - goals.append(cdr_decode(cdr_encode(value), PoseStamped)), - received.set(), - ) + lambda value: (goals.append(PoseStamped.decode(value.encode())), received.set()) ) message = Detection2DArray( header=Header(frame_id="base_link", stamp=Time(sec=1700000000, nanosec=123456789)), - detections=[ - Detection2D( - bbox=BoundingBox2D( - center=Pose2D(position=Point2D(x=420, y=290), theta=0.0), size_x=0.0, size_y=0.0 - ), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - results=[], - id="", - ) - ], + detections=[Detection2D(bbox=BoundingBox2D(center=Pose2D(position=Point2D(x=420, y=290))))], ) try: module.start() module._on_detection(message) assert not goals - camera = CameraInfo( - k=np.array([500, 0, 320, 0, 250, 240, 0, 0, 1], dtype=np.float64), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - height=0, - width=0, - distortion_model="", - d=np.array([], dtype=np.float64), - r=np.zeros(9, dtype=np.float64), - p=np.zeros(12, dtype=np.float64), - binning_x=0, - binning_y=0, - roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), - ) + camera = CameraInfo(k=[500, 0, 320, 0, 250, 240, 0, 0, 1]) camera_unsubscribe = module.camera_info.subscribe(lambda _: ready.set()) - module.camera_info.transport.publish(cdr_decode(cdr_encode(camera), CameraInfo)) + module.camera_info.transport.publish(CameraInfo.decode(camera.encode())) assert ready.wait(2) camera_unsubscribe() - module.detection2d.transport.publish(cdr_decode(cdr_encode(message), Detection2DArray)) + module.detection2d.transport.publish(Detection2DArray.decode(message.encode())) assert received.wait(2) assert len(goals) == 1 goal = goals[0] @@ -91,11 +65,7 @@ def main() -> None: f"CDR goal: x={goal.pose.position.x:.2f}, y={goal.pose.position.y:.2f}, z={goal.pose.position.z:.2f} m" ) print("PASS: LCM calibration + bbox → generated goal with exact source header") - module._on_detection( - Detection2DArray( - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), detections=[] - ) - ) + module._on_detection(Detection2DArray()) assert len(goals) == 1 finally: unsubscribe() diff --git a/examples/message-codegen/demo_blueprint.py b/examples/message-codegen/demo_blueprint.py index 0df46e565f6..42e33a3f5a7 100644 --- a/examples/message-codegen/demo_blueprint.py +++ b/examples/message-codegen/demo_blueprint.py @@ -26,12 +26,9 @@ from unittest.mock import patch import uuid -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.dimos_msgs.msg import LineSegment3D, LineSegments3D from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.sensor_msgs.msg import Image -from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.core.coordination.blueprints import Blueprint, autoconnect @@ -86,12 +83,7 @@ def exchange(self, sample: int) -> str: self._image = None self._received.clear() lines = LineSegments3D( - segments=[ - LineSegment3D( - start=Point(x=sample, y=0.0, z=0.0), end=Point(y=2, x=0.0, z=0.0), weight=sample - ) - ], - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + segments=[LineSegment3D(start=Point(x=sample), end=Point(y=2), weight=sample)] ) lines.header.stamp = time_from_nanoseconds(self._stamp) lines.header.frame_id = "map" @@ -101,17 +93,11 @@ def exchange(self, sample: int) -> str: step=1920, encoding="rgb8", data=np.full(640 * 480 * 3, sample % 256, dtype=np.uint8), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - is_bigendian=0, ) image.header.stamp = time_from_nanoseconds(self._stamp) image.header.frame_id = "camera" pose = PoseStamped( - header=lines.header, - pose=Pose( - position=Point(x=sample, y=0.0, z=0.0), - orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), - ), + header=lines.header, pose=Pose(position=Point(x=sample), orientation=Quaternion(w=1)) ) for _ in range(60): self.p0.publish(pose) @@ -124,15 +110,13 @@ def exchange(self, sample: int) -> str: f"Missing native relay reply for sample {sample}: " f"lines={self._lines is not None}, image={self._image is not None}" ) - expected = cdr_decode(cdr_encode(lines), LineSegments3D) + expected = LineSegments3D.decode(lines.encode()) expected.segments = [ - LineSegment3D( - start=Point(x=sample, y=0.0, z=0.0), end=Point(y=2, x=0.0, z=0.0), weight=sample + 2 - ) + LineSegment3D(start=Point(x=sample), end=Point(y=2), weight=sample + 2) ] - if cdr_encode(self._lines) != cdr_encode(expected): + if self._lines.encode() != expected.encode(): raise ValueError("Native custom message reply differs from the expected edits") - if cdr_encode(self._image) != cdr_encode(image): + if self._image.encode() != image.encode(): raise ValueError("Native image reply changed pixels or metadata") return ( f"sample {sample}: Python weight={sample} → C++ {sample + 1} → Rust {sample + 2}; " diff --git a/examples/message-codegen/demo_blueprint_recording.py b/examples/message-codegen/demo_blueprint_recording.py index 8d05adfb276..82986eb6dd2 100644 --- a/examples/message-codegen/demo_blueprint_recording.py +++ b/examples/message-codegen/demo_blueprint_recording.py @@ -28,7 +28,6 @@ from dimos_generated.dimos_msgs.msg import LineSegments3D from dimos_generated.geometry_msgs.msg import PoseStamped from dimos_generated.sensor_msgs.msg import Image -from dimos_message_build.registry import encode as cdr_encode from mcap.reader import make_reader import numpy as np from rosbags.typesys import Stores, get_types_from_msg, get_typestore diff --git a/examples/message-codegen/demo_camera_bridge.py b/examples/message-codegen/demo_camera_bridge.py index 973d3fd4af6..5f340f34027 100644 --- a/examples/message-codegen/demo_camera_bridge.py +++ b/examples/message-codegen/demo_camera_bridge.py @@ -17,9 +17,8 @@ from pathlib import Path from types import SimpleNamespace -from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseWithCovariance, Quaternion, Vector3 -from dimos_generated.sensor_msgs.msg import CameraInfo, CompressedImage, RegionOfInterest +from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion, Vector3 +from dimos_generated.sensor_msgs.msg import CameraInfo, CompressedImage from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import ( BoundingBox3D, @@ -28,7 +27,6 @@ ObjectHypothesis, ObjectHypothesisWithPose, ) -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import rerun as rr @@ -45,35 +43,16 @@ def main() -> None: bridge._min_intervals = {} bridge._camera_infos = {} bridge._image_entities = set() - header = Header(frame_id="camera_optical", stamp=Time(sec=0, nanosec=0)) + header = Header(frame_id="camera_optical") pixels = np.zeros((120, 160, 3), dtype=np.uint8) pixels[:, :80, 0] = 255 pixels[:, 80:, 1] = 255 color = image_from_array(pixels, encoding="rgb8", header=header) - info = CameraInfo( - header=header, - width=160, - height=120, - k=np.array([100, 0, 80, 0, 100, 60, 0, 0, 1], dtype=np.float64), - distortion_model="", - d=np.array([], dtype=np.float64), - r=np.zeros(9, dtype=np.float64), - p=np.zeros(12, dtype=np.float64), - binning_x=0, - binning_y=0, - roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), - ) + info = CameraInfo(header=header, width=160, height=120, k=[100, 0, 80, 0, 100, 60, 0, 0, 1]) messages = [ ("color", color), ("camera_info", info), - ( - "jpeg", - CompressedImage( - header=header, - format="jpeg", - data=np.frombuffer(image_to_jpeg(color), dtype=np.uint8), - ), - ), + ("jpeg", CompressedImage(header=header, format="jpeg", data=image_to_jpeg(color))), ( "depth_mm", image_from_array( @@ -93,25 +72,14 @@ def main() -> None: Detection3D( id="4", bbox=BoundingBox3D( - center=Pose( - position=Point(z=1, x=0.0, y=0.0), - orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), - ), + center=Pose(position=Point(z=1), orientation=Quaternion(w=1)), size=Vector3(x=0.5, y=0.5, z=0.2), ), results=[ ObjectHypothesisWithPose( - hypothesis=ObjectHypothesis(class_id="demo-box", score=1), - pose=PoseWithCovariance( - pose=Pose( - position=Point(x=0.0, y=0.0, z=0.0), - orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), - ), - covariance=np.zeros(36, dtype=np.float64), - ), + hypothesis=ObjectHypothesis(class_id="demo-box", score=1) ) ], - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), ) ], ) @@ -119,7 +87,7 @@ def main() -> None: try: for name, value in messages: bridge._on_message( - cdr_decode(cdr_encode(value), type(value)), SimpleNamespace(name="/camera/" + name) + type(value).decode(value.encode()), SimpleNamespace(name="/camera/" + name) ) print(f"CDR {type(value).__name__} → world/camera/{name}") finally: diff --git a/examples/message-codegen/demo_camera_mux_cdr.py b/examples/message-codegen/demo_camera_mux_cdr.py index e97679179da..8ba87f9aefb 100644 --- a/examples/message-codegen/demo_camera_mux_cdr.py +++ b/examples/message-codegen/demo_camera_mux_cdr.py @@ -18,7 +18,6 @@ from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.core.module import Module @@ -47,8 +46,8 @@ def main() -> None: encoding="rgb8", header=Header(stamp=time_from_nanoseconds(stamp_ns + index), frame_id=camera), ) - mux._on_cam(camera, cdr_decode(cdr_encode(image), Image)) - output = cdr_decode(cdr_encode(mux.mux_image.publish.call_args.args[0]), Image) + mux._on_cam(camera, Image.decode(image.encode())) + output = Image.decode(mux.mux_image.publish.call_args.args[0].encode()) assert output.width == 100 and output.height == 36 assert to_nanoseconds(output.header.stamp) == stamp_ns + 1 assert output.header.frame_id == "camera_mux" diff --git a/examples/message-codegen/demo_cloud_filters.py b/examples/message-codegen/demo_cloud_filters.py index 8748dcbad4f..de8366f8bcd 100644 --- a/examples/message-codegen/demo_cloud_filters.py +++ b/examples/message-codegen/demo_cloud_filters.py @@ -16,11 +16,9 @@ from typing import cast -from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 -from dimos_generated.sensor_msgs.msg import CameraInfo, PointCloud2, RegionOfInterest +from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped +from dimos_generated.sensor_msgs.msg import CameraInfo, PointCloud2 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.pointcloud import pointcloud_from_xyz @@ -35,40 +33,15 @@ def main() -> None: points = np.random.default_rng(42).normal(scale=0.05, size=(100, 3)) points[:, 2] += 2 points = np.vstack((points, [10, 10, -1])) - cloud = pointcloud_from_xyz( - points, header=Header(frame_id="world", stamp=Time(sec=0, nanosec=0)) - ) - cloud = cdr_decode(cdr_encode(cloud), PointCloud2) - transform = TransformStamped( - transform=Transform( - rotation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), translation=Vector3(x=0.0, y=0.0, z=0.0) - ), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - child_frame_id="", - ) + cloud = pointcloud_from_xyz(points, header=Header(frame_id="world")) + cloud = PointCloud2.decode(cloud.encode()) + transform = TransformStamped(transform=Transform(rotation=Quaternion(w=1))) # These geometric filters do not inspect the detection argument. detection = cast("Detection2DBBox", None) for name, operation in (("height", height_filter()), ("radius", radius_outlier())): - result = operation( - detection, - cloud, - CameraInfo( - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - height=0, - width=0, - distortion_model="", - d=np.array([], dtype=np.float64), - k=np.zeros(9, dtype=np.float64), - r=np.zeros(9, dtype=np.float64), - p=np.zeros(12, dtype=np.float64), - binning_x=0, - binning_y=0, - roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), - ), - transform, - ) + result = operation(detection, cloud, CameraInfo(), transform) assert result is not None - result = cdr_decode(cdr_encode(result), PointCloud2) + result = PointCloud2.decode(result.encode()) assert result.width == 100 and result.header == cloud.header print(f"{name}: 101 input points → {result.width} retained points; source header preserved") print("PASS: generated clouds survive filtering and CDR round trips") diff --git a/examples/message-codegen/demo_command_center.py b/examples/message-codegen/demo_command_center.py index 284aab0203d..1732391893e 100644 --- a/examples/message-codegen/demo_command_center.py +++ b/examples/message-codegen/demo_command_center.py @@ -17,12 +17,8 @@ import asyncio import json -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid, Path -from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode -import numpy as np from dimos.web.websocket_vis.websocket_vis_module import WebsocketVisModule @@ -31,49 +27,24 @@ def main() -> None: module = WebsocketVisModule() goals: list[PoseStamped] = [] unsubscribe = module.goal_request.subscribe( - lambda value: goals.append(cdr_decode(cdr_encode(value), PoseStamped)) + lambda value: goals.append(PoseStamped.decode(value.encode())) ) try: module._create_server() - pose = PoseStamped( - pose=Pose( - position=Point(x=2, y=3, z=0.0), orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0) - ), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - ) - module._on_robot_pose(cdr_decode(cdr_encode(pose), PoseStamped)) - path = Path( - poses=[ - pose, - PoseStamped( - pose=Pose( - position=Point(x=5, y=3, z=0.0), - orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), - ), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - ), - ], - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - ) - module._on_path(cdr_decode(cdr_encode(path), Path)) + pose = PoseStamped(pose=Pose(position=Point(x=2, y=3), orientation=Quaternion(w=1))) + module._on_robot_pose(PoseStamped.decode(pose.encode())) + path = Path(poses=[pose, PoseStamped(pose=Pose(position=Point(x=5, y=3)))]) + module._on_path(Path.decode(path.encode())) grid = OccupancyGrid( info=MapMetaData( - width=2, - height=2, - resolution=1, - origin=Pose( - orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), - position=Point(x=0.0, y=0.0, z=0.0), - ), - map_load_time=Time(sec=0, nanosec=0), + width=2, height=2, resolution=1, origin=Pose(orientation=Quaternion(w=1)) ), - data=np.array([100, 0, 0, -1], dtype=np.int8), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + data=[100, 0, 0, -1], ) - module._on_global_costmap(cdr_decode(cdr_encode(grid), OccupancyGrid)) + module._on_global_costmap(OccupancyGrid.decode(grid.encode())) assert module.sio is not None asyncio.run(module.sio.handlers["/"]["click"]("demo", [5, 3])) - assert goals[0].pose.position == Point(x=5, y=3, z=0.0) + assert goals[0].pose.position == Point(x=5, y=3) assert goals[0].header.frame_id == "world" print("Command-center state from CDR pose, path, and costmap:") print(json.dumps(module.vis_state, indent=2)) diff --git a/examples/message-codegen/demo_coordinator_joints.py b/examples/message-codegen/demo_coordinator_joints.py index fe5eb508291..03749906c6e 100644 --- a/examples/message-codegen/demo_coordinator_joints.py +++ b/examples/message-codegen/demo_coordinator_joints.py @@ -18,7 +18,6 @@ import threading from dimos_generated.sensor_msgs.msg import JointState -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.control.components import HardwareComponent, HardwareType from dimos.control.coordinator import ControlCoordinator @@ -72,7 +71,7 @@ def receive(port: str, message: JointState) -> None: assert list(complete["right_arm_joints"].position) == [0.3, 0.4] assert len(complete["coordinator_joint_state"].position) == 4 for port, message in complete.items(): - assert cdr_decode(cdr_encode(message), JointState) == message + assert JointState.decode(message.encode()) == message print( f"{port}: frame={message.header.frame_id}, names={list(message.name)}, q={list(message.position)}, stamp={to_nanoseconds(message.header.stamp)}" ) diff --git a/examples/message-codegen/demo_detection_bbox.py b/examples/message-codegen/demo_detection_bbox.py index 74f1df382fa..43a9b92bd98 100644 --- a/examples/message-codegen/demo_detection_bbox.py +++ b/examples/message-codegen/demo_detection_bbox.py @@ -20,7 +20,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection2DArray -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.image import image_from_array, image_view @@ -46,7 +45,7 @@ def main() -> None: image=source, ) collection = ImageDetections2D(image=source, detections=[detection]) - array = cdr_decode(cdr_encode(collection.to_ros_detection2d_array()), Detection2DArray) + array = Detection2DArray.decode(collection.to_ros_detection2d_array().encode()) wire = array.detections[0] assert array.header == source.header assert wire.header == source.header diff --git a/examples/message-codegen/demo_detection_projection.py b/examples/message-codegen/demo_detection_projection.py index aed4e012103..78b58d18bc0 100644 --- a/examples/message-codegen/demo_detection_projection.py +++ b/examples/message-codegen/demo_detection_projection.py @@ -22,9 +22,8 @@ TransformStamped, Vector3, ) -from dimos_generated.sensor_msgs.msg import CameraInfo, Image, RegionOfInterest +from dimos_generated.sensor_msgs.msg import CameraInfo, Image from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.image import image_from_array @@ -37,7 +36,7 @@ def main() -> None: depth = image_from_array( np.full((4, 4), 2000, dtype=np.uint16), encoding="16UC1", header=header ) - depth = cdr_decode(cdr_encode(depth), Image) + depth = Image.decode(depth.encode()) detection = Detection2DBBox( bbox=(0, 0, 3, 3), track_id=1, @@ -47,29 +46,15 @@ def main() -> None: ts=1700000000.0, image=depth, ) - camera = CameraInfo( - width=4, - height=4, - k=np.array([2, 0, 0, 0, 2, 0, 0, 0, 1], dtype=np.float64), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - distortion_model="", - d=np.array([], dtype=np.float64), - r=np.zeros(9, dtype=np.float64), - p=np.zeros(12, dtype=np.float64), - binning_x=0, - binning_y=0, - roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), - ) + camera = CameraInfo(width=4, height=4, k=[2, 0, 0, 0, 2, 0, 0, 0, 1]) transform = TransformStamped( - header=Header(frame_id="camera", stamp=Time(sec=0, nanosec=0)), + header=Header(frame_id="camera"), child_frame_id="world", - transform=Transform( - translation=Vector3(x=-10, y=0.0, z=0.0), rotation=Quaternion(w=1, x=0.0, y=0.0, z=0.0) - ), + transform=Transform(translation=Vector3(x=-10), rotation=Quaternion(w=1)), ) result = Detection3DPC.from_depth(detection, depth, camera, transform, filters=[]) assert result is not None - pose = cdr_decode(cdr_encode(result.pose), PoseStamped) + pose = PoseStamped.decode(result.pose.encode()) assert pose.header.stamp == header.stamp assert pose.header.frame_id == "world" assert (pose.pose.position.x, pose.pose.position.y, pose.pose.position.z) == (11.5, 1.5, 2) diff --git a/examples/message-codegen/demo_export_detection_fixture.py b/examples/message-codegen/demo_export_detection_fixture.py index ccdcdc51e31..ae6a3ad0980 100644 --- a/examples/message-codegen/demo_export_detection_fixture.py +++ b/examples/message-codegen/demo_export_detection_fixture.py @@ -25,7 +25,6 @@ from dimos_generated.geometry_msgs.msg import PoseStamped from dimos_generated.sensor_msgs.msg import Image, PointCloud2 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from numpy.core.multiarray import _reconstruct @@ -145,13 +144,13 @@ def nearest(kind: str, target: float) -> tuple[float, Path, Any]: np.testing.assert_array_equal(image_view(msg), value.data) else: msg = pose_from_webrtc_odometry(value) - data = cdr_encode(msg) - assert cdr_encode(cdr_decode(data, type(msg))) == data + data = msg.encode() + assert type(msg).decode(data).encode() == data name = f"{seek}-{kind}.cdr" (out / name).write_bytes(data) entry["streams"][kind] = { "file": name, - "msg_name": msg.__msgtype__, + "msg_name": msg.msg_name, "recorded_ts": ts, "source": str(p.relative_to(root)), "source_sha256": hashlib.sha256(p.read_bytes()).hexdigest(), diff --git a/examples/message-codegen/demo_frontiers.py b/examples/message-codegen/demo_frontiers.py index 3b2b9e8a3b6..c19734d33f5 100644 --- a/examples/message-codegen/demo_frontiers.py +++ b/examples/message-codegen/demo_frontiers.py @@ -17,10 +17,9 @@ from pathlib import Path from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion +from dimos_generated.geometry_msgs.msg import Pose, PoseStamped, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.memory.vis.space.space import Space @@ -37,27 +36,19 @@ def main() -> None: grid = OccupancyGrid( header=header, info=MapMetaData( - width=20, - height=20, - resolution=0.5, - origin=Pose( - orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), - position=Point(x=0.0, y=0.0, z=0.0), - ), - map_load_time=Time(sec=0, nanosec=0), + width=20, height=20, resolution=0.5, origin=Pose(orientation=Quaternion(w=1)) ), - data=np.asarray(cells.ravel(), dtype=np.int8), + data=cells.ravel(), ) explorer = WavefrontFrontierExplorer() try: - received = cdr_decode(cdr_encode(grid), OccupancyGrid) + received = OccupancyGrid.decode(grid.encode()) frontiers = explorer.detect_frontiers(grid_to_world(received, (5, 10)), received) assert len(frontiers) == 1 goal = PoseStamped( - header=received.header, - pose=Pose(position=frontiers[0], orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0)), + header=received.header, pose=Pose(position=frontiers[0], orientation=Quaternion(w=1)) ) - decoded = cdr_decode(cdr_encode(goal), PoseStamped) + decoded = PoseStamped.decode(goal.encode()) assert decoded.header == header assert decoded.pose.position.x == 5 and decoded.pose.position.y == 4.75 output = Path("build/message-codegen/demo/evidence/frontiers.svg") diff --git a/examples/message-codegen/demo_g1_messages.py b/examples/message-codegen/demo_g1_messages.py index 4815ea28616..61ef5e7ea46 100644 --- a/examples/message-codegen/demo_g1_messages.py +++ b/examples/message-codegen/demo_g1_messages.py @@ -19,7 +19,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.time import to_nanoseconds from dimos.robot.unitree.g1.wholebody_connection import G1LowStateSnapshot, G1WholeBodyConnection @@ -53,7 +52,7 @@ def main() -> None: assert list(state.position) == [index * 0.1] * 29 assert orientation.orientation.w == 0.8 and orientation.orientation.z == 0.6 for message in (state, orientation): - assert cdr_decode(cdr_encode(message), type(message)) == message + assert type(message).decode(message.encode()) == message print( f"G1 sample {index}: joints={len(state.name)}, q0={state.position[0]:.1f}, IMU xyzw=(0,0,0.6,0.8), stamp={to_nanoseconds(state.header.stamp)}" ) diff --git a/examples/message-codegen/demo_galaxea_messages.py b/examples/message-codegen/demo_galaxea_messages.py index 5424c32c5ec..e83894638ff 100644 --- a/examples/message-codegen/demo_galaxea_messages.py +++ b/examples/message-codegen/demo_galaxea_messages.py @@ -22,7 +22,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.time import to_nanoseconds from dimos.robot.galaxea.r1pro.connection import R1ProConnection @@ -51,12 +50,9 @@ def receive(name: str, message: Any) -> None: robot._on_chassis_speed( TwistStamped( header=Header( - stamp=Time(sec=1700000000, nanosec=123456789 + index * 100000000), - frame_id="", - ), - twist=Twist( - linear=Vector3(x=1.0, y=0.0, z=0.0), angular=Vector3(z=0.2, x=0.0, y=0.0) + stamp=Time(sec=1700000000, nanosec=123456789 + index * 100000000) ), + twist=Twist(linear=Vector3(x=1.0), angular=Vector3(z=0.2)), ), None, ) @@ -68,7 +64,7 @@ def receive(name: str, message: Any) -> None: assert all(to_nanoseconds(edge.header.stamp) == stamp for edge in tf.transforms) assert math.isclose(pose.pose.orientation.z, math.sin(index * 0.01)) for message in (pose, odometry, tf): - assert cdr_decode(cdr_encode(message), type(message)) == message + assert type(message).decode(message.encode()) == message print( f"tick {index}: x={pose.pose.position.x:.6f}, y={pose.pose.position.y:.6f}, stamp={stamp}" ) diff --git a/examples/message-codegen/demo_go2_command_cdr.py b/examples/message-codegen/demo_go2_command_cdr.py index 434221c9f34..fc053c0b9cc 100644 --- a/examples/message-codegen/demo_go2_command_cdr.py +++ b/examples/message-codegen/demo_go2_command_cdr.py @@ -19,7 +19,6 @@ from dimos_generated.geometry_msgs.msg import PoseStamped, Twist, TwistStamped, Vector3 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.core.module import Module from dimos.msgs.time import time_from_nanoseconds @@ -37,15 +36,15 @@ def main() -> None: stamp_ns = time.time_ns() - 100_000_000 for offset in (0, 1): message = TwistStamped( - header=Header(stamp=time_from_nanoseconds(stamp_ns + offset), frame_id=""), - twist=Twist(linear=Vector3(x=99, y=0.0, z=0.0), angular=Vector3(z=-50, x=0.0, y=0.0)), + header=Header(stamp=time_from_nanoseconds(stamp_ns + offset)), + twist=Twist(linear=Vector3(x=99), angular=Vector3(z=-50)), ) - module._on_cmd_vel_in(cdr_decode(cdr_encode(message), TwistStamped)) + module._on_cmd_vel_in(TwistStamped.decode(message.encode())) assert module.tele_cmd_vel.publish.call_count == 2 - command = cdr_decode(cdr_encode(module.tele_cmd_vel.publish.call_args.args[0]), Twist) + command = Twist.decode(module.tele_cmd_vel.publish.call_args.args[0].encode()) assert command.linear.x == 1.5 and command.angular.z == -2 module._handle_nav_goal({"x": 2.5, "y": -1, "nonce": 1}) - goal = cdr_decode(cdr_encode(module.goal_request.publish.call_args.args[0]), PoseStamped) + goal = PoseStamped.decode(module.goal_request.publish.call_args.args[0].encode()) assert goal.header.frame_id == "world" and goal.pose.position.x == 2.5 module._estopped = True module._on_cmd_vel_in(message) diff --git a/examples/message-codegen/demo_grasp_proposals.py b/examples/message-codegen/demo_grasp_proposals.py index cdfeb4af32d..3f2a0c99f94 100644 --- a/examples/message-codegen/demo_grasp_proposals.py +++ b/examples/message-codegen/demo_grasp_proposals.py @@ -18,7 +18,6 @@ from dimos_generated.dimos_msgs.msg import GraspCandidateArray from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.manipulation.grasping.heuristic_grasp import HeuristicGraspModule @@ -38,9 +37,9 @@ def main() -> None: ) provider = HeuristicGraspModule() try: - proposals = provider.propose_grasps(cdr_decode(cdr_encode(cloud), PointCloud2)) - payload = cdr_encode(proposals) - received = cdr_decode(payload, GraspCandidateArray) + proposals = provider.propose_grasps(PointCloud2.decode(cloud.encode())) + payload = proposals.encode() + received = GraspCandidateArray.decode(payload) assert received.header == cloud.header assert len(received.candidates) == 1 candidate = received.candidates[0] diff --git a/examples/message-codegen/demo_grid_path.py b/examples/message-codegen/demo_grid_path.py index 03b7345515b..e82637cbe13 100644 --- a/examples/message-codegen/demo_grid_path.py +++ b/examples/message-codegen/demo_grid_path.py @@ -20,10 +20,9 @@ from pathlib import Path as FilePath from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion +from dimos_generated.geometry_msgs.msg import Pose, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid, Path from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.mapping.occupancy.path_mask import make_path_mask @@ -43,18 +42,11 @@ def main() -> None: grid = OccupancyGrid( header=header, info=MapMetaData( - width=40, - height=40, - resolution=0.25, - origin=Pose( - orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), - position=Point(x=0.0, y=0.0, z=0.0), - ), - map_load_time=Time(sec=0, nanosec=0), + width=40, height=40, resolution=0.25, origin=Pose(orientation=Quaternion(w=1)) ), - data=np.asarray(cells.ravel(), dtype=np.int8), + data=cells.ravel(), ) - received = cdr_decode(cdr_encode(grid), OccupancyGrid) + received = OccupancyGrid.decode(grid.encode()) start = grid_to_world(received, (5, 5)) goal = grid_to_world(received, (35, 35)) output_dir = FilePath("build/message-codegen/demo/evidence") @@ -63,15 +55,8 @@ def main() -> None: name = "cpp" if use_cpp else "python" path = min_cost_astar(received, goal, start, use_cpp=use_cpp) assert path is not None - resampled = simple_resample_path( - path, - Pose( - orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), - position=Point(x=0.0, y=0.0, z=0.0), - ), - 0.1, - ) - decoded = cdr_decode(cdr_encode(resampled), Path) + resampled = simple_resample_path(path, Pose(orientation=Quaternion(w=1)), 0.1) + decoded = Path.decode(resampled.encode()) assert decoded.header == header assert all(pose.header == header for pose in decoded.poses) mask = make_path_mask(received, decoded, 0.1) diff --git a/examples/message-codegen/demo_habitat_native.py b/examples/message-codegen/demo_habitat_native.py index 02a81c6d126..587be189c71 100644 --- a/examples/message-codegen/demo_habitat_native.py +++ b/examples/message-codegen/demo_habitat_native.py @@ -19,11 +19,10 @@ from pathlib import Path import sys -from dimos_generated.geometry_msgs.msg import Twist, Vector3 +from dimos_generated.geometry_msgs.msg import Twist from dimos_generated.nav_msgs.msg import Odometry from dimos_generated.sensor_msgs.msg import CameraInfo, Image, PointCloud2 from dimos_generated.tf2_msgs.msg import TFMessage -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np root = Path(__file__).resolve().parents[2] @@ -77,22 +76,14 @@ ), } for name, (message_type, payload) in payloads.items(): - value = cdr_decode(payload, message_type) + value = message_type.decode(payload) header = value.transforms[0].header if name == "tf" else value.header assert header.stamp.sec == 12 and header.stamp.nanosec == 250000000 (output / (name + ".cdr")).write_bytes(payload) -assert cdr_decode(payloads["odometry"][1], Odometry).pose.pose.position.x == 1 -assert cdr_decode(payloads["cloud"][1], PointCloud2).row_step == 16 -assert cdr_decode(payloads["tf"][1], TFMessage).transforms[1].transform.translation.z == 0.45 -assert ( - cdr_decode( - cdr_encode( - Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) - ), - Twist, - ).linear.x - == 0 -) +assert Odometry.decode(payloads["odometry"][1]).pose.pose.position.x == 1 +assert PointCloud2.decode(payloads["cloud"][1]).row_step == 16 +assert TFMessage.decode(payloads["tf"][1]).transforms[1].transform.translation.z == 0.45 +assert Twist.decode(Twist().encode()).linear.x == 0 print( json.dumps( { diff --git a/examples/message-codegen/demo_holonomic_path.py b/examples/message-codegen/demo_holonomic_path.py index 22b102655bf..ebcec9fd6dc 100644 --- a/examples/message-codegen/demo_holonomic_path.py +++ b/examples/message-codegen/demo_holonomic_path.py @@ -17,11 +17,9 @@ import math import time -from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist, Vector3 +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist from dimos_generated.nav_msgs.msg import Path from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.time import time_from_nanoseconds from dimos.navigation.dannav.holonomic_tc.module import DanHolonomicTCConfig, _HolonomicPathFollower @@ -32,12 +30,12 @@ def main() -> None: core = _HolonomicPathFollower( DanHolonomicTCConfig(speed_m_s=1.2, control_frequency=60.0, goal_tolerance=0.08) ) - command = Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + command = Twist() stopped: list[str] = [] def receive(value: Twist) -> None: nonlocal command - command = cdr_decode(cdr_encode(value), Twist) + command = Twist.decode(value.encode()) subscription = core.cmd_vel.subscribe(receive) stop_subscription = core.stopped_navigating.subscribe(stopped.append) @@ -51,22 +49,16 @@ def odometry(tick: int) -> PoseStamped: stamp=time_from_nanoseconds(1700000000000000000 + round(tick * dt * 1e9)), ), pose=Pose( - position=Point(x=x, y=y, z=0.0), - orientation=Quaternion(z=math.sin(yaw / 2), w=math.cos(yaw / 2), x=0.0, y=0.0), + position=Point(x=x, y=y), + orientation=Quaternion(z=math.sin(yaw / 2), w=math.cos(yaw / 2)), ), ) - return cdr_decode(cdr_encode(value), PoseStamped) + return PoseStamped.decode(value.encode()) path = Path( - header=Header(frame_id="map", stamp=Time(sec=0, nanosec=0)), + header=Header(frame_id="map"), poses=[ - PoseStamped( - pose=Pose( - position=Point(x=px, y=0.0, z=0.0), - orientation=Quaternion(w=1.0, x=0.0, y=0.0, z=0.0), - ), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - ) + PoseStamped(pose=Pose(position=Point(x=px), orientation=Quaternion(w=1.0))) for px in (0.1, 1.0) ], ) @@ -75,14 +67,14 @@ def odometry(tick: int) -> PoseStamped: DanLocalPlannerConfig(lock_replan=0.5, resample_spacing_m=0.1, smoothing_window=3) ) gate.on_odom(odometry(0)) - committed = gate.on_planner_path(cdr_decode(cdr_encode(path), Path)) + committed = gate.on_planner_path(Path.decode(path.encode())) assert committed is not None - assert gate.on_planner_path(cdr_decode(cdr_encode(path), Path)) is None + assert gate.on_planner_path(Path.decode(path.encode())) is None print( f"Local planner committed {len(committed.poses)} resampled poses; duplicate replan held" ) core.handle_odom(odometry(0)) - core.start_planning(cdr_decode(cdr_encode(committed), Path)) + core.start_planning(Path.decode(committed.encode())) for tick in range(300): if stopped: break diff --git a/examples/message-codegen/demo_holonomic_tracking.py b/examples/message-codegen/demo_holonomic_tracking.py index 37210ee175a..097e7c4d166 100644 --- a/examples/message-codegen/demo_holonomic_tracking.py +++ b/examples/message-codegen/demo_holonomic_tracking.py @@ -16,8 +16,7 @@ import math -from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion, Twist, Vector3 -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode +from dimos_generated.geometry_msgs.msg import Point, Pose, Quaternion, Twist from dimos.navigation.dannav.holonomic_tc.command_limits import ( HolonomicCommandLimits, @@ -36,23 +35,15 @@ def main() -> None: limits = HolonomicCommandLimits(1.0, 1.0, 2.0, 2.0) controller = HolonomicTrackingController(k_position_per_s=2.0, k_yaw_per_s=1.0) controller.configure(limits) - target = Pose( - position=Point(x=2.0, y=1.0, z=0.0), orientation=Quaternion(w=1.0, x=0.0, y=0.0, z=0.0) - ) - pose = Pose( - orientation=Quaternion(w=1.0, x=0.0, y=0.0, z=0.0), position=Point(x=0.0, y=0.0, z=0.0) - ) - command = Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) + target = Pose(position=Point(x=2.0, y=1.0), orientation=Quaternion(w=1.0)) + pose = Pose(orientation=Quaternion(w=1.0)) + command = Twist() dt = 0.05 for tick in range(200): - reference = TrajectoryReferenceSample( - tick * dt, - cdr_decode(cdr_encode(target), Pose), - Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)), - ) - measured = TrajectoryMeasuredSample(tick * dt, cdr_decode(cdr_encode(pose), Pose), command) + reference = TrajectoryReferenceSample(tick * dt, Pose.decode(target.encode()), Twist()) + measured = TrajectoryMeasuredSample(tick * dt, Pose.decode(pose.encode()), command) raw = controller.control(reference, measured) - command = cdr_decode(cdr_encode(clamp_holonomic_cmd_vel(command, raw, limits, dt)), Twist) + command = Twist.decode(clamp_holonomic_cmd_vel(command, raw, limits, dt).encode()) pose.position.x += command.linear.x * dt pose.position.y += command.linear.y * dt if tick % 40 == 0: diff --git a/examples/message-codegen/demo_hosted_map.py b/examples/message-codegen/demo_hosted_map.py index 50f64b0389f..49d3858c807 100644 --- a/examples/message-codegen/demo_hosted_map.py +++ b/examples/message-codegen/demo_hosted_map.py @@ -18,11 +18,8 @@ import json from pathlib import Path -from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid -from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.geometry import quaternion_from_euler @@ -39,27 +36,13 @@ def main() -> None: cells[20:44, 20:44] = 50 cells[28:36, 28:36] = 100 grid = OccupancyGrid( - info=MapMetaData( - width=64, - height=64, - resolution=0.1, - map_load_time=Time(sec=0, nanosec=0), - origin=Pose( - position=Point(x=0.0, y=0.0, z=0.0), - orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), - ), - ), - data=np.asarray(cells.ravel(), dtype=np.int8), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + info=MapMetaData(width=64, height=64, resolution=0.1), data=cells.ravel() ) - module._on_costmap(cdr_decode(cdr_encode(grid), OccupancyGrid)) + module._on_costmap(OccupancyGrid.decode(grid.encode())) pose = PoseStamped( - pose=Pose( - position=Point(x=3.2, y=3.2, z=0.0), orientation=quaternion_from_euler(0, 0, 1.0) - ), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + pose=Pose(position=Point(x=3.2, y=3.2), orientation=quaternion_from_euler(0, 0, 1.0)) ) - module._on_odom(cdr_decode(cdr_encode(pose), PoseStamped)) + module._on_odom(PoseStamped.decode(pose.encode())) assert [value["type"] for value in payloads] == ["map", "odom"] assert payloads[1]["yaw"] == 1.0 destination = Path("build/message-codegen/demo/evidence/hosted-map.png") diff --git a/examples/message-codegen/demo_keyboard_cdr.py b/examples/message-codegen/demo_keyboard_cdr.py index e877f7639d6..51e3723eb47 100644 --- a/examples/message-codegen/demo_keyboard_cdr.py +++ b/examples/message-codegen/demo_keyboard_cdr.py @@ -14,9 +14,8 @@ """Exercise keyboard command and release events without a display or robot.""" -from dimos_generated.geometry_msgs.msg import Twist, TwistStamped, Vector3 +from dimos_generated.geometry_msgs.msg import Twist, TwistStamped from dimos_generated.std_msgs.msg import Float32 -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import pygame from dimos.teleop.keyboard.keyboard_teleop_module import KeyboardTeleopModule @@ -28,11 +27,9 @@ def main() -> None: gripper: list[Float32] = [] subscriptions = [ module.ee_twist_command.subscribe( - lambda msg: commands.append(cdr_decode(cdr_encode(msg), TwistStamped)) - ), - module.gripper_command.subscribe( - lambda msg: gripper.append(cdr_decode(cdr_encode(msg), Float32)) + lambda msg: commands.append(TwistStamped.decode(msg.encode())) ), + module.gripper_command.subscribe(lambda msg: gripper.append(Float32.decode(msg.encode()))), ] try: held = {pygame.K_w, pygame.K_a} @@ -40,9 +37,7 @@ def main() -> None: assert commands[-1].twist.linear.y == 0.05 print("Release W while A remains held → CDR velocity: left 0.05 m/s") module._handle_pygame_event(pygame.event.Event(pygame.KEYUP, key=pygame.K_a), held) - assert commands[-1].twist == Twist( - linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0) - ) + assert commands[-1].twist == Twist() print("Release final motion key → CDR velocity: all six components zero") for key in [pygame.K_LEFTBRACKET, pygame.K_RIGHTBRACKET]: module._handle_pygame_event(pygame.event.Event(pygame.KEYDOWN, key=key), held) diff --git a/examples/message-codegen/demo_lidar.cpp b/examples/message-codegen/demo_lidar.cpp index a777615c945..17bab0281b6 100644 --- a/examples/message-codegen/demo_lidar.cpp +++ b/examples/message-codegen/demo_lidar.cpp @@ -1,8 +1,6 @@ // Copyright 2026 Dimensional Inc. // SPDX-License-Identifier: Apache-2.0 -#include -#include #include #include #include @@ -20,8 +18,8 @@ int main() { point[3] = 0.5; } for (bool little : {true, false}) { - auto bytes = dimos::native::cdr_encode(cloud, little); - auto decoded = dimos::native::cdr_decode(bytes); + auto bytes = dimos::cdr::encode(cloud, little); + auto decoded = dimos::cdr::decode(bytes); assert(decoded == cloud); assert(decoded.header.stamp.sec == 1 && decoded.header.stamp.nanosec == 250000000); assert(decoded.width == 2 && decoded.fields.size() == 4 && decoded.data.size() == 32); diff --git a/examples/message-codegen/demo_live_bridge.py b/examples/message-codegen/demo_live_bridge.py index 5b4663765d4..7edbdcfa452 100644 --- a/examples/message-codegen/demo_live_bridge.py +++ b/examples/message-codegen/demo_live_bridge.py @@ -21,7 +21,6 @@ from typing import Any from uuid import uuid4 -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header import numpy as np @@ -99,9 +98,7 @@ def main() -> None: pixels[:, :80, 0] = 255 pixels[:, 80:, 2] = 255 message = image_from_array( - pixels, - encoding="rgb8", - header=Header(frame_id="camera_optical", stamp=Time(sec=0, nanosec=0)), + pixels, encoding="rgb8", header=Header(frame_id="camera_optical") ) for _ in range(10): sender.publish(Topic(channel, Image), message) diff --git a/examples/message-codegen/demo_marker_messages.py b/examples/message-codegen/demo_marker_messages.py index eb5dd055a0a..90e97b3c1d0 100644 --- a/examples/message-codegen/demo_marker_messages.py +++ b/examples/message-codegen/demo_marker_messages.py @@ -18,7 +18,6 @@ from dimos_generated.geometry_msgs.msg import Vector3 from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection3DArray -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.msgs.image import image_from_array @@ -42,7 +41,7 @@ def main() -> None: ts=0, image=image, center=Vector3(x=float(identifier), y=2, z=3), - size=Vector3(x=0.16, y=0.16, z=0.0), + size=Vector3(x=0.16, y=0.16), frame_id="world", marker_id=identifier, dictionary="DICT_APRILTAG_36h11", @@ -50,7 +49,7 @@ def main() -> None: for identifier in (7, 42) ] message = ImageDetections3D(image, markers).to_ros_detection3d_array() - decoded = cdr_decode(cdr_encode(message), Detection3DArray) + decoded = Detection3DArray.decode(message.encode()) assert decoded.header.stamp == image.header.stamp for marker in decoded.detections: assert marker.results[0].hypothesis.class_id == f"DICT_APRILTAG_36h11:{marker.id}" diff --git a/examples/message-codegen/demo_message_helpers.py b/examples/message-codegen/demo_message_helpers.py index cf6b8643e5f..c84834403d7 100644 --- a/examples/message-codegen/demo_message_helpers.py +++ b/examples/message-codegen/demo_message_helpers.py @@ -16,12 +16,10 @@ from pathlib import Path -from dimos_generated.builtin_interfaces.msg import Duration, Time from dimos_generated.dimos_msgs.msg import LineSegment3D, LineSegments3D, TrajectoryStatus from dimos_generated.geometry_msgs.msg import Point from dimos_generated.sensor_msgs.msg import CameraInfo from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.camera_info import camera_info_from_yaml, intrinsic_matrix from dimos.msgs.time import ( @@ -33,35 +31,25 @@ def main() -> None: - message = LineSegments3D( - segments=[ - LineSegment3D(start=Point(x=1, y=0.0, z=0.0), end=Point(y=2, x=0.0, z=0.0), weight=4) - ], - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - ) + message = LineSegments3D(segments=[LineSegment3D(start=Point(x=1), end=Point(y=2), weight=4)]) message.header.stamp = time_from_nanoseconds(1_700_000_000_123_456_789) message.header.frame_id = "map" - decoded = cdr_decode(cdr_encode(message), LineSegments3D) - print(f"{decoded.__msgtype__}: frame={decoded.header.frame_id}") + decoded = LineSegments3D.decode(message.encode()) + print(f"{decoded.msg_name}: frame={decoded.header.frame_id}") print(f"Exact source nanoseconds: {to_nanoseconds(decoded.header.stamp)}") segment = decoded.segments[0] print(f"Segment: start.x={segment.start.x}, end.y={segment.end.y}, weight={segment.weight}") status = TrajectoryStatus( - state=TrajectoryStatus.EXECUTING, - time_remaining=duration_from_seconds(1.25), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - progress=0.0, - time_elapsed=Duration(sec=0, nanosec=0), - error="", + state=TrajectoryStatus.EXECUTING, time_remaining=duration_from_seconds(1.25) ) - remaining = cdr_decode(cdr_encode(status), TrajectoryStatus).time_remaining + remaining = TrajectoryStatus.decode(status.encode()).time_remaining print(f"Trajectory remaining: sec={remaining.sec}, nanosec={remaining.nanosec}") print(f"Seconds for a controller API: {to_seconds(remaining)}") calibration = camera_info_from_yaml( Path(__file__).resolve().parents[2] / "dimos/robot/unitree/go2/front_camera_720.yaml", header=Header(frame_id="camera_optical", stamp=message.header.stamp), ) - restored = cdr_decode(cdr_encode(calibration), CameraInfo) + restored = CameraInfo.decode(calibration.encode()) print(f"Camera calibration: {restored.width}x{restored.height}, {restored.distortion_model}") print(f"Camera source nanoseconds: {to_nanoseconds(restored.header.stamp)}") print(f"Intrinsic matrix (independent NumPy copy):\n{intrinsic_matrix(restored)}") diff --git a/examples/message-codegen/demo_mls_transformer.py b/examples/message-codegen/demo_mls_transformer.py index 3fdcf27ecb4..548517a90f8 100644 --- a/examples/message-codegen/demo_mls_transformer.py +++ b/examples/message-codegen/demo_mls_transformer.py @@ -31,7 +31,6 @@ from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header from dimos_generated.tf2_msgs.msg import TFMessage -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np import rerun as rr @@ -61,17 +60,14 @@ def main() -> None: edge = TransformStamped( header=cloud.header, child_frame_id="base_link", - transform=Transform( - translation=Vector3(x=-2.0, y=-2.0, z=1.0), - rotation=Quaternion(w=1.0, x=0.0, y=0.0, z=0.0), - ), + transform=Transform(translation=Vector3(x=-2.0, y=-2.0, z=1.0), rotation=Quaternion(w=1.0)), ) - tf.receive_transform(cdr_decode(cdr_encode(edge), TransformStamped)) + tf.receive_transform(TransformStamped.decode(edge.encode())) relay = StartRelay(world_frame="world") relay._tf = tf poses: list[PoseStamped] = [] unsubscribe = relay.start_pose.subscribe( - lambda value: poses.append(cdr_decode(cdr_encode(value), PoseStamped)) + lambda value: poses.append(PoseStamped.decode(value.encode())) ) try: relay._on_tf(TFMessage(transforms=[edge])) @@ -88,17 +84,17 @@ def main() -> None: ts=0.0, pose=poses[0], tags={"region_bounds": (0.0, 0.0, 5.0, -1.0, 2.0)}, - _data=cdr_decode(cdr_encode(cloud), PointCloud2), + _data=PointCloud2.decode(cloud.encode()), ) ray_input = obs.derive(data=cloud, pose_tuple=(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)) [mapped] = list(RayTraceMap(voxel_size=0.2)(iter([ray_input]))) - mapped_cloud = cdr_decode(cdr_encode(mapped.data), PointCloud2) + mapped_cloud = PointCloud2.decode(mapped.data.encode()) assert mapped_cloud.header.stamp.nanosec == 123456789 print( f"Ray-traced CDR local map: {mapped_cloud.width * mapped_cloud.height} points, frame={mapped_cloud.header.frame_id}" ) [result] = list(MLSPlan(goal=(2.0, 2.0, 0.0), voxel_size=0.2, robot_height=1.0)(iter([obs]))) - path = cdr_decode(cdr_encode(result.data), Path) + path = Path.decode(result.data.encode()) assert result.tags["planned"] and len(path.poses) >= 2 assert path.header.stamp.nanosec == 123456789 print( @@ -114,35 +110,21 @@ def main() -> None: bridge._min_intervals = {} try: bridge._on_message( - cdr_decode(cdr_encode(TFMessage(transforms=[edge])), TFMessage), - SimpleNamespace(name="/tf"), + TFMessage.decode(TFMessage(transforms=[edge]).encode()), SimpleNamespace(name="/tf") ) finally: bridge.stop() bridge = RerunBridgeModule() bridge._min_intervals = {} try: - bridge._on_message( - cdr_decode(cdr_encode(cloud), PointCloud2), SimpleNamespace(name="/terrain") - ) - bridge._on_message( - cdr_decode(cdr_encode(path), Path), SimpleNamespace(name="/planned_path") - ) + bridge._on_message(PointCloud2.decode(cloud.encode()), SimpleNamespace(name="/terrain")) + bridge._on_message(Path.decode(path.encode()), SimpleNamespace(name="/planned_path")) grid = OccupancyGrid( header=path.header, - info=MapMetaData( - width=2, - height=2, - resolution=1.0, - origin=poses[0].pose, - map_load_time=Time(sec=0, nanosec=0), - ), - data=np.array([0, 100, -1, 50], dtype=np.int8), - ) - bridge._on_message( - cdr_decode(cdr_encode(grid), OccupancyGrid), - SimpleNamespace(name="/occupancy"), + info=MapMetaData(width=2, height=2, resolution=1.0, origin=poses[0].pose), + data=[0, 100, -1, 50], ) + bridge._on_message(OccupancyGrid.decode(grid.encode()), SimpleNamespace(name="/occupancy")) finally: bridge.stop() rr.log("world/ray_map", render_surface_map(mapped_cloud)) @@ -157,15 +139,11 @@ def main() -> None: LineSegment3D( start=Point(x=a.pose.position.x, y=a.pose.position.y, z=a.pose.position.z), end=Point(x=b.pose.position.x, y=b.pose.position.y, z=b.pose.position.z), - weight=1.0, ) for a, b in zip(path.poses, list(path.poses)[1:], strict=False) ], ) - rr.log( - "world/path_edges", - render_node_edges(cdr_decode(cdr_encode(segments), LineSegments3D)), - ) + rr.log("world/path_edges", render_node_edges(LineSegments3D.decode(segments.encode()))) rr.disconnect() assert output.stat().st_size > 0 print(f"Rerun recording: {output}") diff --git a/examples/message-codegen/demo_movement.py b/examples/message-codegen/demo_movement.py index 25a75eb9bf3..78dc166b23f 100644 --- a/examples/message-codegen/demo_movement.py +++ b/examples/message-codegen/demo_movement.py @@ -17,7 +17,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Point, PointStamped, Twist, Vector3 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.navigation.movement_manager.movement_manager import MovementManager @@ -27,32 +26,24 @@ def main() -> None: goals: list[PointStamped] = [] commands: list[Twist] = [] unsubs = [ - manager.goal.subscribe(lambda msg: goals.append(cdr_decode(cdr_encode(msg), PointStamped))), - manager.cmd_vel.subscribe(lambda msg: commands.append(cdr_decode(cdr_encode(msg), Twist))), + manager.goal.subscribe(lambda msg: goals.append(PointStamped.decode(msg.encode()))), + manager.cmd_vel.subscribe(lambda msg: commands.append(Twist.decode(msg.encode()))), ] try: clicked = PointStamped( header=Header(frame_id="map", stamp=Time(sec=1700000000, nanosec=123456789)), - point=Point(x=3, y=4, z=0.0), + point=Point(x=3, y=4), ) - manager._on_click(cdr_decode(cdr_encode(clicked), PointStamped)) + manager._on_click(PointStamped.decode(clicked.encode())) assert goals == [clicked] print("Click → CDR goal: (3, 4), map, 1700000000123456789 ns") - manager._on_nav( - Twist(linear=Vector3(x=0.2, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) - ) - manager._on_teleop( - Twist(linear=Vector3(x=0.5, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) - ) - manager._on_nav( - Twist(linear=Vector3(x=0.9, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) - ) + manager._on_nav(Twist(linear=Vector3(x=0.2))) + manager._on_teleop(Twist(linear=Vector3(x=0.5))) + manager._on_nav(Twist(linear=Vector3(x=0.9))) assert [msg.linear.x for msg in commands] == [0.2, 0.5] print("Navigation: 0.2 m/s; teleop: 0.5 m/s; competing navigation suppressed") manager.config.tele_cooldown_sec = 0 - manager._on_nav( - Twist(linear=Vector3(x=0.1, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) - ) + manager._on_nav(Twist(linear=Vector3(x=0.1))) assert commands[-1].linear.x == 0.1 print("Cooldown elapsed → navigation resumes at 0.1 m/s") print("PASS: generated click and velocity messages cross CDR output boundaries") diff --git a/examples/message-codegen/demo_native.py b/examples/message-codegen/demo_native.py index c6f9f74ab27..5692d767480 100644 --- a/examples/message-codegen/demo_native.py +++ b/examples/message-codegen/demo_native.py @@ -29,12 +29,9 @@ from urllib.parse import urlsplit import uuid -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.dimos_msgs.msg import LineSegment3D, LineSegments3D from dimos_generated.geometry_msgs.msg import Point from dimos_generated.sensor_msgs.msg import Image -from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import encode as cdr_encode import numpy as np from dimos.core.transport import LCMTransport, PubSubTransport, ZenohTransport @@ -154,12 +151,7 @@ def receive(value: Any, name: str = name) -> None: def demonstrate(backend: str, cpp: Path, rust: Path, evidence: Path) -> None: stamp = 1_700_000_000_123_456_789 - lines = LineSegments3D( - segments=[ - LineSegment3D(start=Point(x=1, y=0.0, z=0.0), end=Point(y=2, x=0.0, z=0.0), weight=4) - ], - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - ) + lines = LineSegments3D(segments=[LineSegment3D(start=Point(x=1), end=Point(y=2), weight=4)]) lines.header.frame_id = "map" lines.header.stamp = time_from_nanoseconds(stamp) image = Image( @@ -168,8 +160,6 @@ def demonstrate(backend: str, cpp: Path, rust: Path, evidence: Path) -> None: encoding="rgb8", step=1920, data=np.arange(640 * 480 * 3, dtype=np.uint8), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - is_bigendian=0, ) image.header.frame_id = "camera" image.header.stamp = time_from_nanoseconds(stamp) @@ -180,7 +170,7 @@ def demonstrate(backend: str, cpp: Path, rust: Path, evidence: Path) -> None: assert decoded_lines.header.frame_id == "map" assert decoded_lines.segments[0].start.x == 1 assert decoded_lines.segments[0].end.y == 2 - assert cdr_encode(received["image"]) == cdr_encode(image) + assert received["image"].encode() == image.encode() print(f"{backend}: Python weight=4 → C++ weight=5 → Rust weight=6 → Python verified") print(f"{backend}: {len(image.data):,} image bytes and source nanoseconds={stamp} match") diff --git a/examples/message-codegen/demo_navigation.py b/examples/message-codegen/demo_navigation.py index 64d87a5bb52..12e747ebe05 100644 --- a/examples/message-codegen/demo_navigation.py +++ b/examples/message-codegen/demo_navigation.py @@ -24,20 +24,10 @@ from demo_pubsub import free_port from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import ( - Point, - PointStamped, - Pose, - PoseWithCovariance, - Quaternion, - Twist, - TwistWithCovariance, - Vector3, -) +from dimos_generated.geometry_msgs.msg import Point, PointStamped, Pose, Quaternion, Twist from dimos_generated.nav_msgs.msg import OccupancyGrid, Odometry, Path from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Bool, Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.core.transport import LCMTransport, ZenohTransport @@ -118,7 +108,7 @@ def transport(name: str, message_type: type, peer: int) -> Any: x, y = np.meshgrid(np.arange(0, 6, 0.25), np.arange(0, 6, 0.25)) points = np.column_stack((x.ravel(), y.ravel(), np.zeros(x.size))) source = pointcloud_from_xyz(points, header=header) - voxels.add_frame(cdr_decode(cdr_encode(source), PointCloud2)) + voxels.add_frame(PointCloud2.decode(source.encode())) accumulated = voxels.get_global_pointcloud2() assert accumulated.header == header position = [1.0, 1.0, 0.0] @@ -128,28 +118,10 @@ def transport(name: str, message_type: type, peer: int) -> Any: received_paths: list[Path] = [] def feedback() -> None: - message = Odometry( - header=header, - child_frame_id="base_link", - pose=PoseWithCovariance( - pose=Pose( - position=Point(x=0.0, y=0.0, z=0.0), - orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), - ), - covariance=np.zeros(36, dtype=np.float64), - ), - twist=TwistWithCovariance( - twist=Twist( - linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0) - ), - covariance=np.zeros(36, dtype=np.float64), - ), - ) + message = Odometry(header=header, child_frame_id="base_link") message.pose.pose = Pose( - position=Point(x=position[0], y=position[1], z=0.0), - orientation=Quaternion( - z=math.sin(position[2] / 2), w=math.cos(position[2] / 2), x=0.0, y=0.0 - ), + position=Point(x=position[0], y=position[1]), + orientation=Quaternion(z=math.sin(position[2] / 2), w=math.cos(position[2] / 2)), ) odometry.publish(message) @@ -177,7 +149,7 @@ def initialized() -> bool: ) wait_until(initialized, timeout=5) - goals.publish(PointStamped(header=header, point=Point(x=3, y=1, z=0.0))) + goals.publish(PointStamped(header=header, point=Point(x=3, y=1))) assert arrived.wait(10), f"{backend}: navigation module did not report arrival" with lock: final = tuple(position) @@ -185,12 +157,7 @@ def initialized() -> bool: assert any(command.linear.x > 0 for command in commands) path = next(path for path in received_paths if len(path.poses)) assert path.header == header and all(pose.header == header for pose in path.poses) - wait_until( - lambda: bool(commands) - and commands[-1] - == Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)), - timeout=5, - ) + wait_until(lambda: bool(commands) and commands[-1] == Twist(), timeout=5) grid = module._planner._navigation_map.binary_costmap assert grid.header == header print( diff --git a/examples/message-codegen/demo_navigation_recording.py b/examples/message-codegen/demo_navigation_recording.py index 3fa38af61cf..e786d334aa5 100644 --- a/examples/message-codegen/demo_navigation_recording.py +++ b/examples/message-codegen/demo_navigation_recording.py @@ -27,8 +27,6 @@ Quaternion, Transform, TransformStamped, - Twist, - TwistWithCovariance, Vector3, ) from dimos_generated.nav_msgs.msg import Odometry @@ -58,8 +56,8 @@ def main() -> None: header=Header(frame_id="lidar", stamp=stamp), ) pose = Pose( - position=Point(x=float(tick), y=0.0, z=0.0), - orientation=Quaternion(z=math.sqrt(0.5), w=math.sqrt(0.5), x=0.0, y=0.0), + position=Point(x=float(tick)), + orientation=Quaternion(z=math.sqrt(0.5), w=math.sqrt(0.5)), ) lidar.append(cloud, ts=timestamp) transforms.append( @@ -69,8 +67,7 @@ def main() -> None: header=Header(frame_id="world", stamp=stamp), child_frame_id="lidar", transform=Transform( - translation=Vector3(x=float(tick), y=0.0, z=0.0), - rotation=pose.orientation, + translation=Vector3(x=float(tick)), rotation=pose.orientation ), ) ] @@ -80,17 +77,7 @@ def main() -> None: odometry.append( Odometry( header=Header(frame_id="world", stamp=stamp), - pose=PoseWithCovariance( - pose=pose, covariance=np.zeros(36, dtype=np.float64) - ), - child_frame_id="", - twist=TwistWithCovariance( - twist=Twist( - linear=Vector3(x=0.0, y=0.0, z=0.0), - angular=Vector3(x=0.0, y=0.0, z=0.0), - ), - covariance=np.zeros(36, dtype=np.float64), - ), + pose=PoseWithCovariance(pose=pose), ), ts=timestamp, ) diff --git a/examples/message-codegen/demo_navigation_skill.py b/examples/message-codegen/demo_navigation_skill.py index 8af4ea89d55..5a21c0d0892 100644 --- a/examples/message-codegen/demo_navigation_skill.py +++ b/examples/message-codegen/demo_navigation_skill.py @@ -17,10 +17,7 @@ import math from unittest.mock import Mock, patch -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped -from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.agents.skills.navigation import NavigationSkillContainer @@ -40,15 +37,14 @@ def main() -> None: pose=Pose( position=Point(x=1, y=2, z=3), orientation=quaternion_from_euler(0.2, -0.3, math.pi / 2), - ), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), + ) ) - skill._on_odom(cdr_decode(cdr_encode(original), PoseStamped)) + skill._on_odom(PoseStamped.decode(original.encode())) print(skill.tag_location("desk")) location = memory.tag_location.call_args.args[0] memory.query_tagged_location.return_value = location print(skill._navigate_by_tagged_location("desk")) - goal = cdr_decode(cdr_encode(navigator.set_goal.call_args.args[0]), PoseStamped) + goal = PoseStamped.decode(navigator.set_goal.call_args.args[0].encode()) np.testing.assert_allclose( quaternion_euler(goal.pose.orientation), (0.2, -0.3, math.pi / 2) ) diff --git a/examples/message-codegen/demo_occupancy.py b/examples/message-codegen/demo_occupancy.py index 377c0057e0b..cfb17f57dff 100644 --- a/examples/message-codegen/demo_occupancy.py +++ b/examples/message-codegen/demo_occupancy.py @@ -23,7 +23,6 @@ from dimos_generated.nav_msgs.msg import OccupancyGrid from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.mapping.occupancy.inflation import simple_inflate @@ -38,9 +37,9 @@ def main() -> None: points = np.column_stack((x.ravel(), y.ravel(), np.zeros(x.size))) points[(points[:, 0] > 1.8) & (points[:, 0] < 2.2), 2] = 1 header = Header(stamp=Time(sec=1700000000, nanosec=123456789), frame_id="map") - cloud = cdr_decode(cdr_encode(pointcloud_from_xyz(points, header=header)), PointCloud2) + cloud = PointCloud2.decode(pointcloud_from_xyz(points, header=header).encode()) grid = general_occupancy(cloud, resolution=0.1) - inflated = cdr_decode(cdr_encode(simple_inflate(grid, 0.2)), OccupancyGrid) + inflated = OccupancyGrid.decode(simple_inflate(grid, 0.2).encode()) assert inflated.header == header before = np.count_nonzero(occupancy_view(grid) == 100) after = np.count_nonzero(occupancy_view(inflated) == 100) diff --git a/examples/message-codegen/demo_odometry_history.py b/examples/message-codegen/demo_odometry_history.py index a3b1e756b38..28e2f769a9f 100644 --- a/examples/message-codegen/demo_odometry_history.py +++ b/examples/message-codegen/demo_odometry_history.py @@ -18,20 +18,9 @@ from pathlib import Path as FilePath from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import ( - Point, - Pose, - PoseStamped, - PoseWithCovariance, - Quaternion, - Twist, - TwistWithCovariance, - Vector3, -) +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist from dimos_generated.nav_msgs.msg import Odometry, Path from dimos_generated.std_msgs.msg import Bool, Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode -import numpy as np from dimos.mapping.odometry_hist import OdometryHist, path_at_true_height from dimos.memory.vis.space.elements import Polyline @@ -45,66 +34,35 @@ async def main() -> None: commands: list[Twist] = [] arrivals: list[Bool] = [] paths: list[Path] = [] - follower.nav_cmd_vel.subscribe(lambda msg: commands.append(cdr_decode(cdr_encode(msg), Twist))) - follower.goal_reached.subscribe(lambda msg: arrivals.append(cdr_decode(cdr_encode(msg), Bool))) - history.odom_hist.subscribe(lambda msg: paths.append(cdr_decode(cdr_encode(msg), Path))) + follower.nav_cmd_vel.subscribe(lambda msg: commands.append(Twist.decode(msg.encode()))) + follower.goal_reached.subscribe(lambda msg: arrivals.append(Bool.decode(msg.encode()))) + history.odom_hist.subscribe(lambda msg: paths.append(Path.decode(msg.encode()))) header = Header(stamp=Time(sec=1700000000, nanosec=123456789), frame_id="map") reference = Path( header=header, poses=[ - PoseStamped( - header=header, - pose=Pose( - position=Point(x=x, y=0.0, z=0.0), - orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), - ), - ) + PoseStamped(header=header, pose=Pose(position=Point(x=x), orientation=Quaternion(w=1))) for x in [0, 1, 2] ], ) try: - follower._on_path(cdr_decode(cdr_encode(reference), Path)) + follower._on_path(Path.decode(reference.encode())) waypoints = follower._waypoints assert waypoints is not None x = 0.0 for tick in range(100): header.stamp.nanosec = 123456789 + tick pose = PoseStamped( - header=header, - pose=Pose( - position=Point(x=x, z=0.25, y=0.0), - orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), - ), - ) - sample = Odometry( - header=header, - child_frame_id="", - pose=PoseWithCovariance( - pose=Pose( - position=Point(x=0.0, y=0.0, z=0.0), - orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), - ), - covariance=np.zeros(36, dtype=np.float64), - ), - twist=TwistWithCovariance( - twist=Twist( - linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0) - ), - covariance=np.zeros(36, dtype=np.float64), - ), + header=header, pose=Pose(position=Point(x=x, z=0.25), orientation=Quaternion(w=1)) ) + sample = Odometry(header=header) sample.pose.pose = pose.pose - await history.handle_odometry(cdr_decode(cdr_encode(sample), Odometry)) - follower._step(cdr_decode(cdr_encode(pose), PoseStamped), waypoints) + await history.handle_odometry(Odometry.decode(sample.encode())) + follower._step(PoseStamped.decode(pose.encode()), waypoints) if arrivals: break x += commands[-1].linear.x * 0.1 - assert ( - arrivals - and arrivals[-1].data - and commands[-1] - == Twist(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)) - ) + assert arrivals and arrivals[-1].data and commands[-1] == Twist() assert x >= 1.7 and x <= 2 recorded = paths[-1] assert recorded.poses[0].header.stamp.nanosec == 123456789 diff --git a/examples/message-codegen/demo_path_following.py b/examples/message-codegen/demo_path_following.py index 86d0df0d5b7..37addcf1692 100644 --- a/examples/message-codegen/demo_path_following.py +++ b/examples/message-codegen/demo_path_following.py @@ -16,11 +16,9 @@ from pathlib import Path as FilePath -from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion, Twist, Vector3 +from dimos_generated.geometry_msgs.msg import PoseStamped, Twist, Vector3 from dimos_generated.nav_msgs.msg import Path from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.control.benchmarking.paths import straight_line, trajectory_to_svg from dimos.control.benchmarking.plant import ( @@ -38,11 +36,11 @@ def main() -> None: reference = straight_line(length=2.0) - reference.header = Header(frame_id="world", stamp=Time(sec=0, nanosec=0)) + reference.header = Header(frame_id="world") reference.poses = [ PoseStamped(header=reference.header, pose=pose.pose) for pose in reference.poses ] - received = cdr_decode(cdr_encode(reference), Path) + received = Path.decode(reference.encode()) names = ["base/vx", "base/vy", "base/wz"] task = PathFollowerTask( "demo", PathFollowerTaskConfig(joint_names=names, speed=0.5), GlobalConfig() @@ -50,16 +48,7 @@ def main() -> None: channel = FopdtChannelParams(K=1.0, tau=0.1, L=0.0) plant = TwistBasePlantSim(TwistBasePlantParams(vx=channel, vy=channel, wz=channel)) plant.reset(0.0, 0.0, 0.0, 0.1) - assert task.start_path( - received, - PoseStamped( - header=received.header, - pose=Pose( - position=Point(x=0.0, y=0.0, z=0.0), - orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), - ), - ), - ) + assert task.start_path(received, PoseStamped(header=received.header)) trace: list[tuple[float, float]] = [] for tick in range(200): state = CoordinatorState( @@ -76,10 +65,8 @@ def main() -> None: break assert command is not None vx, vy, wz = command.velocities - wire = cdr_encode( - Twist(linear=Vector3(x=vx, y=vy, z=0.0), angular=Vector3(z=wz, x=0.0, y=0.0)) - ) - decoded = cdr_decode(wire, Twist) + wire = Twist(linear=Vector3(x=vx, y=vy), angular=Vector3(z=wz)).encode() + decoded = Twist.decode(wire) plant.step(decoded.linear.x, decoded.linear.y, decoded.angular.z, 0.1) assert task.get_state() == "arrived" assert abs(plant.x - 2.0) <= 0.2 and abs(plant.y) < 1e-9 diff --git a/examples/message-codegen/demo_patrol.py b/examples/message-codegen/demo_patrol.py index 67c8377bfd3..6bb358146d4 100644 --- a/examples/message-codegen/demo_patrol.py +++ b/examples/message-codegen/demo_patrol.py @@ -17,10 +17,9 @@ from pathlib import Path from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion +from dimos_generated.geometry_msgs.msg import Pose, PoseStamped, Quaternion from dimos_generated.nav_msgs.msg import MapMetaData, OccupancyGrid from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.memory.vis.space.space import Space @@ -37,18 +36,11 @@ def main() -> None: grid = OccupancyGrid( header=Header(frame_id="map", stamp=Time(sec=1700000000, nanosec=123456789)), info=MapMetaData( - width=24, - height=24, - resolution=0.5, - origin=Pose( - orientation=Quaternion(w=1, x=0.0, y=0.0, z=0.0), - position=Point(x=0.0, y=0.0, z=0.0), - ), - map_load_time=Time(sec=0, nanosec=0), + width=24, height=24, resolution=0.5, origin=Pose(orientation=Quaternion(w=1)) ), - data=np.asarray(cells.ravel(), dtype=np.int8), + data=cells.ravel(), ) - grid = cdr_decode(cdr_encode(grid), OccupancyGrid) + grid = OccupancyGrid.decode(grid.encode()) for name in ("random", "coverage", "frontier"): router = create_patrol_router(name, 0.5) router.handle_occupancy_grid(grid) @@ -57,7 +49,7 @@ def main() -> None: for _ in range(5): goal = router.next_goal() assert goal is not None - goal = cdr_decode(cdr_encode(goal), PoseStamped) + goal = PoseStamped.decode(goal.encode()) assert goal.header == grid.header space.add(goal, color="#ff0000") router.handle_odom(goal) diff --git a/examples/message-codegen/demo_person_follow.py b/examples/message-codegen/demo_person_follow.py index fcec5cbff7c..583322b065f 100644 --- a/examples/message-codegen/demo_person_follow.py +++ b/examples/message-codegen/demo_person_follow.py @@ -17,11 +17,8 @@ from types import SimpleNamespace from unittest.mock import MagicMock, patch -from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Twist, Vector3 -from dimos_generated.sensor_msgs.msg import CameraInfo, RegionOfInterest -from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode +from dimos_generated.geometry_msgs.msg import Twist +from dimos_generated.sensor_msgs.msg import CameraInfo import numpy as np from dimos.agents.skills.person_follow import PersonFollowSkillContainer @@ -32,19 +29,7 @@ def main() -> None: - camera = CameraInfo( - width=640, - height=480, - k=np.array([500, 0, 320, 0, 500, 240, 0, 0, 1], dtype=np.float64), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - distortion_model="", - d=np.array([], dtype=np.float64), - r=np.zeros(9, dtype=np.float64), - p=np.zeros(12, dtype=np.float64), - binning_x=0, - binning_y=0, - roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), - ) + camera = CameraInfo(width=640, height=480, k=[500, 0, 320, 0, 500, 240, 0, 0, 1]) with patch("dimos.agents.skills.person_follow.create", return_value=MagicMock()): module = PersonFollowSkillContainer(camera_info=camera, g=GlobalConfig(simulation="")) image = image_from_array(np.zeros((480, 640, 3), dtype=np.uint8), encoding="rgb8") @@ -65,7 +50,7 @@ def main() -> None: commands: list[Twist] = [] def receive(value: Twist) -> None: - command = cdr_decode(cdr_encode(value), Twist) + command = Twist.decode(value.encode()) commands.append(command) print( f"CDR command: forward={command.linear.x:.2f} m/s, turn={command.angular.z:.2f} rad/s" @@ -81,9 +66,7 @@ def receive(value: Twist) -> None: assert thread is not None thread.join(timeout=2) assert not thread.is_alive() - assert commands[0].linear.x == 0.5 and commands[-1] == Twist( - linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0) - ) + assert commands[0].linear.x == 0.5 and commands[-1] == Twist() print("PASS: real control thread publishes motion, stops, and publishes zero") print("Tracker/model output is substituted; no inference or robot actuation.") finally: diff --git a/examples/message-codegen/demo_phone_cdr.py b/examples/message-codegen/demo_phone_cdr.py index 8dcd43485c3..b135a8c254a 100644 --- a/examples/message-codegen/demo_phone_cdr.py +++ b/examples/message-codegen/demo_phone_cdr.py @@ -20,7 +20,6 @@ import threading from dimos_generated.geometry_msgs.msg import TwistStamped -from dimos_message_build.registry import decode as cdr_decode import uvicorn from dimos.teleop.phone.phone_teleop_module import PhoneTeleopModule @@ -33,7 +32,7 @@ def __init__(self) -> None: def _on_sensors_bytes(self, data: bytes) -> None: super()._on_sensors_bytes(data) - self.received.put(cdr_decode(data, TwistStamped)) + self.received.put(TwistStamped.decode(data)) def main() -> None: @@ -56,7 +55,7 @@ def main() -> None: assert message.header.frame_id == "phone" assert message.header.stamp.sec > 0 print( - f"Browser → {message.__msgtype__}: stamp={message.header.stamp.sec}s + " + f"Browser → {message.msg_name}: stamp={message.header.stamp.sec}s + " f"{message.header.stamp.nanosec}ns", flush=True, ) diff --git a/examples/message-codegen/demo_planning_backends.py b/examples/message-codegen/demo_planning_backends.py index 731f53b2fa4..4635ee62abb 100644 --- a/examples/message-codegen/demo_planning_backends.py +++ b/examples/message-codegen/demo_planning_backends.py @@ -21,7 +21,6 @@ from dimos_generated.sensor_msgs.msg import JointState from dimos_generated.std_msgs.msg import Header from dimos_generated.tf2_msgs.msg import TFMessage -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.manipulation.planning.groups.models import PlanningGroupDefinition @@ -60,37 +59,17 @@ def main() -> None: monitor = WorldMonitor(world=world) monitor.load_model(config) world.finalize() - start = cdr_decode( - cdr_encode( - JointState( - name=config.joint_names, - position=np.array([-0.4, 0.3], dtype=np.float64), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - velocity=np.array([], dtype=np.float64), - effort=np.array([], dtype=np.float64), - ) - ), - JointState, - ) - goal = cdr_decode( - cdr_encode( - JointState( - name=config.joint_names, - position=np.array([0.4, -0.3], dtype=np.float64), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - velocity=np.array([], dtype=np.float64), - effort=np.array([], dtype=np.float64), - ) - ), - JointState, + start = JointState.decode( + JointState(name=config.joint_names, position=[-0.4, 0.3]).encode() ) + goal = JointState.decode(JointState(name=config.joint_names, position=[0.4, -0.3]).encode()) result = RRTConnectPlanner().plan_joint_path(world, start, goal) assert result.is_success(), result path_points = interpolate_path(result.path, resolution=0.2) print(f"Drake model joints: {world.get_prepared_model().joint_space.names}") print(f"RRT result: {result.status.name}; interpolated waypoints={len(path_points)}") for index, point in enumerate(path_points): - decoded = cdr_decode(cdr_encode(point), JointState) + decoded = JointState.decode(point.encode()) assert decoded == point assert world.check_config_collision_free(decoded) with world.scratch_context() as context: @@ -106,7 +85,7 @@ def main() -> None: ) pose = monitor.get_group_ee_pose("arm", decoded) transform = transform_from_pose(pose, child_frame_id="tool") - tf = cdr_decode(cdr_encode(TFMessage(transforms=[transform])), TFMessage) + tf = TFMessage.decode(TFMessage(transforms=[transform]).encode()) assert tf.transforms[0].header.stamp == decoded.header.stamp expected = np.array([np.cos(decoded.position[0]), np.sin(decoded.position[0]), 0.0]) np.testing.assert_allclose(pose_matrix(pose.pose)[:3, 3], expected, atol=1e-12) diff --git a/examples/message-codegen/demo_planning_joints.py b/examples/message-codegen/demo_planning_joints.py index 24e6b897b35..e5a9f3f8b96 100644 --- a/examples/message-codegen/demo_planning_joints.py +++ b/examples/message-codegen/demo_planning_joints.py @@ -17,8 +17,6 @@ from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import JointState from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode -import numpy as np from dimos.manipulation.planning.groups.models import PlanningGroup from dimos.manipulation.planning.groups.utils import ( @@ -38,21 +36,12 @@ def main() -> None: source = JointState( header=Header(stamp=Time(sec=1700000000, nanosec=123456789), frame_id="robot"), name=["right/j1", "left/j2", "left/j1"], - position=np.array([0.9, 0.3, -0.2], dtype=np.float64), - velocity=np.array([], dtype=np.float64), - effort=np.array([], dtype=np.float64), + position=[0.9, 0.3, -0.2], ) - decoded = cdr_decode(cdr_encode(source), JointState) + decoded = JointState.decode(source.encode()) selected = filter_joint_state_to_selected_joints(decoded, group.joint_names) target = normalize_joint_target( - group, - JointState( - header=source.header, - name=["left/j2", "left/j1"], - position=np.array([0.5, 0.1], dtype=np.float64), - velocity=np.array([], dtype=np.float64), - effort=np.array([], dtype=np.float64), - ), + group, JointState(header=source.header, name=["left/j2", "left/j1"], position=[0.5, 0.1]) ) space = JointSpace( tuple( @@ -72,7 +61,7 @@ def main() -> None: assert positions.tolist() == [-0.2, 0.3] assert space.from_joint_state(target).tolist() == [0.1, 0.5] assert selected.header == target.header == source.header - assert cdr_decode(cdr_encode(target), JointState) == target + assert JointState.decode(target.encode()) == target print(f"Coordinator input: names={list(source.name)}, q={list(source.position)}") print(f"Selected {group.id}: names={list(selected.name)}, q={positions.tolist()}") print(f"Normalized target: q={list(target.position)}; within declared joint limits") diff --git a/examples/message-codegen/demo_pointcloud.py b/examples/message-codegen/demo_pointcloud.py index 6b36b0fe5ac..ffddace3d46 100644 --- a/examples/message-codegen/demo_pointcloud.py +++ b/examples/message-codegen/demo_pointcloud.py @@ -19,11 +19,7 @@ import struct -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import PointCloud2, PointField -from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode -import numpy as np from dimos.msgs.pointcloud import pointcloud_view, pointcloud_xyz @@ -40,17 +36,15 @@ def main() -> None: point_step=20, row_step=32, is_bigendian=big_endian, - data=np.frombuffer(bytes(payload), dtype=np.uint8), + data=bytes(payload), fields=[ PointField(name="x", offset=0, datatype=7, count=1), PointField(name="y", offset=4, datatype=7, count=1), PointField(name="z", offset=8, datatype=7, count=1), PointField(name="tags", offset=12, datatype=4, count=2), ], - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - is_dense=False, ) - decoded = cdr_decode(cdr_encode(message, little_endian=not big_endian), PointCloud2) + decoded = PointCloud2.decode(message.encode(little_endian=not big_endian)) view = pointcloud_view(decoded) assert pointcloud_xyz(decoded).tolist() == [[1, 2, 3], [2, 2, 3]] assert view["tags"].tolist() == [[[7, 9]], [[7, 9]]] diff --git a/examples/message-codegen/demo_pubsub.py b/examples/message-codegen/demo_pubsub.py index 936e060e227..fb1e51f0995 100644 --- a/examples/message-codegen/demo_pubsub.py +++ b/examples/message-codegen/demo_pubsub.py @@ -22,12 +22,9 @@ from urllib.parse import urlsplit import uuid -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.dimos_msgs.msg import LineSegment3D, LineSegments3D from dimos_generated.geometry_msgs.msg import Point from dimos_generated.sensor_msgs.msg import Image -from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import encode as cdr_encode import numpy as np from dimos.core.transport import LCMTransport, PubSubTransport, SHMTransport, ZenohTransport @@ -69,17 +66,10 @@ def demonstrate(backend: str) -> None: encoding="rgb8", step=1920, data=np.arange(640 * 480 * 3, dtype=np.uint8), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - is_bigendian=0, ) image.header.frame_id = "camera" image.header.stamp = time_from_nanoseconds(1_700_000_000_123_456_789) - lines = LineSegments3D( - segments=[ - LineSegment3D(start=Point(x=1, y=0.0, z=0.0), end=Point(y=2, x=0.0, z=0.0), weight=4) - ], - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - ) + lines = LineSegments3D(segments=[LineSegment3D(start=Point(x=1), end=Point(y=2), weight=4)]) lines.header.frame_id = "map" with ExitStack() as stack: pools = [ZenohSessionPool(), ZenohSessionPool()] @@ -112,16 +102,16 @@ def demonstrate(backend: str) -> None: peer.start() peers.append(peer) decoded = exchange(peers[0], peers[1], message) - assert cdr_encode(decoded) == cdr_encode(message) + assert decoded.encode() == message.encode() if isinstance(decoded, LineSegments3D): print( - f"{backend}: {decoded.__msgtype__}, frame={decoded.header.frame_id}, " + f"{backend}: {decoded.msg_name}, frame={decoded.header.frame_id}, " f"segment weight={decoded.segments[0].weight}" ) else: assert isinstance(decoded, Image) print( - f"{backend}: {decoded.__msgtype__}, {len(decoded.data):,} pixel bytes match, " + f"{backend}: {decoded.msg_name}, {len(decoded.data):,} pixel bytes match, " f"source nanoseconds={to_nanoseconds(decoded.header.stamp)}" ) diff --git a/examples/message-codegen/demo_robot_tf.py b/examples/message-codegen/demo_robot_tf.py index 9ec44405af9..c15045c4d21 100644 --- a/examples/message-codegen/demo_robot_tf.py +++ b/examples/message-codegen/demo_robot_tf.py @@ -15,7 +15,6 @@ """Inspect a Go2 device pose and generated CDR TF chain without connecting to a robot.""" from dimos_generated.tf2_msgs.msg import TFMessage -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.msgs.geometry import compose_transforms from dimos.msgs.time import to_nanoseconds @@ -26,7 +25,7 @@ def main() -> None: pose = pose_from_webrtc_odometry(raw_odometry_msg_sample) edges = GO2Connection._odom_to_tf(pose, prefix="robot0") - decoded = cdr_decode(cdr_encode(TFMessage(transforms=edges)), TFMessage) + decoded = TFMessage.decode(TFMessage(transforms=edges).encode()) assert len(decoded.transforms) == 3 print(f"Device pose: frame={pose.header.frame_id}, stamp={to_nanoseconds(pose.header.stamp)}") for edge in decoded.transforms: diff --git a/examples/message-codegen/demo_ros_bridge.py b/examples/message-codegen/demo_ros_bridge.py index b0135b2853f..8f6dc033049 100644 --- a/examples/message-codegen/demo_ros_bridge.py +++ b/examples/message-codegen/demo_ros_bridge.py @@ -18,11 +18,9 @@ import uuid from dimos_generated.builtin_interfaces.msg import Time -from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped, Quaternion +from dimos_generated.geometry_msgs.msg import Point, Pose, PoseStamped from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import encode as cdr_encode -import numpy as np from dimos.msgs.protocol import DimosMsg from dimos.protocol.pubsub.impl.rospubsub import DimosROS, ROSTopic @@ -45,7 +43,7 @@ def collect(message: DimosMsg, topic: ROSTopic) -> None: stamp = message.header.stamp key = (topic.topic, stamp.nanosec) received[key] = message - print(f"ROS received {message.__msgtype__}: source={stamp.sec}.{stamp.nanosec:09d}") + print(f"ROS received {message.msg_name}: source={stamp.sec}.{stamp.nanosec:09d}") if len(received) == 6: done.set() @@ -60,21 +58,14 @@ def publish_next() -> None: return header = Header(stamp=Time(sec=1700000000, nanosec=123456789 + count), frame_id="map") messages: list[DimosMsg] = [ - PoseStamped( - header=header, - pose=Pose( - position=Point(x=float(count), y=0.0, z=0.0), - orientation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), - ), - ), + PoseStamped(header=header, pose=Pose(position=Point(x=float(count)))), Image( header=header, height=1, width=1, encoding="rgb8", step=3, - data=np.frombuffer(bytes([count, 128, 255 - count]), dtype=np.uint8), - is_bigendian=0, + data=bytes([count, 128, 255 - count]), ), ] for topic, message in zip(topics, messages, strict=True): @@ -85,9 +76,7 @@ def publish_next() -> None: timer = node.create_timer(0.1, publish_next) try: assert done.wait(15), "ROS discovery or message delivery timed out" - assert {key: cdr_encode(value) for key, value in received.items()} == { - key: cdr_encode(value) for key, value in expected.items() - } + assert received == expected for index in range(3): pose = received[(topics[0].topic, 123456789 + index)] image = received[(topics[1].topic, 123456789 + index)] diff --git a/examples/message-codegen/demo_self_filter.py b/examples/message-codegen/demo_self_filter.py index 038966e212c..2dda6e584b3 100644 --- a/examples/message-codegen/demo_self_filter.py +++ b/examples/message-codegen/demo_self_filter.py @@ -17,10 +17,9 @@ from pathlib import Path from tempfile import TemporaryDirectory -from dimos_generated.geometry_msgs.msg import Quaternion, Transform, TransformStamped, Vector3 +from dimos_generated.geometry_msgs.msg import Transform, TransformStamped, Vector3 from dimos_generated.sensor_msgs.msg import PointCloud2 from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.manipulation.planning.utils.point_cloud_self_filter import PointCloudSelfFilter @@ -51,19 +50,16 @@ def main() -> None: TransformStamped( header=Header(frame_id=frame, stamp=stamp), child_frame_id="arm", - transform=Transform( - translation=Vector3(x=arm_x, y=0.0, z=0.0), - rotation=Quaternion(x=0.0, y=0.0, z=0.0, w=1.0), - ), + transform=Transform(translation=Vector3(x=arm_x)), ) ) source = pointcloud_from_xyz( np.array([[arm_x, 0, 0], [5.0, 0, 0]]), header=Header(frame_id="camera", stamp=stamp), ) - result = module.filter_cloud(cdr_decode(cdr_encode(source), PointCloud2)) + result = module.filter_cloud(PointCloud2.decode(source.encode())) assert result is not None - filtered, mask = (cdr_decode(cdr_encode(value), PointCloud2) for value in result) + filtered, mask = (PointCloud2.decode(value.encode()) for value in result) np.testing.assert_allclose(pointcloud_xyz(filtered), [[5.0, 0, 0]]) assert filtered.header == source.header assert mask.header.stamp == stamp and mask.header.frame_id == "world" diff --git a/examples/message-codegen/demo_storage_replay.py b/examples/message-codegen/demo_storage_replay.py index 2ddee7645b3..ef37885d8dd 100644 --- a/examples/message-codegen/demo_storage_replay.py +++ b/examples/message-codegen/demo_storage_replay.py @@ -23,7 +23,6 @@ from dimos_generated.dimos_msgs.msg import LineSegment3D, LineSegments3D from dimos_generated.geometry_msgs.msg import Point from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import encode as cdr_encode, schema as cdr_schema from dimos.memory.codecs.base import codec_for, codec_id from dimos.memory.replay_module import replay_module diff --git a/examples/message-codegen/demo_video_stats.py b/examples/message-codegen/demo_video_stats.py index 277c438c6c7..63ee0f59c5a 100644 --- a/examples/message-codegen/demo_video_stats.py +++ b/examples/message-codegen/demo_video_stats.py @@ -18,7 +18,6 @@ import tempfile from dimos_generated.dimos_msgs.msg import VideoStats -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from dimos.memory.store.sqlite import SqliteStore from dimos.teleop.utils.video_stats import video_stats_from_dict @@ -35,7 +34,7 @@ def main() -> None: "frames_dropped": 2**32 + 1, } ) - decoded = cdr_decode(cdr_encode(message), VideoStats) + decoded = VideoStats.decode(message.encode()) assert decoded == message with tempfile.TemporaryDirectory() as directory: path = Path(directory) / "video.db" @@ -45,7 +44,7 @@ def main() -> None: restored = store.stream("video_stats").first().data assert restored == message print( - f"Recorded {restored.__msgtype__}: {restored.width}x{restored.height}, {restored.fps} fps" + f"Recorded {restored.msg_name}: {restored.width}x{restored.height}, {restored.fps} fps" ) print(f"Exact dropped-frame counter: {restored.frames_dropped}") print(f"Source stamp: {restored.header.stamp.sec}s + {restored.header.stamp.nanosec}ns") diff --git a/examples/message-codegen/demo_viewer_controls.py b/examples/message-codegen/demo_viewer_controls.py index 7eb11133d60..c6a1ebfc3b4 100644 --- a/examples/message-codegen/demo_viewer_controls.py +++ b/examples/message-codegen/demo_viewer_controls.py @@ -18,8 +18,7 @@ import json from threading import Event -from dimos_generated.geometry_msgs.msg import PointStamped, Twist, Vector3 -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode +from dimos_generated.geometry_msgs.msg import PointStamped, Twist import websockets.asyncio.client as ws_client from dimos.core.global_config import GlobalConfig @@ -35,13 +34,13 @@ def main() -> None: stopped = Event() def receive_velocity(message: Twist) -> None: - velocities.append(cdr_decode(cdr_encode(message), Twist)) + velocities.append(Twist.decode(message.encode())) if len(velocities) == 2: stopped.set() subscriptions = [ server.clicked_point.subscribe( - lambda message: points.append(cdr_decode(cdr_encode(message), PointStamped)) + lambda message: points.append(PointStamped.decode(message.encode())) ), server.tele_cmd_vel.subscribe(receive_velocity), ] @@ -72,9 +71,7 @@ async def send_events() -> None: assert point.header.frame_id == "map" assert (point.header.stamp.sec, point.header.stamp.nanosec) == (1700000000, 123000000) assert velocities[0].linear.x == 0.5 and velocities[0].angular.z == 0.8 - assert velocities[1] == Twist( - linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0) - ) + assert velocities[1] == Twist() print("Viewer click → CDR PointStamped: map (1.5, 2.5, 0), stamp 1700000000.123000000") print("Viewer velocity → CDR Twist: forward 0.5 m/s, yaw 0.8 rad/s") print("Viewer stop → CDR Twist: all six components zero") diff --git a/examples/message-codegen/demo_visual_servo.py b/examples/message-codegen/demo_visual_servo.py index b54f842252a..d34f864db09 100644 --- a/examples/message-codegen/demo_visual_servo.py +++ b/examples/message-codegen/demo_visual_servo.py @@ -14,31 +14,15 @@ """Print CDR velocity commands for synthetic camera detections.""" -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.geometry_msgs.msg import Twist -from dimos_generated.sensor_msgs.msg import CameraInfo, RegionOfInterest -from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode -import numpy as np +from dimos_generated.sensor_msgs.msg import CameraInfo from dimos.navigation.visual_servoing.visual_servoing_2d import VisualServoing2D def main() -> None: - camera = CameraInfo( - width=640, - height=480, - k=np.array([500, 0, 320, 0, 500, 240, 0, 0, 1], dtype=np.float64), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - distortion_model="", - d=np.array([], dtype=np.float64), - r=np.zeros(9, dtype=np.float64), - p=np.zeros(12, dtype=np.float64), - binning_x=0, - binning_y=0, - roi=RegionOfInterest(x_offset=0, y_offset=0, height=0, width=0, do_rectify=False), - ) - controller = VisualServoing2D(cdr_decode(cdr_encode(camera), CameraInfo)) + camera = CameraInfo(width=640, height=480, k=[500, 0, 320, 0, 500, 240, 0, 0, 1]) + controller = VisualServoing2D(CameraInfo.decode(camera.encode())) for label, bbox, expected in ( ("far", (270, 0, 370, 100), (0.5, 0)), ("target distance", (245, 0, 395, 100), (0, 0)), @@ -46,7 +30,7 @@ def main() -> None: ("right of center", (370, 0, 470, 100), (0.36, -0.2)), ): command = controller.compute_twist(bbox, camera.width) - decoded = cdr_decode(cdr_encode(command), Twist) + decoded = Twist.decode(command.encode()) assert abs(decoded.linear.x - expected[0]) < 1e-9 assert abs(decoded.angular.z - expected[1]) < 1e-9 print(f"{label}: linear={decoded.linear.x:.2f} m/s, angular={decoded.angular.z:.2f} rad/s") diff --git a/examples/message-codegen/demo_vl_images.py b/examples/message-codegen/demo_vl_images.py index 81a67727832..dc09d6c7b58 100644 --- a/examples/message-codegen/demo_vl_images.py +++ b/examples/message-codegen/demo_vl_images.py @@ -14,11 +14,9 @@ """Exercise generated image preparation with a fixed model response, offline.""" -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.sensor_msgs.msg import Image from dimos_generated.std_msgs.msg import Header from dimos_generated.vision_msgs.msg import Detection2DArray -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode import numpy as np from dimos.models.vl.base import VlModel @@ -35,15 +33,13 @@ def stop(self) -> None: def main() -> None: image = image_from_array( - np.zeros((40, 60, 3), dtype=np.uint8), - encoding="rgb8", - header=Header(frame_id="camera", stamp=Time(sec=0, nanosec=0)), + np.zeros((40, 60, 3), dtype=np.uint8), encoding="rgb8", header=Header(frame_id="camera") ) model = FixedResponseModel(auto_resize=(30, 20)) resized, scale = model._prepare_image(image) assert (resized.width, resized.height, scale) == (30, 20, 0.5) detections = model.query_detections(image, "target") - wire = cdr_decode(cdr_encode(detections.to_ros_detection2d_array()), Detection2DArray) + wire = Detection2DArray.decode(detections.to_ros_detection2d_array().encode()) assert wire.header == image.header and len(wire.detections) == 1 print("Generated image: 60x40 → 30x20, scale=0.5") print("Fixed model response → one generated CDR detection; source header preserved") diff --git a/examples/message-codegen/demo_vlm_image.py b/examples/message-codegen/demo_vlm_image.py index 91677583d07..1e682394973 100644 --- a/examples/message-codegen/demo_vlm_image.py +++ b/examples/message-codegen/demo_vlm_image.py @@ -19,7 +19,6 @@ from unittest.mock import Mock, patch from dimos_generated.sensor_msgs.msg import Image -from dimos_message_build.registry import decode as cdr_decode, encode as cdr_encode from langchain_core.messages import AIMessage import numpy as np @@ -37,7 +36,7 @@ def main() -> None: with patch("langchain.chat_models.init_chat_model", return_value=model): agent = VLMAgent() try: - result = agent.query_image(cdr_decode(cdr_encode(image), Image), "Describe the colors") + result = agent.query_image(Image.decode(image.encode()), "Describe the colors") request = model.invoke.call_args.args[0][-1] encoded = request.content[1]["image_url"]["url"].split(",", 1)[1] destination = Path("build/message-codegen/demo/evidence/vlm-request.jpg") diff --git a/examples/message-codegen/demo_whole_body_transport.py b/examples/message-codegen/demo_whole_body_transport.py index 27b0bddefe1..66c2a234cde 100644 --- a/examples/message-codegen/demo_whole_body_transport.py +++ b/examples/message-codegen/demo_whole_body_transport.py @@ -21,12 +21,9 @@ import uuid from demo_pubsub import free_port -from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.dimos_msgs.msg import MotorCommandArray from dimos_generated.geometry_msgs.msg import Quaternion, Vector3 from dimos_generated.sensor_msgs.msg import Imu, JointState -from dimos_generated.std_msgs.msg import Header -import numpy as np from dimos.core.transport import LCMTransport, PubSubTransport, ZenohTransport from dimos.hardware.whole_body.spec import MotorCommand @@ -80,25 +77,9 @@ def collect(message: MotorCommandArray) -> None: def feedback_received() -> bool: states.publish( - JointState( - position=np.array([0.25, -0.5], dtype=np.float64), - velocity=np.array([0.1, 0.2], dtype=np.float64), - effort=np.array([1.0, 2.0], dtype=np.float64), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - name=[], - ) - ) - imu.publish( - Imu( - orientation=Quaternion(w=0.8, z=0.6, x=0.0, y=0.0), - angular_velocity=Vector3(z=0.2, x=0.0, y=0.0), - header=Header(stamp=Time(sec=0, nanosec=0), frame_id=""), - orientation_covariance=np.zeros(9, dtype=np.float64), - angular_velocity_covariance=np.zeros(9, dtype=np.float64), - linear_acceleration=Vector3(x=0.0, y=0.0, z=0.0), - linear_acceleration_covariance=np.zeros(9, dtype=np.float64), - ) + JointState(position=[0.25, -0.5], velocity=[0.1, 0.2], effort=[1.0, 2.0]) ) + imu.publish(Imu(orientation=Quaternion(w=0.8, z=0.6), angular_velocity=Vector3(z=0.2))) return adapter.has_motor_states() and adapter.read_imu().gyroscope[2] == 0.2 wait_until(feedback_received, timeout=5) diff --git a/examples/message-codegen/external-app/relay.cpp b/examples/message-codegen/external-app/relay.cpp index c88686ff4ce..9eced06291f 100644 --- a/examples/message-codegen/external-app/relay.cpp +++ b/examples/message-codegen/external-app/relay.cpp @@ -1,7 +1,5 @@ - - -#include -#include +#include +#include #include #include #include @@ -10,10 +8,10 @@ int main(int argc, char** argv) { if (argc != 3) return 2; std::ifstream input(argv[1], std::ios::binary); std::vector bytes{std::istreambuf_iterator(input), {}}; - auto value = dimos::native::cdr_decode(bytes); + auto value = dimos::cdr::decode(bytes); std::cout << "Installed C++ package received: " << value.application_note << '\n'; value.application_note += "/cpp"; - auto encoded = dimos::native::cdr_encode(value); + auto encoded = dimos::cdr::encode(value); std::ofstream output(argv[2], std::ios::binary); output.write(reinterpret_cast(encoded.data()), encoded.size()); return output ? 0 : 1; diff --git a/examples/message-codegen/external-native/relay.cpp b/examples/message-codegen/external-native/relay.cpp index ccf9d209e42..30e5ff884fe 100644 --- a/examples/message-codegen/external-native/relay.cpp +++ b/examples/message-codegen/external-native/relay.cpp @@ -1,9 +1,8 @@ // Copyright 2026 Dimensional Inc. // SPDX-License-Identifier: Apache-2.0 -#include #include "dimos/native.hpp" - +#include using demo_msgs::msg::Telemetry; using namespace dimos::native; diff --git a/examples/message-codegen/user-story/demo_module.py b/examples/message-codegen/user-story/demo_module.py index b4eb4bf68cd..c51495724f1 100644 --- a/examples/message-codegen/user-story/demo_module.py +++ b/examples/message-codegen/user-story/demo_module.py @@ -15,6 +15,7 @@ """Use an application-local generated message in a Python module and file relay.""" import argparse +import os from pathlib import Path import subprocess @@ -80,7 +81,10 @@ def main() -> None: ) subprocess.run( [ - str(args.build / "rust/target/debug/story-consumer"), + str( + Path(os.environ.get("CARGO_TARGET_DIR", args.build / "rust/target")) + / "debug/story-consumer" + ), str(evidence / "cpp.cdr"), str(evidence / "rust.cdr"), ], diff --git a/examples/message-project/demo_blueprint.py b/examples/message-project/demo_blueprint.py index a838f78c7b7..117d650a438 100644 --- a/examples/message-project/demo_blueprint.py +++ b/examples/message-project/demo_blueprint.py @@ -27,7 +27,6 @@ from dimos_cdrgen.registry import encode as cdr_encode from dimos_generated.builtin_interfaces.msg import Time from dimos_generated.std_msgs.msg import Header -from dimos_message_build.registry import encode as cdr_encode from story_messages.story_msgs.msg import DeviceReading from dimos.core.coordination.blueprints import Blueprint, autoconnect diff --git a/packages/dimos-generated/src/dimos_generated/_types.pyi b/packages/dimos-generated/src/dimos_generated/_types.pyi deleted file mode 100644 index cf6c9bc0286..00000000000 --- a/packages/dimos-generated/src/dimos_generated/_types.pyi +++ /dev/null @@ -1,2991 +0,0 @@ -# Copyright 2020 - 2025 Ternaris -# SPDX-License-Identifier: Apache-2.0 -# -# THIS FILE IS GENERATED, DO NOT EDIT -"""Message type definitions.""" - -# ruff: noqa: N801,N816,RUF100,TC004 - -from __future__ import annotations - -from dataclasses import dataclass -from typing import TYPE_CHECKING - -from rosbags.interfaces import Nodetype as T - -if TYPE_CHECKING: - from typing import ClassVar - - import numpy as np - from rosbags.interfaces.typing import Typesdict - -@dataclass -class builtin_interfaces__msg__Duration: - """Class for builtin_interfaces/msg/Duration.""" - - sec: int - nanosec: int - __msgtype__: ClassVar[str] = "builtin_interfaces/msg/Duration" - -@dataclass -class builtin_interfaces__msg__Time: - """Class for builtin_interfaces/msg/Time.""" - - sec: int - nanosec: int - __msgtype__: ClassVar[str] = "builtin_interfaces/msg/Time" - -@dataclass -class std_msgs__msg__Header: - """Class for std_msgs/msg/Header.""" - - stamp: builtin_interfaces__msg__Time - frame_id: str - __msgtype__: ClassVar[str] = "std_msgs/msg/Header" - -@dataclass -class vision_msgs__msg__Point2D: - """Class for vision_msgs/msg/Point2D.""" - - x: float - y: float - __msgtype__: ClassVar[str] = "vision_msgs/msg/Point2D" - -@dataclass -class vision_msgs__msg__Pose2D: - """Class for vision_msgs/msg/Pose2D.""" - - position: vision_msgs__msg__Point2D - theta: float - __msgtype__: ClassVar[str] = "vision_msgs/msg/Pose2D" - -@dataclass -class vision_msgs__msg__BoundingBox2D: - """Class for vision_msgs/msg/BoundingBox2D.""" - - center: vision_msgs__msg__Pose2D - size_x: float - size_y: float - __msgtype__: ClassVar[str] = "vision_msgs/msg/BoundingBox2D" - -@dataclass -class dimos_msgs__msg__BoundingBox2DArray: - """Class for dimos_msgs/msg/BoundingBox2DArray.""" - - header: std_msgs__msg__Header - boxes: list[vision_msgs__msg__BoundingBox2D] - __msgtype__: ClassVar[str] = "dimos_msgs/msg/BoundingBox2DArray" - -@dataclass -class geometry_msgs__msg__Point: - """Class for geometry_msgs/msg/Point.""" - - x: float - y: float - z: float - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Point" - -@dataclass -class geometry_msgs__msg__Quaternion: - """Class for geometry_msgs/msg/Quaternion.""" - - x: float - y: float - z: float - w: float - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Quaternion" - -@dataclass -class geometry_msgs__msg__Pose: - """Class for geometry_msgs/msg/Pose.""" - - position: geometry_msgs__msg__Point - orientation: geometry_msgs__msg__Quaternion - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Pose" - -@dataclass -class geometry_msgs__msg__Vector3: - """Class for geometry_msgs/msg/Vector3.""" - - x: float - y: float - z: float - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Vector3" - -@dataclass -class vision_msgs__msg__BoundingBox3D: - """Class for vision_msgs/msg/BoundingBox3D.""" - - center: geometry_msgs__msg__Pose - size: geometry_msgs__msg__Vector3 - __msgtype__: ClassVar[str] = "vision_msgs/msg/BoundingBox3D" - -@dataclass -class dimos_msgs__msg__BoundingBox3DArray: - """Class for dimos_msgs/msg/BoundingBox3DArray.""" - - header: std_msgs__msg__Header - boxes: list[vision_msgs__msg__BoundingBox3D] - __msgtype__: ClassVar[str] = "dimos_msgs/msg/BoundingBox3DArray" - -@dataclass -class dimos_msgs__msg__EntityMarker: - """Class for dimos_msgs/msg/EntityMarker.""" - - entity_id: str - label: str - entity_type: str - position: geometry_msgs__msg__Point - __msgtype__: ClassVar[str] = "dimos_msgs/msg/EntityMarker" - -@dataclass -class dimos_msgs__msg__EntityMarkers: - """Class for dimos_msgs/msg/EntityMarkers.""" - - header: std_msgs__msg__Header - markers: list[dimos_msgs__msg__EntityMarker] - __msgtype__: ClassVar[str] = "dimos_msgs/msg/EntityMarkers" - -@dataclass -class dimos_msgs__msg__GraspCandidate: - """Class for dimos_msgs/msg/GraspCandidate.""" - - pose: geometry_msgs__msg__Pose - score: float - __msgtype__: ClassVar[str] = "dimos_msgs/msg/GraspCandidate" - -@dataclass -class dimos_msgs__msg__GraspCandidateArray: - """Class for dimos_msgs/msg/GraspCandidateArray.""" - - header: std_msgs__msg__Header - candidates: list[dimos_msgs__msg__GraspCandidate] - __msgtype__: ClassVar[str] = "dimos_msgs/msg/GraspCandidateArray" - -@dataclass -class dimos_msgs__msg__ImuInfo: - """Class for dimos_msgs/msg/ImuInfo.""" - - header: std_msgs__msg__Header - gyro_noise_density: float - gyro_random_walk: float - accel_noise_density: float - accel_random_walk: float - frequency: float - __msgtype__: ClassVar[str] = "dimos_msgs/msg/ImuInfo" - -@dataclass -class dimos_msgs__msg__JointCommand: - """Class for dimos_msgs/msg/JointCommand.""" - - header: std_msgs__msg__Header - positions: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = "dimos_msgs/msg/JointCommand" - -@dataclass -class dimos_msgs__msg__LineSegment3D: - """Class for dimos_msgs/msg/LineSegment3D.""" - - start: geometry_msgs__msg__Point - end: geometry_msgs__msg__Point - weight: float - __msgtype__: ClassVar[str] = "dimos_msgs/msg/LineSegment3D" - -@dataclass -class dimos_msgs__msg__LineSegments3D: - """Class for dimos_msgs/msg/LineSegments3D.""" - - header: std_msgs__msg__Header - segments: list[dimos_msgs__msg__LineSegment3D] - __msgtype__: ClassVar[str] = "dimos_msgs/msg/LineSegments3D" - -@dataclass -class dimos_msgs__msg__MotorCommandArray: - """Class for dimos_msgs/msg/MotorCommandArray.""" - - header: std_msgs__msg__Header - q: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - dq: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - kp: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - kd: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - tau: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = "dimos_msgs/msg/MotorCommandArray" - -@dataclass -class dimos_msgs__msg__RobotState: - """Class for dimos_msgs/msg/RobotState.""" - - header: std_msgs__msg__Header - state: int - mode: int - error_code: int - warn_code: int - cmdnum: int - mt_brake: int - mt_able: int - tcp_pose: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - tcp_offset: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - joints: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = "dimos_msgs/msg/RobotState" - -@dataclass -class dimos_msgs__msg__TrajectoryStatus: - """Class for dimos_msgs/msg/TrajectoryStatus.""" - - header: std_msgs__msg__Header - state: int - progress: float - time_elapsed: builtin_interfaces__msg__Duration - time_remaining: builtin_interfaces__msg__Duration - error: str - IDLE: ClassVar[int] = 0 - EXECUTING: ClassVar[int] = 1 - COMPLETED: ClassVar[int] = 2 - ABORTED: ClassVar[int] = 3 - FAULT: ClassVar[int] = 4 - __msgtype__: ClassVar[str] = "dimos_msgs/msg/TrajectoryStatus" - -@dataclass -class dimos_msgs__msg__VideoStats: - """Class for dimos_msgs/msg/VideoStats.""" - - header: std_msgs__msg__Header - fps: float - kbps: float - width: int - height: int - loss_pct: float - jitter_buffer_ms: float - decode_ms: float - frames_dropped: int - freezes: int - e2e_latency_ms: float - __msgtype__: ClassVar[str] = "dimos_msgs/msg/VideoStats" - -@dataclass -class foxglove_msgs__msg__CompressedVideo: - """Class for foxglove_msgs/msg/CompressedVideo.""" - - timestamp: builtin_interfaces__msg__Time - frame_id: str - data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - format: str - __msgtype__: ClassVar[str] = "foxglove_msgs/msg/CompressedVideo" - -@dataclass -class geometry_msgs__msg__Accel: - """Class for geometry_msgs/msg/Accel.""" - - linear: geometry_msgs__msg__Vector3 - angular: geometry_msgs__msg__Vector3 - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Accel" - -@dataclass -class geometry_msgs__msg__AccelStamped: - """Class for geometry_msgs/msg/AccelStamped.""" - - header: std_msgs__msg__Header - accel: geometry_msgs__msg__Accel - __msgtype__: ClassVar[str] = "geometry_msgs/msg/AccelStamped" - -@dataclass -class geometry_msgs__msg__AccelWithCovariance: - """Class for geometry_msgs/msg/AccelWithCovariance.""" - - accel: geometry_msgs__msg__Accel - covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = "geometry_msgs/msg/AccelWithCovariance" - -@dataclass -class geometry_msgs__msg__AccelWithCovarianceStamped: - """Class for geometry_msgs/msg/AccelWithCovarianceStamped.""" - - header: std_msgs__msg__Header - accel: geometry_msgs__msg__AccelWithCovariance - __msgtype__: ClassVar[str] = "geometry_msgs/msg/AccelWithCovarianceStamped" - -@dataclass -class geometry_msgs__msg__Inertia: - """Class for geometry_msgs/msg/Inertia.""" - - m: float - com: geometry_msgs__msg__Vector3 - ixx: float - ixy: float - ixz: float - iyy: float - iyz: float - izz: float - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Inertia" - -@dataclass -class geometry_msgs__msg__InertiaStamped: - """Class for geometry_msgs/msg/InertiaStamped.""" - - header: std_msgs__msg__Header - inertia: geometry_msgs__msg__Inertia - __msgtype__: ClassVar[str] = "geometry_msgs/msg/InertiaStamped" - -@dataclass -class geometry_msgs__msg__Point32: - """Class for geometry_msgs/msg/Point32.""" - - x: float - y: float - z: float - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Point32" - -@dataclass -class geometry_msgs__msg__PointStamped: - """Class for geometry_msgs/msg/PointStamped.""" - - header: std_msgs__msg__Header - point: geometry_msgs__msg__Point - __msgtype__: ClassVar[str] = "geometry_msgs/msg/PointStamped" - -@dataclass -class geometry_msgs__msg__Polygon: - """Class for geometry_msgs/msg/Polygon.""" - - points: list[geometry_msgs__msg__Point32] - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Polygon" - -@dataclass -class geometry_msgs__msg__PolygonInstance: - """Class for geometry_msgs/msg/PolygonInstance.""" - - polygon: geometry_msgs__msg__Polygon - id: int - __msgtype__: ClassVar[str] = "geometry_msgs/msg/PolygonInstance" - -@dataclass -class geometry_msgs__msg__PolygonInstanceStamped: - """Class for geometry_msgs/msg/PolygonInstanceStamped.""" - - header: std_msgs__msg__Header - polygon: geometry_msgs__msg__PolygonInstance - __msgtype__: ClassVar[str] = "geometry_msgs/msg/PolygonInstanceStamped" - -@dataclass -class geometry_msgs__msg__PolygonStamped: - """Class for geometry_msgs/msg/PolygonStamped.""" - - header: std_msgs__msg__Header - polygon: geometry_msgs__msg__Polygon - __msgtype__: ClassVar[str] = "geometry_msgs/msg/PolygonStamped" - -@dataclass -class geometry_msgs__msg__Pose2D: - """Class for geometry_msgs/msg/Pose2D.""" - - x: float - y: float - theta: float - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Pose2D" - -@dataclass -class geometry_msgs__msg__PoseArray: - """Class for geometry_msgs/msg/PoseArray.""" - - header: std_msgs__msg__Header - poses: list[geometry_msgs__msg__Pose] - __msgtype__: ClassVar[str] = "geometry_msgs/msg/PoseArray" - -@dataclass -class geometry_msgs__msg__PoseStamped: - """Class for geometry_msgs/msg/PoseStamped.""" - - header: std_msgs__msg__Header - pose: geometry_msgs__msg__Pose - __msgtype__: ClassVar[str] = "geometry_msgs/msg/PoseStamped" - -@dataclass -class geometry_msgs__msg__PoseWithCovariance: - """Class for geometry_msgs/msg/PoseWithCovariance.""" - - pose: geometry_msgs__msg__Pose - covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = "geometry_msgs/msg/PoseWithCovariance" - -@dataclass -class geometry_msgs__msg__PoseWithCovarianceStamped: - """Class for geometry_msgs/msg/PoseWithCovarianceStamped.""" - - header: std_msgs__msg__Header - pose: geometry_msgs__msg__PoseWithCovariance - __msgtype__: ClassVar[str] = "geometry_msgs/msg/PoseWithCovarianceStamped" - -@dataclass -class geometry_msgs__msg__QuaternionStamped: - """Class for geometry_msgs/msg/QuaternionStamped.""" - - header: std_msgs__msg__Header - quaternion: geometry_msgs__msg__Quaternion - __msgtype__: ClassVar[str] = "geometry_msgs/msg/QuaternionStamped" - -@dataclass -class geometry_msgs__msg__Transform: - """Class for geometry_msgs/msg/Transform.""" - - translation: geometry_msgs__msg__Vector3 - rotation: geometry_msgs__msg__Quaternion - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Transform" - -@dataclass -class geometry_msgs__msg__TransformStamped: - """Class for geometry_msgs/msg/TransformStamped.""" - - header: std_msgs__msg__Header - child_frame_id: str - transform: geometry_msgs__msg__Transform - __msgtype__: ClassVar[str] = "geometry_msgs/msg/TransformStamped" - -@dataclass -class geometry_msgs__msg__Twist: - """Class for geometry_msgs/msg/Twist.""" - - linear: geometry_msgs__msg__Vector3 - angular: geometry_msgs__msg__Vector3 - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Twist" - -@dataclass -class geometry_msgs__msg__TwistStamped: - """Class for geometry_msgs/msg/TwistStamped.""" - - header: std_msgs__msg__Header - twist: geometry_msgs__msg__Twist - __msgtype__: ClassVar[str] = "geometry_msgs/msg/TwistStamped" - -@dataclass -class geometry_msgs__msg__TwistWithCovariance: - """Class for geometry_msgs/msg/TwistWithCovariance.""" - - twist: geometry_msgs__msg__Twist - covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = "geometry_msgs/msg/TwistWithCovariance" - -@dataclass -class geometry_msgs__msg__TwistWithCovarianceStamped: - """Class for geometry_msgs/msg/TwistWithCovarianceStamped.""" - - header: std_msgs__msg__Header - twist: geometry_msgs__msg__TwistWithCovariance - __msgtype__: ClassVar[str] = "geometry_msgs/msg/TwistWithCovarianceStamped" - -@dataclass -class geometry_msgs__msg__Vector3Stamped: - """Class for geometry_msgs/msg/Vector3Stamped.""" - - header: std_msgs__msg__Header - vector: geometry_msgs__msg__Vector3 - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Vector3Stamped" - -@dataclass -class geometry_msgs__msg__VelocityStamped: - """Class for geometry_msgs/msg/VelocityStamped.""" - - header: std_msgs__msg__Header - body_frame_id: str - reference_frame_id: str - velocity: geometry_msgs__msg__Twist - __msgtype__: ClassVar[str] = "geometry_msgs/msg/VelocityStamped" - -@dataclass -class geometry_msgs__msg__VelocityWithCovarianceStamped: - """Class for geometry_msgs/msg/VelocityWithCovarianceStamped.""" - - header: std_msgs__msg__Header - body_frame_id: str - reference_frame_id: str - velocity: geometry_msgs__msg__TwistWithCovariance - __msgtype__: ClassVar[str] = "geometry_msgs/msg/VelocityWithCovarianceStamped" - -@dataclass -class geometry_msgs__msg__Wrench: - """Class for geometry_msgs/msg/Wrench.""" - - force: geometry_msgs__msg__Vector3 - torque: geometry_msgs__msg__Vector3 - __msgtype__: ClassVar[str] = "geometry_msgs/msg/Wrench" - -@dataclass -class geometry_msgs__msg__WrenchStamped: - """Class for geometry_msgs/msg/WrenchStamped.""" - - header: std_msgs__msg__Header - wrench: geometry_msgs__msg__Wrench - __msgtype__: ClassVar[str] = "geometry_msgs/msg/WrenchStamped" - -@dataclass -class nav_msgs__msg__Goals: - """Class for nav_msgs/msg/Goals.""" - - header: std_msgs__msg__Header - goals: list[geometry_msgs__msg__PoseStamped] - __msgtype__: ClassVar[str] = "nav_msgs/msg/Goals" - -@dataclass -class nav_msgs__msg__GridCells: - """Class for nav_msgs/msg/GridCells.""" - - header: std_msgs__msg__Header - cell_width: float - cell_height: float - cells: list[geometry_msgs__msg__Point] - __msgtype__: ClassVar[str] = "nav_msgs/msg/GridCells" - -@dataclass -class nav_msgs__msg__MapMetaData: - """Class for nav_msgs/msg/MapMetaData.""" - - map_load_time: builtin_interfaces__msg__Time - resolution: float - width: int - height: int - origin: geometry_msgs__msg__Pose - __msgtype__: ClassVar[str] = "nav_msgs/msg/MapMetaData" - -@dataclass -class nav_msgs__msg__OccupancyGrid: - """Class for nav_msgs/msg/OccupancyGrid.""" - - header: std_msgs__msg__Header - info: nav_msgs__msg__MapMetaData - data: np.ndarray[tuple[int, ...], np.dtype[np.int8]] - __msgtype__: ClassVar[str] = "nav_msgs/msg/OccupancyGrid" - -@dataclass -class nav_msgs__msg__Odometry: - """Class for nav_msgs/msg/Odometry.""" - - header: std_msgs__msg__Header - child_frame_id: str - pose: geometry_msgs__msg__PoseWithCovariance - twist: geometry_msgs__msg__TwistWithCovariance - __msgtype__: ClassVar[str] = "nav_msgs/msg/Odometry" - -@dataclass -class nav_msgs__msg__Path: - """Class for nav_msgs/msg/Path.""" - - header: std_msgs__msg__Header - poses: list[geometry_msgs__msg__PoseStamped] - __msgtype__: ClassVar[str] = "nav_msgs/msg/Path" - -@dataclass -class nav_msgs__msg__TrajectoryPoint: - """Class for nav_msgs/msg/TrajectoryPoint.""" - - header: std_msgs__msg__Header - pose: geometry_msgs__msg__Pose - velocity: geometry_msgs__msg__Twist - acceleration: geometry_msgs__msg__Accel - effort: geometry_msgs__msg__Wrench - __msgtype__: ClassVar[str] = "nav_msgs/msg/TrajectoryPoint" - -@dataclass -class nav_msgs__msg__Trajectory: - """Class for nav_msgs/msg/Trajectory.""" - - header: std_msgs__msg__Header - points: list[nav_msgs__msg__TrajectoryPoint] - __msgtype__: ClassVar[str] = "nav_msgs/msg/Trajectory" - -@dataclass -class sensor_msgs__msg__BatteryState: - """Class for sensor_msgs/msg/BatteryState.""" - - header: std_msgs__msg__Header - voltage: float - temperature: float - current: float - charge: float - capacity: float - design_capacity: float - percentage: float - power_supply_status: int - power_supply_health: int - power_supply_technology: int - present: bool - cell_voltage: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - cell_temperature: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - location: str - serial_number: str - POWER_SUPPLY_STATUS_UNKNOWN: ClassVar[int] = 0 - POWER_SUPPLY_STATUS_CHARGING: ClassVar[int] = 1 - POWER_SUPPLY_STATUS_DISCHARGING: ClassVar[int] = 2 - POWER_SUPPLY_STATUS_NOT_CHARGING: ClassVar[int] = 3 - POWER_SUPPLY_STATUS_FULL: ClassVar[int] = 4 - POWER_SUPPLY_HEALTH_UNKNOWN: ClassVar[int] = 0 - POWER_SUPPLY_HEALTH_GOOD: ClassVar[int] = 1 - POWER_SUPPLY_HEALTH_OVERHEAT: ClassVar[int] = 2 - POWER_SUPPLY_HEALTH_DEAD: ClassVar[int] = 3 - POWER_SUPPLY_HEALTH_OVERVOLTAGE: ClassVar[int] = 4 - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE: ClassVar[int] = 5 - POWER_SUPPLY_HEALTH_COLD: ClassVar[int] = 6 - POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE: ClassVar[int] = 7 - POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE: ClassVar[int] = 8 - POWER_SUPPLY_TECHNOLOGY_UNKNOWN: ClassVar[int] = 0 - POWER_SUPPLY_TECHNOLOGY_NIMH: ClassVar[int] = 1 - POWER_SUPPLY_TECHNOLOGY_LION: ClassVar[int] = 2 - POWER_SUPPLY_TECHNOLOGY_LIPO: ClassVar[int] = 3 - POWER_SUPPLY_TECHNOLOGY_LIFE: ClassVar[int] = 4 - POWER_SUPPLY_TECHNOLOGY_NICD: ClassVar[int] = 5 - POWER_SUPPLY_TECHNOLOGY_LIMN: ClassVar[int] = 6 - POWER_SUPPLY_TECHNOLOGY_TERNARY: ClassVar[int] = 7 - POWER_SUPPLY_TECHNOLOGY_VRLA: ClassVar[int] = 8 - __msgtype__: ClassVar[str] = "sensor_msgs/msg/BatteryState" - -@dataclass -class sensor_msgs__msg__RegionOfInterest: - """Class for sensor_msgs/msg/RegionOfInterest.""" - - x_offset: int - y_offset: int - height: int - width: int - do_rectify: bool - __msgtype__: ClassVar[str] = "sensor_msgs/msg/RegionOfInterest" - -@dataclass -class sensor_msgs__msg__CameraInfo: - """Class for sensor_msgs/msg/CameraInfo.""" - - header: std_msgs__msg__Header - height: int - width: int - distortion_model: str - d: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - k: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - r: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - p: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - binning_x: int - binning_y: int - roi: sensor_msgs__msg__RegionOfInterest - __msgtype__: ClassVar[str] = "sensor_msgs/msg/CameraInfo" - -@dataclass -class sensor_msgs__msg__ChannelFloat32: - """Class for sensor_msgs/msg/ChannelFloat32.""" - - name: str - values: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/ChannelFloat32" - -@dataclass -class sensor_msgs__msg__CompressedImage: - """Class for sensor_msgs/msg/CompressedImage.""" - - header: std_msgs__msg__Header - format: str - data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/CompressedImage" - -@dataclass -class sensor_msgs__msg__FluidPressure: - """Class for sensor_msgs/msg/FluidPressure.""" - - header: std_msgs__msg__Header - fluid_pressure: float - variance: float - __msgtype__: ClassVar[str] = "sensor_msgs/msg/FluidPressure" - -@dataclass -class sensor_msgs__msg__Illuminance: - """Class for sensor_msgs/msg/Illuminance.""" - - header: std_msgs__msg__Header - illuminance: float - variance: float - __msgtype__: ClassVar[str] = "sensor_msgs/msg/Illuminance" - -@dataclass -class sensor_msgs__msg__Image: - """Class for sensor_msgs/msg/Image.""" - - header: std_msgs__msg__Header - height: int - width: int - encoding: str - is_bigendian: int - step: int - data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/Image" - -@dataclass -class sensor_msgs__msg__Imu: - """Class for sensor_msgs/msg/Imu.""" - - header: std_msgs__msg__Header - orientation: geometry_msgs__msg__Quaternion - orientation_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - angular_velocity: geometry_msgs__msg__Vector3 - angular_velocity_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - linear_acceleration: geometry_msgs__msg__Vector3 - linear_acceleration_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/Imu" - -@dataclass -class sensor_msgs__msg__JointState: - """Class for sensor_msgs/msg/JointState.""" - - header: std_msgs__msg__Header - name: list[str] - position: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - velocity: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - effort: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/JointState" - -@dataclass -class sensor_msgs__msg__Joy: - """Class for sensor_msgs/msg/Joy.""" - - header: std_msgs__msg__Header - axes: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - buttons: np.ndarray[tuple[int, ...], np.dtype[np.int32]] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/Joy" - -@dataclass -class sensor_msgs__msg__JoyFeedback: - """Class for sensor_msgs/msg/JoyFeedback.""" - - type: int - id: int - intensity: float - TYPE_LED: ClassVar[int] = 0 - TYPE_RUMBLE: ClassVar[int] = 1 - TYPE_BUZZER: ClassVar[int] = 2 - __msgtype__: ClassVar[str] = "sensor_msgs/msg/JoyFeedback" - -@dataclass -class sensor_msgs__msg__JoyFeedbackArray: - """Class for sensor_msgs/msg/JoyFeedbackArray.""" - - array: list[sensor_msgs__msg__JoyFeedback] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/JoyFeedbackArray" - -@dataclass -class sensor_msgs__msg__LaserEcho: - """Class for sensor_msgs/msg/LaserEcho.""" - - echoes: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/LaserEcho" - -@dataclass -class sensor_msgs__msg__LaserScan: - """Class for sensor_msgs/msg/LaserScan.""" - - header: std_msgs__msg__Header - angle_min: float - angle_max: float - angle_increment: float - time_increment: float - scan_time: float - range_min: float - range_max: float - ranges: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - intensities: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/LaserScan" - -@dataclass -class sensor_msgs__msg__MagneticField: - """Class for sensor_msgs/msg/MagneticField.""" - - header: std_msgs__msg__Header - magnetic_field: geometry_msgs__msg__Vector3 - magnetic_field_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/MagneticField" - -@dataclass -class sensor_msgs__msg__MultiDOFJointState: - """Class for sensor_msgs/msg/MultiDOFJointState.""" - - header: std_msgs__msg__Header - joint_names: list[str] - transforms: list[geometry_msgs__msg__Transform] - twist: list[geometry_msgs__msg__Twist] - wrench: list[geometry_msgs__msg__Wrench] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/MultiDOFJointState" - -@dataclass -class sensor_msgs__msg__MultiEchoLaserScan: - """Class for sensor_msgs/msg/MultiEchoLaserScan.""" - - header: std_msgs__msg__Header - angle_min: float - angle_max: float - angle_increment: float - time_increment: float - scan_time: float - range_min: float - range_max: float - ranges: list[sensor_msgs__msg__LaserEcho] - intensities: list[sensor_msgs__msg__LaserEcho] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/MultiEchoLaserScan" - -@dataclass -class sensor_msgs__msg__NavSatStatus: - """Class for sensor_msgs/msg/NavSatStatus.""" - - status: int - service: int - STATUS_UNKNOWN: ClassVar[int] = -2 - STATUS_NO_FIX: ClassVar[int] = -1 - STATUS_FIX: ClassVar[int] = 0 - STATUS_SBAS_FIX: ClassVar[int] = 1 - STATUS_GBAS_FIX: ClassVar[int] = 2 - SERVICE_UNKNOWN: ClassVar[int] = 0 - SERVICE_GPS: ClassVar[int] = 1 - SERVICE_GLONASS: ClassVar[int] = 2 - SERVICE_COMPASS: ClassVar[int] = 4 - SERVICE_GALILEO: ClassVar[int] = 8 - __msgtype__: ClassVar[str] = "sensor_msgs/msg/NavSatStatus" - -@dataclass -class sensor_msgs__msg__NavSatFix: - """Class for sensor_msgs/msg/NavSatFix.""" - - header: std_msgs__msg__Header - status: sensor_msgs__msg__NavSatStatus - latitude: float - longitude: float - altitude: float - position_covariance: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - position_covariance_type: int - COVARIANCE_TYPE_UNKNOWN: ClassVar[int] = 0 - COVARIANCE_TYPE_APPROXIMATED: ClassVar[int] = 1 - COVARIANCE_TYPE_DIAGONAL_KNOWN: ClassVar[int] = 2 - COVARIANCE_TYPE_KNOWN: ClassVar[int] = 3 - __msgtype__: ClassVar[str] = "sensor_msgs/msg/NavSatFix" - -@dataclass -class sensor_msgs__msg__PointCloud: - """Class for sensor_msgs/msg/PointCloud.""" - - header: std_msgs__msg__Header - points: list[geometry_msgs__msg__Point32] - channels: list[sensor_msgs__msg__ChannelFloat32] - __msgtype__: ClassVar[str] = "sensor_msgs/msg/PointCloud" - -@dataclass -class sensor_msgs__msg__PointField: - """Class for sensor_msgs/msg/PointField.""" - - name: str - offset: int - datatype: int - count: int - INT8: ClassVar[int] = 1 - UINT8: ClassVar[int] = 2 - INT16: ClassVar[int] = 3 - UINT16: ClassVar[int] = 4 - INT32: ClassVar[int] = 5 - UINT32: ClassVar[int] = 6 - FLOAT32: ClassVar[int] = 7 - FLOAT64: ClassVar[int] = 8 - __msgtype__: ClassVar[str] = "sensor_msgs/msg/PointField" - -@dataclass -class sensor_msgs__msg__PointCloud2: - """Class for sensor_msgs/msg/PointCloud2.""" - - header: std_msgs__msg__Header - height: int - width: int - fields: list[sensor_msgs__msg__PointField] - is_bigendian: bool - point_step: int - row_step: int - data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - is_dense: bool - __msgtype__: ClassVar[str] = "sensor_msgs/msg/PointCloud2" - -@dataclass -class sensor_msgs__msg__Range: - """Class for sensor_msgs/msg/Range.""" - - header: std_msgs__msg__Header - radiation_type: int - field_of_view: float - min_range: float - max_range: float - range: float - variance: float - ULTRASOUND: ClassVar[int] = 0 - INFRARED: ClassVar[int] = 1 - __msgtype__: ClassVar[str] = "sensor_msgs/msg/Range" - -@dataclass -class sensor_msgs__msg__RelativeHumidity: - """Class for sensor_msgs/msg/RelativeHumidity.""" - - header: std_msgs__msg__Header - relative_humidity: float - variance: float - __msgtype__: ClassVar[str] = "sensor_msgs/msg/RelativeHumidity" - -@dataclass -class sensor_msgs__msg__Temperature: - """Class for sensor_msgs/msg/Temperature.""" - - header: std_msgs__msg__Header - temperature: float - variance: float - __msgtype__: ClassVar[str] = "sensor_msgs/msg/Temperature" - -@dataclass -class sensor_msgs__msg__TimeReference: - """Class for sensor_msgs/msg/TimeReference.""" - - header: std_msgs__msg__Header - time_ref: builtin_interfaces__msg__Time - source: str - __msgtype__: ClassVar[str] = "sensor_msgs/msg/TimeReference" - -@dataclass -class shape_msgs__msg__MeshTriangle: - """Class for shape_msgs/msg/MeshTriangle.""" - - vertex_indices: np.ndarray[tuple[int, ...], np.dtype[np.uint32]] - __msgtype__: ClassVar[str] = "shape_msgs/msg/MeshTriangle" - -@dataclass -class shape_msgs__msg__Mesh: - """Class for shape_msgs/msg/Mesh.""" - - triangles: list[shape_msgs__msg__MeshTriangle] - vertices: list[geometry_msgs__msg__Point] - __msgtype__: ClassVar[str] = "shape_msgs/msg/Mesh" - -@dataclass -class shape_msgs__msg__Plane: - """Class for shape_msgs/msg/Plane.""" - - coef: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = "shape_msgs/msg/Plane" - -@dataclass -class shape_msgs__msg__SolidPrimitive: - """Class for shape_msgs/msg/SolidPrimitive.""" - - type: int - dimensions: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - polygon: geometry_msgs__msg__Polygon - BOX: ClassVar[int] = 1 - SPHERE: ClassVar[int] = 2 - CYLINDER: ClassVar[int] = 3 - CONE: ClassVar[int] = 4 - PRISM: ClassVar[int] = 5 - BOX_X: ClassVar[int] = 0 - BOX_Y: ClassVar[int] = 1 - BOX_Z: ClassVar[int] = 2 - SPHERE_RADIUS: ClassVar[int] = 0 - CYLINDER_HEIGHT: ClassVar[int] = 0 - CYLINDER_RADIUS: ClassVar[int] = 1 - CONE_HEIGHT: ClassVar[int] = 0 - CONE_RADIUS: ClassVar[int] = 1 - PRISM_HEIGHT: ClassVar[int] = 0 - __msgtype__: ClassVar[str] = "shape_msgs/msg/SolidPrimitive" - -@dataclass -class std_msgs__msg__Bool: - """Class for std_msgs/msg/Bool.""" - - data: bool - __msgtype__: ClassVar[str] = "std_msgs/msg/Bool" - -@dataclass -class std_msgs__msg__Byte: - """Class for std_msgs/msg/Byte.""" - - data: int - __msgtype__: ClassVar[str] = "std_msgs/msg/Byte" - -@dataclass -class std_msgs__msg__MultiArrayDimension: - """Class for std_msgs/msg/MultiArrayDimension.""" - - label: str - size: int - stride: int - __msgtype__: ClassVar[str] = "std_msgs/msg/MultiArrayDimension" - -@dataclass -class std_msgs__msg__MultiArrayLayout: - """Class for std_msgs/msg/MultiArrayLayout.""" - - dim: list[std_msgs__msg__MultiArrayDimension] - data_offset: int - __msgtype__: ClassVar[str] = "std_msgs/msg/MultiArrayLayout" - -@dataclass -class std_msgs__msg__ByteMultiArray: - """Class for std_msgs/msg/ByteMultiArray.""" - - layout: std_msgs__msg__MultiArrayLayout - data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - __msgtype__: ClassVar[str] = "std_msgs/msg/ByteMultiArray" - -@dataclass -class std_msgs__msg__Char: - """Class for std_msgs/msg/Char.""" - - data: int - __msgtype__: ClassVar[str] = "std_msgs/msg/Char" - -@dataclass -class std_msgs__msg__ColorRGBA: - """Class for std_msgs/msg/ColorRGBA.""" - - r: float - g: float - b: float - a: float - __msgtype__: ClassVar[str] = "std_msgs/msg/ColorRGBA" - -@dataclass -class std_msgs__msg__Empty: - """Class for std_msgs/msg/Empty.""" - - structure_needs_at_least_one_member: int = 0 - __msgtype__: ClassVar[str] = "std_msgs/msg/Empty" - -@dataclass -class std_msgs__msg__Float32: - """Class for std_msgs/msg/Float32.""" - - data: float - __msgtype__: ClassVar[str] = "std_msgs/msg/Float32" - -@dataclass -class std_msgs__msg__Float32MultiArray: - """Class for std_msgs/msg/Float32MultiArray.""" - - layout: std_msgs__msg__MultiArrayLayout - data: np.ndarray[tuple[int, ...], np.dtype[np.float32]] - __msgtype__: ClassVar[str] = "std_msgs/msg/Float32MultiArray" - -@dataclass -class std_msgs__msg__Float64: - """Class for std_msgs/msg/Float64.""" - - data: float - __msgtype__: ClassVar[str] = "std_msgs/msg/Float64" - -@dataclass -class std_msgs__msg__Float64MultiArray: - """Class for std_msgs/msg/Float64MultiArray.""" - - layout: std_msgs__msg__MultiArrayLayout - data: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - __msgtype__: ClassVar[str] = "std_msgs/msg/Float64MultiArray" - -@dataclass -class std_msgs__msg__Int16: - """Class for std_msgs/msg/Int16.""" - - data: int - __msgtype__: ClassVar[str] = "std_msgs/msg/Int16" - -@dataclass -class std_msgs__msg__Int16MultiArray: - """Class for std_msgs/msg/Int16MultiArray.""" - - layout: std_msgs__msg__MultiArrayLayout - data: np.ndarray[tuple[int, ...], np.dtype[np.int16]] - __msgtype__: ClassVar[str] = "std_msgs/msg/Int16MultiArray" - -@dataclass -class std_msgs__msg__Int32: - """Class for std_msgs/msg/Int32.""" - - data: int - __msgtype__: ClassVar[str] = "std_msgs/msg/Int32" - -@dataclass -class std_msgs__msg__Int32MultiArray: - """Class for std_msgs/msg/Int32MultiArray.""" - - layout: std_msgs__msg__MultiArrayLayout - data: np.ndarray[tuple[int, ...], np.dtype[np.int32]] - __msgtype__: ClassVar[str] = "std_msgs/msg/Int32MultiArray" - -@dataclass -class std_msgs__msg__Int64: - """Class for std_msgs/msg/Int64.""" - - data: int - __msgtype__: ClassVar[str] = "std_msgs/msg/Int64" - -@dataclass -class std_msgs__msg__Int64MultiArray: - """Class for std_msgs/msg/Int64MultiArray.""" - - layout: std_msgs__msg__MultiArrayLayout - data: np.ndarray[tuple[int, ...], np.dtype[np.int64]] - __msgtype__: ClassVar[str] = "std_msgs/msg/Int64MultiArray" - -@dataclass -class std_msgs__msg__Int8: - """Class for std_msgs/msg/Int8.""" - - data: int - __msgtype__: ClassVar[str] = "std_msgs/msg/Int8" - -@dataclass -class std_msgs__msg__Int8MultiArray: - """Class for std_msgs/msg/Int8MultiArray.""" - - layout: std_msgs__msg__MultiArrayLayout - data: np.ndarray[tuple[int, ...], np.dtype[np.int8]] - __msgtype__: ClassVar[str] = "std_msgs/msg/Int8MultiArray" - -@dataclass -class std_msgs__msg__String: - """Class for std_msgs/msg/String.""" - - data: str - __msgtype__: ClassVar[str] = "std_msgs/msg/String" - -@dataclass -class std_msgs__msg__UInt16: - """Class for std_msgs/msg/UInt16.""" - - data: int - __msgtype__: ClassVar[str] = "std_msgs/msg/UInt16" - -@dataclass -class std_msgs__msg__UInt16MultiArray: - """Class for std_msgs/msg/UInt16MultiArray.""" - - layout: std_msgs__msg__MultiArrayLayout - data: np.ndarray[tuple[int, ...], np.dtype[np.uint16]] - __msgtype__: ClassVar[str] = "std_msgs/msg/UInt16MultiArray" - -@dataclass -class std_msgs__msg__UInt32: - """Class for std_msgs/msg/UInt32.""" - - data: int - __msgtype__: ClassVar[str] = "std_msgs/msg/UInt32" - -@dataclass -class std_msgs__msg__UInt32MultiArray: - """Class for std_msgs/msg/UInt32MultiArray.""" - - layout: std_msgs__msg__MultiArrayLayout - data: np.ndarray[tuple[int, ...], np.dtype[np.uint32]] - __msgtype__: ClassVar[str] = "std_msgs/msg/UInt32MultiArray" - -@dataclass -class std_msgs__msg__UInt64: - """Class for std_msgs/msg/UInt64.""" - - data: int - __msgtype__: ClassVar[str] = "std_msgs/msg/UInt64" - -@dataclass -class std_msgs__msg__UInt64MultiArray: - """Class for std_msgs/msg/UInt64MultiArray.""" - - layout: std_msgs__msg__MultiArrayLayout - data: np.ndarray[tuple[int, ...], np.dtype[np.uint64]] - __msgtype__: ClassVar[str] = "std_msgs/msg/UInt64MultiArray" - -@dataclass -class std_msgs__msg__UInt8: - """Class for std_msgs/msg/UInt8.""" - - data: int - __msgtype__: ClassVar[str] = "std_msgs/msg/UInt8" - -@dataclass -class std_msgs__msg__UInt8MultiArray: - """Class for std_msgs/msg/UInt8MultiArray.""" - - layout: std_msgs__msg__MultiArrayLayout - data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - __msgtype__: ClassVar[str] = "std_msgs/msg/UInt8MultiArray" - -@dataclass -class tf2_msgs__msg__TF2Error: - """Class for tf2_msgs/msg/TF2Error.""" - - error: int - error_string: str - NO_ERROR: ClassVar[int] = 0 - LOOKUP_ERROR: ClassVar[int] = 1 - CONNECTIVITY_ERROR: ClassVar[int] = 2 - EXTRAPOLATION_ERROR: ClassVar[int] = 3 - INVALID_ARGUMENT_ERROR: ClassVar[int] = 4 - TIMEOUT_ERROR: ClassVar[int] = 5 - TRANSFORM_ERROR: ClassVar[int] = 6 - __msgtype__: ClassVar[str] = "tf2_msgs/msg/TF2Error" - -@dataclass -class tf2_msgs__msg__TFMessage: - """Class for tf2_msgs/msg/TFMessage.""" - - transforms: list[geometry_msgs__msg__TransformStamped] - __msgtype__: ClassVar[str] = "tf2_msgs/msg/TFMessage" - -@dataclass -class trajectory_msgs__msg__JointTrajectoryPoint: - """Class for trajectory_msgs/msg/JointTrajectoryPoint.""" - - positions: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - velocities: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - accelerations: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - effort: np.ndarray[tuple[int, ...], np.dtype[np.float64]] - time_from_start: builtin_interfaces__msg__Duration - __msgtype__: ClassVar[str] = "trajectory_msgs/msg/JointTrajectoryPoint" - -@dataclass -class trajectory_msgs__msg__JointTrajectory: - """Class for trajectory_msgs/msg/JointTrajectory.""" - - header: std_msgs__msg__Header - joint_names: list[str] - points: list[trajectory_msgs__msg__JointTrajectoryPoint] - __msgtype__: ClassVar[str] = "trajectory_msgs/msg/JointTrajectory" - -@dataclass -class trajectory_msgs__msg__MultiDOFJointTrajectoryPoint: - """Class for trajectory_msgs/msg/MultiDOFJointTrajectoryPoint.""" - - transforms: list[geometry_msgs__msg__Transform] - velocities: list[geometry_msgs__msg__Twist] - accelerations: list[geometry_msgs__msg__Twist] - time_from_start: builtin_interfaces__msg__Duration - __msgtype__: ClassVar[str] = "trajectory_msgs/msg/MultiDOFJointTrajectoryPoint" - -@dataclass -class trajectory_msgs__msg__MultiDOFJointTrajectory: - """Class for trajectory_msgs/msg/MultiDOFJointTrajectory.""" - - header: std_msgs__msg__Header - joint_names: list[str] - points: list[trajectory_msgs__msg__MultiDOFJointTrajectoryPoint] - __msgtype__: ClassVar[str] = "trajectory_msgs/msg/MultiDOFJointTrajectory" - -@dataclass -class vision_msgs__msg__BoundingBox2DArray: - """Class for vision_msgs/msg/BoundingBox2DArray.""" - - header: std_msgs__msg__Header - boxes: list[vision_msgs__msg__BoundingBox2D] - __msgtype__: ClassVar[str] = "vision_msgs/msg/BoundingBox2DArray" - -@dataclass -class vision_msgs__msg__BoundingBox3DArray: - """Class for vision_msgs/msg/BoundingBox3DArray.""" - - header: std_msgs__msg__Header - boxes: list[vision_msgs__msg__BoundingBox3D] - __msgtype__: ClassVar[str] = "vision_msgs/msg/BoundingBox3DArray" - -@dataclass -class vision_msgs__msg__ObjectHypothesis: - """Class for vision_msgs/msg/ObjectHypothesis.""" - - class_id: str - score: float - __msgtype__: ClassVar[str] = "vision_msgs/msg/ObjectHypothesis" - -@dataclass -class vision_msgs__msg__Classification: - """Class for vision_msgs/msg/Classification.""" - - header: std_msgs__msg__Header - results: list[vision_msgs__msg__ObjectHypothesis] - __msgtype__: ClassVar[str] = "vision_msgs/msg/Classification" - -@dataclass -class vision_msgs__msg__ObjectHypothesisWithPose: - """Class for vision_msgs/msg/ObjectHypothesisWithPose.""" - - hypothesis: vision_msgs__msg__ObjectHypothesis - pose: geometry_msgs__msg__PoseWithCovariance - __msgtype__: ClassVar[str] = "vision_msgs/msg/ObjectHypothesisWithPose" - -@dataclass -class vision_msgs__msg__Detection2D: - """Class for vision_msgs/msg/Detection2D.""" - - header: std_msgs__msg__Header - results: list[vision_msgs__msg__ObjectHypothesisWithPose] - bbox: vision_msgs__msg__BoundingBox2D - id: str - __msgtype__: ClassVar[str] = "vision_msgs/msg/Detection2D" - -@dataclass -class vision_msgs__msg__Detection2DArray: - """Class for vision_msgs/msg/Detection2DArray.""" - - header: std_msgs__msg__Header - detections: list[vision_msgs__msg__Detection2D] - __msgtype__: ClassVar[str] = "vision_msgs/msg/Detection2DArray" - -@dataclass -class vision_msgs__msg__Detection3D: - """Class for vision_msgs/msg/Detection3D.""" - - header: std_msgs__msg__Header - results: list[vision_msgs__msg__ObjectHypothesisWithPose] - bbox: vision_msgs__msg__BoundingBox3D - id: str - __msgtype__: ClassVar[str] = "vision_msgs/msg/Detection3D" - -@dataclass -class vision_msgs__msg__Detection3DArray: - """Class for vision_msgs/msg/Detection3DArray.""" - - header: std_msgs__msg__Header - detections: list[vision_msgs__msg__Detection3D] - __msgtype__: ClassVar[str] = "vision_msgs/msg/Detection3DArray" - -@dataclass -class vision_msgs__msg__VisionClass: - """Class for vision_msgs/msg/VisionClass.""" - - class_id: int - class_name: str - __msgtype__: ClassVar[str] = "vision_msgs/msg/VisionClass" - -@dataclass -class vision_msgs__msg__LabelInfo: - """Class for vision_msgs/msg/LabelInfo.""" - - header: std_msgs__msg__Header - class_map: list[vision_msgs__msg__VisionClass] - threshold: float - __msgtype__: ClassVar[str] = "vision_msgs/msg/LabelInfo" - -@dataclass -class vision_msgs__msg__VisionInfo: - """Class for vision_msgs/msg/VisionInfo.""" - - header: std_msgs__msg__Header - method: str - database_location: str - database_version: int - __msgtype__: ClassVar[str] = "vision_msgs/msg/VisionInfo" - -@dataclass -class visualization_msgs__msg__ImageMarker: - """Class for visualization_msgs/msg/ImageMarker.""" - - header: std_msgs__msg__Header - ns: str - id: int - type: int - action: int - position: geometry_msgs__msg__Point - scale: float - outline_color: std_msgs__msg__ColorRGBA - filled: int - fill_color: std_msgs__msg__ColorRGBA - lifetime: builtin_interfaces__msg__Duration - points: list[geometry_msgs__msg__Point] - outline_colors: list[std_msgs__msg__ColorRGBA] - CIRCLE: ClassVar[int] = 0 - LINE_STRIP: ClassVar[int] = 1 - LINE_LIST: ClassVar[int] = 2 - POLYGON: ClassVar[int] = 3 - POINTS: ClassVar[int] = 4 - ADD: ClassVar[int] = 0 - REMOVE: ClassVar[int] = 1 - __msgtype__: ClassVar[str] = "visualization_msgs/msg/ImageMarker" - -@dataclass -class visualization_msgs__msg__MeshFile: - """Class for visualization_msgs/msg/MeshFile.""" - - filename: str - data: np.ndarray[tuple[int, ...], np.dtype[np.uint8]] - __msgtype__: ClassVar[str] = "visualization_msgs/msg/MeshFile" - -@dataclass -class visualization_msgs__msg__UVCoordinate: - """Class for visualization_msgs/msg/UVCoordinate.""" - - u: float - v: float - __msgtype__: ClassVar[str] = "visualization_msgs/msg/UVCoordinate" - -@dataclass -class visualization_msgs__msg__Marker: - """Class for visualization_msgs/msg/Marker.""" - - header: std_msgs__msg__Header - ns: str - id: int - type: int - action: int - pose: geometry_msgs__msg__Pose - scale: geometry_msgs__msg__Vector3 - color: std_msgs__msg__ColorRGBA - lifetime: builtin_interfaces__msg__Duration - frame_locked: bool - points: list[geometry_msgs__msg__Point] - colors: list[std_msgs__msg__ColorRGBA] - texture_resource: str - texture: sensor_msgs__msg__CompressedImage - uv_coordinates: list[visualization_msgs__msg__UVCoordinate] - text: str - mesh_resource: str - mesh_file: visualization_msgs__msg__MeshFile - mesh_use_embedded_materials: bool - ARROW: ClassVar[int] = 0 - CUBE: ClassVar[int] = 1 - SPHERE: ClassVar[int] = 2 - CYLINDER: ClassVar[int] = 3 - LINE_STRIP: ClassVar[int] = 4 - LINE_LIST: ClassVar[int] = 5 - CUBE_LIST: ClassVar[int] = 6 - SPHERE_LIST: ClassVar[int] = 7 - POINTS: ClassVar[int] = 8 - TEXT_VIEW_FACING: ClassVar[int] = 9 - MESH_RESOURCE: ClassVar[int] = 10 - TRIANGLE_LIST: ClassVar[int] = 11 - ARROW_STRIP: ClassVar[int] = 12 - ADD: ClassVar[int] = 0 - MODIFY: ClassVar[int] = 0 - DELETE: ClassVar[int] = 2 - DELETEALL: ClassVar[int] = 3 - __msgtype__: ClassVar[str] = "visualization_msgs/msg/Marker" - -@dataclass -class visualization_msgs__msg__InteractiveMarkerControl: - """Class for visualization_msgs/msg/InteractiveMarkerControl.""" - - name: str - orientation: geometry_msgs__msg__Quaternion - orientation_mode: int - interaction_mode: int - always_visible: bool - markers: list[visualization_msgs__msg__Marker] - independent_marker_orientation: bool - description: str - INHERIT: ClassVar[int] = 0 - FIXED: ClassVar[int] = 1 - VIEW_FACING: ClassVar[int] = 2 - NONE: ClassVar[int] = 0 - MENU: ClassVar[int] = 1 - BUTTON: ClassVar[int] = 2 - MOVE_AXIS: ClassVar[int] = 3 - MOVE_PLANE: ClassVar[int] = 4 - ROTATE_AXIS: ClassVar[int] = 5 - MOVE_ROTATE: ClassVar[int] = 6 - MOVE_3D: ClassVar[int] = 7 - ROTATE_3D: ClassVar[int] = 8 - MOVE_ROTATE_3D: ClassVar[int] = 9 - __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarkerControl" - -@dataclass -class visualization_msgs__msg__MenuEntry: - """Class for visualization_msgs/msg/MenuEntry.""" - - id: int - parent_id: int - title: str - command: str - command_type: int - FEEDBACK: ClassVar[int] = 0 - ROSRUN: ClassVar[int] = 1 - ROSLAUNCH: ClassVar[int] = 2 - __msgtype__: ClassVar[str] = "visualization_msgs/msg/MenuEntry" - -@dataclass -class visualization_msgs__msg__InteractiveMarker: - """Class for visualization_msgs/msg/InteractiveMarker.""" - - header: std_msgs__msg__Header - pose: geometry_msgs__msg__Pose - name: str - description: str - scale: float - menu_entries: list[visualization_msgs__msg__MenuEntry] - controls: list[visualization_msgs__msg__InteractiveMarkerControl] - __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarker" - -@dataclass -class visualization_msgs__msg__InteractiveMarkerFeedback: - """Class for visualization_msgs/msg/InteractiveMarkerFeedback.""" - - header: std_msgs__msg__Header - client_id: str - marker_name: str - control_name: str - event_type: int - pose: geometry_msgs__msg__Pose - menu_entry_id: int - mouse_point: geometry_msgs__msg__Point - mouse_point_valid: bool - KEEP_ALIVE: ClassVar[int] = 0 - POSE_UPDATE: ClassVar[int] = 1 - MENU_SELECT: ClassVar[int] = 2 - BUTTON_CLICK: ClassVar[int] = 3 - MOUSE_DOWN: ClassVar[int] = 4 - MOUSE_UP: ClassVar[int] = 5 - __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarkerFeedback" - -@dataclass -class visualization_msgs__msg__InteractiveMarkerInit: - """Class for visualization_msgs/msg/InteractiveMarkerInit.""" - - server_id: str - seq_num: int - markers: list[visualization_msgs__msg__InteractiveMarker] - __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarkerInit" - -@dataclass -class visualization_msgs__msg__InteractiveMarkerPose: - """Class for visualization_msgs/msg/InteractiveMarkerPose.""" - - header: std_msgs__msg__Header - pose: geometry_msgs__msg__Pose - name: str - __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarkerPose" - -@dataclass -class visualization_msgs__msg__InteractiveMarkerUpdate: - """Class for visualization_msgs/msg/InteractiveMarkerUpdate.""" - - server_id: str - seq_num: int - type: int - markers: list[visualization_msgs__msg__InteractiveMarker] - poses: list[visualization_msgs__msg__InteractiveMarkerPose] - erases: list[str] - KEEP_ALIVE: ClassVar[int] = 0 - UPDATE: ClassVar[int] = 1 - __msgtype__: ClassVar[str] = "visualization_msgs/msg/InteractiveMarkerUpdate" - -@dataclass -class visualization_msgs__msg__MarkerArray: - """Class for visualization_msgs/msg/MarkerArray.""" - - markers: list[visualization_msgs__msg__Marker] - __msgtype__: ClassVar[str] = "visualization_msgs/msg/MarkerArray" - -FIELDDEFS: Typesdict = { - "builtin_interfaces/msg/Duration": ( - [], - [ - ("sec", (T.BASE, ("int32", 0))), - ("nanosec", (T.BASE, ("uint32", 0))), - ], - ), - "builtin_interfaces/msg/Time": ( - [], - [ - ("sec", (T.BASE, ("int32", 0))), - ("nanosec", (T.BASE, ("uint32", 0))), - ], - ), - "std_msgs/msg/Header": ( - [], - [ - ("stamp", (T.NAME, "builtin_interfaces/msg/Time")), - ("frame_id", (T.BASE, ("string", 0))), - ], - ), - "vision_msgs/msg/Point2D": ( - [], - [ - ("x", (T.BASE, ("float64", 0))), - ("y", (T.BASE, ("float64", 0))), - ], - ), - "vision_msgs/msg/Pose2D": ( - [], - [ - ("position", (T.NAME, "vision_msgs/msg/Point2D")), - ("theta", (T.BASE, ("float64", 0))), - ], - ), - "vision_msgs/msg/BoundingBox2D": ( - [], - [ - ("center", (T.NAME, "vision_msgs/msg/Pose2D")), - ("size_x", (T.BASE, ("float64", 0))), - ("size_y", (T.BASE, ("float64", 0))), - ], - ), - "dimos_msgs/msg/BoundingBox2DArray": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("boxes", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/BoundingBox2D"), 0))), - ], - ), - "geometry_msgs/msg/Point": ( - [], - [ - ("x", (T.BASE, ("float64", 0))), - ("y", (T.BASE, ("float64", 0))), - ("z", (T.BASE, ("float64", 0))), - ], - ), - "geometry_msgs/msg/Quaternion": ( - [], - [ - ("x", (T.BASE, ("float64", 0))), - ("y", (T.BASE, ("float64", 0))), - ("z", (T.BASE, ("float64", 0))), - ("w", (T.BASE, ("float64", 0))), - ], - ), - "geometry_msgs/msg/Pose": ( - [], - [ - ("position", (T.NAME, "geometry_msgs/msg/Point")), - ("orientation", (T.NAME, "geometry_msgs/msg/Quaternion")), - ], - ), - "geometry_msgs/msg/Vector3": ( - [], - [ - ("x", (T.BASE, ("float64", 0))), - ("y", (T.BASE, ("float64", 0))), - ("z", (T.BASE, ("float64", 0))), - ], - ), - "vision_msgs/msg/BoundingBox3D": ( - [], - [ - ("center", (T.NAME, "geometry_msgs/msg/Pose")), - ("size", (T.NAME, "geometry_msgs/msg/Vector3")), - ], - ), - "dimos_msgs/msg/BoundingBox3DArray": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("boxes", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/BoundingBox3D"), 0))), - ], - ), - "dimos_msgs/msg/EntityMarker": ( - [], - [ - ("entity_id", (T.BASE, ("string", 0))), - ("label", (T.BASE, ("string", 0))), - ("entity_type", (T.BASE, ("string", 0))), - ("position", (T.NAME, "geometry_msgs/msg/Point")), - ], - ), - "dimos_msgs/msg/EntityMarkers": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("markers", (T.SEQUENCE, ((T.NAME, "dimos_msgs/msg/EntityMarker"), 0))), - ], - ), - "dimos_msgs/msg/GraspCandidate": ( - [], - [ - ("pose", (T.NAME, "geometry_msgs/msg/Pose")), - ("score", (T.BASE, ("float64", 0))), - ], - ), - "dimos_msgs/msg/GraspCandidateArray": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("candidates", (T.SEQUENCE, ((T.NAME, "dimos_msgs/msg/GraspCandidate"), 0))), - ], - ), - "dimos_msgs/msg/ImuInfo": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("gyro_noise_density", (T.BASE, ("float64", 0))), - ("gyro_random_walk", (T.BASE, ("float64", 0))), - ("accel_noise_density", (T.BASE, ("float64", 0))), - ("accel_random_walk", (T.BASE, ("float64", 0))), - ("frequency", (T.BASE, ("float64", 0))), - ], - ), - "dimos_msgs/msg/JointCommand": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("positions", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ], - ), - "dimos_msgs/msg/LineSegment3D": ( - [], - [ - ("start", (T.NAME, "geometry_msgs/msg/Point")), - ("end", (T.NAME, "geometry_msgs/msg/Point")), - ("weight", (T.BASE, ("float64", 0))), - ], - ), - "dimos_msgs/msg/LineSegments3D": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("segments", (T.SEQUENCE, ((T.NAME, "dimos_msgs/msg/LineSegment3D"), 0))), - ], - ), - "dimos_msgs/msg/MotorCommandArray": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("q", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("dq", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("kp", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("kd", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("tau", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ], - ), - "dimos_msgs/msg/RobotState": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("state", (T.BASE, ("int32", 0))), - ("mode", (T.BASE, ("int32", 0))), - ("error_code", (T.BASE, ("int32", 0))), - ("warn_code", (T.BASE, ("int32", 0))), - ("cmdnum", (T.BASE, ("int32", 0))), - ("mt_brake", (T.BASE, ("int32", 0))), - ("mt_able", (T.BASE, ("int32", 0))), - ("tcp_pose", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("tcp_offset", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("joints", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ], - ), - "dimos_msgs/msg/TrajectoryStatus": ( - [ - ("IDLE", "uint8", 0), - ("EXECUTING", "uint8", 1), - ("COMPLETED", "uint8", 2), - ("ABORTED", "uint8", 3), - ("FAULT", "uint8", 4), - ], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("state", (T.BASE, ("uint8", 0))), - ("progress", (T.BASE, ("float64", 0))), - ("time_elapsed", (T.NAME, "builtin_interfaces/msg/Duration")), - ("time_remaining", (T.NAME, "builtin_interfaces/msg/Duration")), - ("error", (T.BASE, ("string", 0))), - ], - ), - "dimos_msgs/msg/VideoStats": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("fps", (T.BASE, ("float64", 0))), - ("kbps", (T.BASE, ("float64", 0))), - ("width", (T.BASE, ("uint32", 0))), - ("height", (T.BASE, ("uint32", 0))), - ("loss_pct", (T.BASE, ("float64", 0))), - ("jitter_buffer_ms", (T.BASE, ("float64", 0))), - ("decode_ms", (T.BASE, ("float64", 0))), - ("frames_dropped", (T.BASE, ("uint64", 0))), - ("freezes", (T.BASE, ("uint64", 0))), - ("e2e_latency_ms", (T.BASE, ("float64", 0))), - ], - ), - "foxglove_msgs/msg/CompressedVideo": ( - [], - [ - ("timestamp", (T.NAME, "builtin_interfaces/msg/Time")), - ("frame_id", (T.BASE, ("string", 0))), - ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), - ("format", (T.BASE, ("string", 0))), - ], - ), - "geometry_msgs/msg/Accel": ( - [], - [ - ("linear", (T.NAME, "geometry_msgs/msg/Vector3")), - ("angular", (T.NAME, "geometry_msgs/msg/Vector3")), - ], - ), - "geometry_msgs/msg/AccelStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("accel", (T.NAME, "geometry_msgs/msg/Accel")), - ], - ), - "geometry_msgs/msg/AccelWithCovariance": ( - [], - [ - ("accel", (T.NAME, "geometry_msgs/msg/Accel")), - ("covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 36))), - ], - ), - "geometry_msgs/msg/AccelWithCovarianceStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("accel", (T.NAME, "geometry_msgs/msg/AccelWithCovariance")), - ], - ), - "geometry_msgs/msg/Inertia": ( - [], - [ - ("m", (T.BASE, ("float64", 0))), - ("com", (T.NAME, "geometry_msgs/msg/Vector3")), - ("ixx", (T.BASE, ("float64", 0))), - ("ixy", (T.BASE, ("float64", 0))), - ("ixz", (T.BASE, ("float64", 0))), - ("iyy", (T.BASE, ("float64", 0))), - ("iyz", (T.BASE, ("float64", 0))), - ("izz", (T.BASE, ("float64", 0))), - ], - ), - "geometry_msgs/msg/InertiaStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("inertia", (T.NAME, "geometry_msgs/msg/Inertia")), - ], - ), - "geometry_msgs/msg/Point32": ( - [], - [ - ("x", (T.BASE, ("float32", 0))), - ("y", (T.BASE, ("float32", 0))), - ("z", (T.BASE, ("float32", 0))), - ], - ), - "geometry_msgs/msg/PointStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("point", (T.NAME, "geometry_msgs/msg/Point")), - ], - ), - "geometry_msgs/msg/Polygon": ( - [], - [ - ("points", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point32"), 0))), - ], - ), - "geometry_msgs/msg/PolygonInstance": ( - [], - [ - ("polygon", (T.NAME, "geometry_msgs/msg/Polygon")), - ("id", (T.BASE, ("int64", 0))), - ], - ), - "geometry_msgs/msg/PolygonInstanceStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("polygon", (T.NAME, "geometry_msgs/msg/PolygonInstance")), - ], - ), - "geometry_msgs/msg/PolygonStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("polygon", (T.NAME, "geometry_msgs/msg/Polygon")), - ], - ), - "geometry_msgs/msg/Pose2D": ( - [], - [ - ("x", (T.BASE, ("float64", 0))), - ("y", (T.BASE, ("float64", 0))), - ("theta", (T.BASE, ("float64", 0))), - ], - ), - "geometry_msgs/msg/PoseArray": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("poses", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Pose"), 0))), - ], - ), - "geometry_msgs/msg/PoseStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("pose", (T.NAME, "geometry_msgs/msg/Pose")), - ], - ), - "geometry_msgs/msg/PoseWithCovariance": ( - [], - [ - ("pose", (T.NAME, "geometry_msgs/msg/Pose")), - ("covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 36))), - ], - ), - "geometry_msgs/msg/PoseWithCovarianceStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("pose", (T.NAME, "geometry_msgs/msg/PoseWithCovariance")), - ], - ), - "geometry_msgs/msg/QuaternionStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("quaternion", (T.NAME, "geometry_msgs/msg/Quaternion")), - ], - ), - "geometry_msgs/msg/Transform": ( - [], - [ - ("translation", (T.NAME, "geometry_msgs/msg/Vector3")), - ("rotation", (T.NAME, "geometry_msgs/msg/Quaternion")), - ], - ), - "geometry_msgs/msg/TransformStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("child_frame_id", (T.BASE, ("string", 0))), - ("transform", (T.NAME, "geometry_msgs/msg/Transform")), - ], - ), - "geometry_msgs/msg/Twist": ( - [], - [ - ("linear", (T.NAME, "geometry_msgs/msg/Vector3")), - ("angular", (T.NAME, "geometry_msgs/msg/Vector3")), - ], - ), - "geometry_msgs/msg/TwistStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("twist", (T.NAME, "geometry_msgs/msg/Twist")), - ], - ), - "geometry_msgs/msg/TwistWithCovariance": ( - [], - [ - ("twist", (T.NAME, "geometry_msgs/msg/Twist")), - ("covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 36))), - ], - ), - "geometry_msgs/msg/TwistWithCovarianceStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("twist", (T.NAME, "geometry_msgs/msg/TwistWithCovariance")), - ], - ), - "geometry_msgs/msg/Vector3Stamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("vector", (T.NAME, "geometry_msgs/msg/Vector3")), - ], - ), - "geometry_msgs/msg/VelocityStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("body_frame_id", (T.BASE, ("string", 0))), - ("reference_frame_id", (T.BASE, ("string", 0))), - ("velocity", (T.NAME, "geometry_msgs/msg/Twist")), - ], - ), - "geometry_msgs/msg/VelocityWithCovarianceStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("body_frame_id", (T.BASE, ("string", 0))), - ("reference_frame_id", (T.BASE, ("string", 0))), - ("velocity", (T.NAME, "geometry_msgs/msg/TwistWithCovariance")), - ], - ), - "geometry_msgs/msg/Wrench": ( - [], - [ - ("force", (T.NAME, "geometry_msgs/msg/Vector3")), - ("torque", (T.NAME, "geometry_msgs/msg/Vector3")), - ], - ), - "geometry_msgs/msg/WrenchStamped": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("wrench", (T.NAME, "geometry_msgs/msg/Wrench")), - ], - ), - "nav_msgs/msg/Goals": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("goals", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/PoseStamped"), 0))), - ], - ), - "nav_msgs/msg/GridCells": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("cell_width", (T.BASE, ("float32", 0))), - ("cell_height", (T.BASE, ("float32", 0))), - ("cells", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point"), 0))), - ], - ), - "nav_msgs/msg/MapMetaData": ( - [], - [ - ("map_load_time", (T.NAME, "builtin_interfaces/msg/Time")), - ("resolution", (T.BASE, ("float32", 0))), - ("width", (T.BASE, ("uint32", 0))), - ("height", (T.BASE, ("uint32", 0))), - ("origin", (T.NAME, "geometry_msgs/msg/Pose")), - ], - ), - "nav_msgs/msg/OccupancyGrid": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("info", (T.NAME, "nav_msgs/msg/MapMetaData")), - ("data", (T.SEQUENCE, ((T.BASE, ("int8", 0)), 0))), - ], - ), - "nav_msgs/msg/Odometry": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("child_frame_id", (T.BASE, ("string", 0))), - ("pose", (T.NAME, "geometry_msgs/msg/PoseWithCovariance")), - ("twist", (T.NAME, "geometry_msgs/msg/TwistWithCovariance")), - ], - ), - "nav_msgs/msg/Path": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("poses", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/PoseStamped"), 0))), - ], - ), - "nav_msgs/msg/TrajectoryPoint": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("pose", (T.NAME, "geometry_msgs/msg/Pose")), - ("velocity", (T.NAME, "geometry_msgs/msg/Twist")), - ("acceleration", (T.NAME, "geometry_msgs/msg/Accel")), - ("effort", (T.NAME, "geometry_msgs/msg/Wrench")), - ], - ), - "nav_msgs/msg/Trajectory": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("points", (T.SEQUENCE, ((T.NAME, "nav_msgs/msg/TrajectoryPoint"), 0))), - ], - ), - "sensor_msgs/msg/BatteryState": ( - [ - ("POWER_SUPPLY_STATUS_UNKNOWN", "uint8", 0), - ("POWER_SUPPLY_STATUS_CHARGING", "uint8", 1), - ("POWER_SUPPLY_STATUS_DISCHARGING", "uint8", 2), - ("POWER_SUPPLY_STATUS_NOT_CHARGING", "uint8", 3), - ("POWER_SUPPLY_STATUS_FULL", "uint8", 4), - ("POWER_SUPPLY_HEALTH_UNKNOWN", "uint8", 0), - ("POWER_SUPPLY_HEALTH_GOOD", "uint8", 1), - ("POWER_SUPPLY_HEALTH_OVERHEAT", "uint8", 2), - ("POWER_SUPPLY_HEALTH_DEAD", "uint8", 3), - ("POWER_SUPPLY_HEALTH_OVERVOLTAGE", "uint8", 4), - ("POWER_SUPPLY_HEALTH_UNSPEC_FAILURE", "uint8", 5), - ("POWER_SUPPLY_HEALTH_COLD", "uint8", 6), - ("POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE", "uint8", 7), - ("POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE", "uint8", 8), - ("POWER_SUPPLY_TECHNOLOGY_UNKNOWN", "uint8", 0), - ("POWER_SUPPLY_TECHNOLOGY_NIMH", "uint8", 1), - ("POWER_SUPPLY_TECHNOLOGY_LION", "uint8", 2), - ("POWER_SUPPLY_TECHNOLOGY_LIPO", "uint8", 3), - ("POWER_SUPPLY_TECHNOLOGY_LIFE", "uint8", 4), - ("POWER_SUPPLY_TECHNOLOGY_NICD", "uint8", 5), - ("POWER_SUPPLY_TECHNOLOGY_LIMN", "uint8", 6), - ("POWER_SUPPLY_TECHNOLOGY_TERNARY", "uint8", 7), - ("POWER_SUPPLY_TECHNOLOGY_VRLA", "uint8", 8), - ], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("voltage", (T.BASE, ("float32", 0))), - ("temperature", (T.BASE, ("float32", 0))), - ("current", (T.BASE, ("float32", 0))), - ("charge", (T.BASE, ("float32", 0))), - ("capacity", (T.BASE, ("float32", 0))), - ("design_capacity", (T.BASE, ("float32", 0))), - ("percentage", (T.BASE, ("float32", 0))), - ("power_supply_status", (T.BASE, ("uint8", 0))), - ("power_supply_health", (T.BASE, ("uint8", 0))), - ("power_supply_technology", (T.BASE, ("uint8", 0))), - ("present", (T.BASE, ("bool", 0))), - ("cell_voltage", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), - ("cell_temperature", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), - ("location", (T.BASE, ("string", 0))), - ("serial_number", (T.BASE, ("string", 0))), - ], - ), - "sensor_msgs/msg/RegionOfInterest": ( - [], - [ - ("x_offset", (T.BASE, ("uint32", 0))), - ("y_offset", (T.BASE, ("uint32", 0))), - ("height", (T.BASE, ("uint32", 0))), - ("width", (T.BASE, ("uint32", 0))), - ("do_rectify", (T.BASE, ("bool", 0))), - ], - ), - "sensor_msgs/msg/CameraInfo": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("height", (T.BASE, ("uint32", 0))), - ("width", (T.BASE, ("uint32", 0))), - ("distortion_model", (T.BASE, ("string", 0))), - ("d", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("k", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), - ("r", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), - ("p", (T.ARRAY, ((T.BASE, ("float64", 0)), 12))), - ("binning_x", (T.BASE, ("uint32", 0))), - ("binning_y", (T.BASE, ("uint32", 0))), - ("roi", (T.NAME, "sensor_msgs/msg/RegionOfInterest")), - ], - ), - "sensor_msgs/msg/ChannelFloat32": ( - [], - [ - ("name", (T.BASE, ("string", 0))), - ("values", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), - ], - ), - "sensor_msgs/msg/CompressedImage": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("format", (T.BASE, ("string", 0))), - ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), - ], - ), - "sensor_msgs/msg/FluidPressure": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("fluid_pressure", (T.BASE, ("float64", 0))), - ("variance", (T.BASE, ("float64", 0))), - ], - ), - "sensor_msgs/msg/Illuminance": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("illuminance", (T.BASE, ("float64", 0))), - ("variance", (T.BASE, ("float64", 0))), - ], - ), - "sensor_msgs/msg/Image": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("height", (T.BASE, ("uint32", 0))), - ("width", (T.BASE, ("uint32", 0))), - ("encoding", (T.BASE, ("string", 0))), - ("is_bigendian", (T.BASE, ("uint8", 0))), - ("step", (T.BASE, ("uint32", 0))), - ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), - ], - ), - "sensor_msgs/msg/Imu": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("orientation", (T.NAME, "geometry_msgs/msg/Quaternion")), - ("orientation_covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), - ("angular_velocity", (T.NAME, "geometry_msgs/msg/Vector3")), - ("angular_velocity_covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), - ("linear_acceleration", (T.NAME, "geometry_msgs/msg/Vector3")), - ("linear_acceleration_covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), - ], - ), - "sensor_msgs/msg/JointState": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("name", (T.SEQUENCE, ((T.BASE, ("string", 0)), 0))), - ("position", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("velocity", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("effort", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ], - ), - "sensor_msgs/msg/Joy": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("axes", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), - ("buttons", (T.SEQUENCE, ((T.BASE, ("int32", 0)), 0))), - ], - ), - "sensor_msgs/msg/JoyFeedback": ( - [ - ("TYPE_LED", "uint8", 0), - ("TYPE_RUMBLE", "uint8", 1), - ("TYPE_BUZZER", "uint8", 2), - ], - [ - ("type", (T.BASE, ("uint8", 0))), - ("id", (T.BASE, ("uint8", 0))), - ("intensity", (T.BASE, ("float32", 0))), - ], - ), - "sensor_msgs/msg/JoyFeedbackArray": ( - [], - [ - ("array", (T.SEQUENCE, ((T.NAME, "sensor_msgs/msg/JoyFeedback"), 0))), - ], - ), - "sensor_msgs/msg/LaserEcho": ( - [], - [ - ("echoes", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), - ], - ), - "sensor_msgs/msg/LaserScan": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("angle_min", (T.BASE, ("float32", 0))), - ("angle_max", (T.BASE, ("float32", 0))), - ("angle_increment", (T.BASE, ("float32", 0))), - ("time_increment", (T.BASE, ("float32", 0))), - ("scan_time", (T.BASE, ("float32", 0))), - ("range_min", (T.BASE, ("float32", 0))), - ("range_max", (T.BASE, ("float32", 0))), - ("ranges", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), - ("intensities", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), - ], - ), - "sensor_msgs/msg/MagneticField": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("magnetic_field", (T.NAME, "geometry_msgs/msg/Vector3")), - ("magnetic_field_covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), - ], - ), - "sensor_msgs/msg/MultiDOFJointState": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("joint_names", (T.SEQUENCE, ((T.BASE, ("string", 0)), 0))), - ("transforms", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Transform"), 0))), - ("twist", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Twist"), 0))), - ("wrench", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Wrench"), 0))), - ], - ), - "sensor_msgs/msg/MultiEchoLaserScan": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("angle_min", (T.BASE, ("float32", 0))), - ("angle_max", (T.BASE, ("float32", 0))), - ("angle_increment", (T.BASE, ("float32", 0))), - ("time_increment", (T.BASE, ("float32", 0))), - ("scan_time", (T.BASE, ("float32", 0))), - ("range_min", (T.BASE, ("float32", 0))), - ("range_max", (T.BASE, ("float32", 0))), - ("ranges", (T.SEQUENCE, ((T.NAME, "sensor_msgs/msg/LaserEcho"), 0))), - ("intensities", (T.SEQUENCE, ((T.NAME, "sensor_msgs/msg/LaserEcho"), 0))), - ], - ), - "sensor_msgs/msg/NavSatStatus": ( - [ - ("STATUS_UNKNOWN", "int8", -2), - ("STATUS_NO_FIX", "int8", -1), - ("STATUS_FIX", "int8", 0), - ("STATUS_SBAS_FIX", "int8", 1), - ("STATUS_GBAS_FIX", "int8", 2), - ("SERVICE_UNKNOWN", "uint16", 0), - ("SERVICE_GPS", "uint16", 1), - ("SERVICE_GLONASS", "uint16", 2), - ("SERVICE_COMPASS", "uint16", 4), - ("SERVICE_GALILEO", "uint16", 8), - ], - [ - ("status", (T.BASE, ("int8", 0))), - ("service", (T.BASE, ("uint16", 0))), - ], - ), - "sensor_msgs/msg/NavSatFix": ( - [ - ("COVARIANCE_TYPE_UNKNOWN", "uint8", 0), - ("COVARIANCE_TYPE_APPROXIMATED", "uint8", 1), - ("COVARIANCE_TYPE_DIAGONAL_KNOWN", "uint8", 2), - ("COVARIANCE_TYPE_KNOWN", "uint8", 3), - ], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("status", (T.NAME, "sensor_msgs/msg/NavSatStatus")), - ("latitude", (T.BASE, ("float64", 0))), - ("longitude", (T.BASE, ("float64", 0))), - ("altitude", (T.BASE, ("float64", 0))), - ("position_covariance", (T.ARRAY, ((T.BASE, ("float64", 0)), 9))), - ("position_covariance_type", (T.BASE, ("uint8", 0))), - ], - ), - "sensor_msgs/msg/PointCloud": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("points", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point32"), 0))), - ("channels", (T.SEQUENCE, ((T.NAME, "sensor_msgs/msg/ChannelFloat32"), 0))), - ], - ), - "sensor_msgs/msg/PointField": ( - [ - ("INT8", "uint8", 1), - ("UINT8", "uint8", 2), - ("INT16", "uint8", 3), - ("UINT16", "uint8", 4), - ("INT32", "uint8", 5), - ("UINT32", "uint8", 6), - ("FLOAT32", "uint8", 7), - ("FLOAT64", "uint8", 8), - ], - [ - ("name", (T.BASE, ("string", 0))), - ("offset", (T.BASE, ("uint32", 0))), - ("datatype", (T.BASE, ("uint8", 0))), - ("count", (T.BASE, ("uint32", 0))), - ], - ), - "sensor_msgs/msg/PointCloud2": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("height", (T.BASE, ("uint32", 0))), - ("width", (T.BASE, ("uint32", 0))), - ("fields", (T.SEQUENCE, ((T.NAME, "sensor_msgs/msg/PointField"), 0))), - ("is_bigendian", (T.BASE, ("bool", 0))), - ("point_step", (T.BASE, ("uint32", 0))), - ("row_step", (T.BASE, ("uint32", 0))), - ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), - ("is_dense", (T.BASE, ("bool", 0))), - ], - ), - "sensor_msgs/msg/Range": ( - [ - ("ULTRASOUND", "uint8", 0), - ("INFRARED", "uint8", 1), - ], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("radiation_type", (T.BASE, ("uint8", 0))), - ("field_of_view", (T.BASE, ("float32", 0))), - ("min_range", (T.BASE, ("float32", 0))), - ("max_range", (T.BASE, ("float32", 0))), - ("range", (T.BASE, ("float32", 0))), - ("variance", (T.BASE, ("float32", 0))), - ], - ), - "sensor_msgs/msg/RelativeHumidity": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("relative_humidity", (T.BASE, ("float64", 0))), - ("variance", (T.BASE, ("float64", 0))), - ], - ), - "sensor_msgs/msg/Temperature": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("temperature", (T.BASE, ("float64", 0))), - ("variance", (T.BASE, ("float64", 0))), - ], - ), - "sensor_msgs/msg/TimeReference": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("time_ref", (T.NAME, "builtin_interfaces/msg/Time")), - ("source", (T.BASE, ("string", 0))), - ], - ), - "shape_msgs/msg/MeshTriangle": ( - [], - [ - ("vertex_indices", (T.ARRAY, ((T.BASE, ("uint32", 0)), 3))), - ], - ), - "shape_msgs/msg/Mesh": ( - [], - [ - ("triangles", (T.SEQUENCE, ((T.NAME, "shape_msgs/msg/MeshTriangle"), 0))), - ("vertices", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point"), 0))), - ], - ), - "shape_msgs/msg/Plane": ( - [], - [ - ("coef", (T.ARRAY, ((T.BASE, ("float64", 0)), 4))), - ], - ), - "shape_msgs/msg/SolidPrimitive": ( - [ - ("BOX", "uint8", 1), - ("SPHERE", "uint8", 2), - ("CYLINDER", "uint8", 3), - ("CONE", "uint8", 4), - ("PRISM", "uint8", 5), - ("BOX_X", "uint8", 0), - ("BOX_Y", "uint8", 1), - ("BOX_Z", "uint8", 2), - ("SPHERE_RADIUS", "uint8", 0), - ("CYLINDER_HEIGHT", "uint8", 0), - ("CYLINDER_RADIUS", "uint8", 1), - ("CONE_HEIGHT", "uint8", 0), - ("CONE_RADIUS", "uint8", 1), - ("PRISM_HEIGHT", "uint8", 0), - ], - [ - ("type", (T.BASE, ("uint8", 0))), - ("dimensions", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 3))), - ("polygon", (T.NAME, "geometry_msgs/msg/Polygon")), - ], - ), - "std_msgs/msg/Bool": ( - [], - [ - ("data", (T.BASE, ("bool", 0))), - ], - ), - "std_msgs/msg/Byte": ( - [], - [ - ("data", (T.BASE, ("byte", 0))), - ], - ), - "std_msgs/msg/MultiArrayDimension": ( - [], - [ - ("label", (T.BASE, ("string", 0))), - ("size", (T.BASE, ("uint32", 0))), - ("stride", (T.BASE, ("uint32", 0))), - ], - ), - "std_msgs/msg/MultiArrayLayout": ( - [], - [ - ("dim", (T.SEQUENCE, ((T.NAME, "std_msgs/msg/MultiArrayDimension"), 0))), - ("data_offset", (T.BASE, ("uint32", 0))), - ], - ), - "std_msgs/msg/ByteMultiArray": ( - [], - [ - ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), - ("data", (T.SEQUENCE, ((T.BASE, ("byte", 0)), 0))), - ], - ), - "std_msgs/msg/Char": ( - [], - [ - ("data", (T.BASE, ("char", 0))), - ], - ), - "std_msgs/msg/ColorRGBA": ( - [], - [ - ("r", (T.BASE, ("float32", 0))), - ("g", (T.BASE, ("float32", 0))), - ("b", (T.BASE, ("float32", 0))), - ("a", (T.BASE, ("float32", 0))), - ], - ), - "std_msgs/msg/Empty": ( - [], - [ - ("structure_needs_at_least_one_member", (T.BASE, ("uint8", 0))), - ], - ), - "std_msgs/msg/Float32": ( - [], - [ - ("data", (T.BASE, ("float32", 0))), - ], - ), - "std_msgs/msg/Float32MultiArray": ( - [], - [ - ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), - ("data", (T.SEQUENCE, ((T.BASE, ("float32", 0)), 0))), - ], - ), - "std_msgs/msg/Float64": ( - [], - [ - ("data", (T.BASE, ("float64", 0))), - ], - ), - "std_msgs/msg/Float64MultiArray": ( - [], - [ - ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), - ("data", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ], - ), - "std_msgs/msg/Int16": ( - [], - [ - ("data", (T.BASE, ("int16", 0))), - ], - ), - "std_msgs/msg/Int16MultiArray": ( - [], - [ - ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), - ("data", (T.SEQUENCE, ((T.BASE, ("int16", 0)), 0))), - ], - ), - "std_msgs/msg/Int32": ( - [], - [ - ("data", (T.BASE, ("int32", 0))), - ], - ), - "std_msgs/msg/Int32MultiArray": ( - [], - [ - ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), - ("data", (T.SEQUENCE, ((T.BASE, ("int32", 0)), 0))), - ], - ), - "std_msgs/msg/Int64": ( - [], - [ - ("data", (T.BASE, ("int64", 0))), - ], - ), - "std_msgs/msg/Int64MultiArray": ( - [], - [ - ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), - ("data", (T.SEQUENCE, ((T.BASE, ("int64", 0)), 0))), - ], - ), - "std_msgs/msg/Int8": ( - [], - [ - ("data", (T.BASE, ("int8", 0))), - ], - ), - "std_msgs/msg/Int8MultiArray": ( - [], - [ - ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), - ("data", (T.SEQUENCE, ((T.BASE, ("int8", 0)), 0))), - ], - ), - "std_msgs/msg/String": ( - [], - [ - ("data", (T.BASE, ("string", 0))), - ], - ), - "std_msgs/msg/UInt16": ( - [], - [ - ("data", (T.BASE, ("uint16", 0))), - ], - ), - "std_msgs/msg/UInt16MultiArray": ( - [], - [ - ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), - ("data", (T.SEQUENCE, ((T.BASE, ("uint16", 0)), 0))), - ], - ), - "std_msgs/msg/UInt32": ( - [], - [ - ("data", (T.BASE, ("uint32", 0))), - ], - ), - "std_msgs/msg/UInt32MultiArray": ( - [], - [ - ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), - ("data", (T.SEQUENCE, ((T.BASE, ("uint32", 0)), 0))), - ], - ), - "std_msgs/msg/UInt64": ( - [], - [ - ("data", (T.BASE, ("uint64", 0))), - ], - ), - "std_msgs/msg/UInt64MultiArray": ( - [], - [ - ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), - ("data", (T.SEQUENCE, ((T.BASE, ("uint64", 0)), 0))), - ], - ), - "std_msgs/msg/UInt8": ( - [], - [ - ("data", (T.BASE, ("uint8", 0))), - ], - ), - "std_msgs/msg/UInt8MultiArray": ( - [], - [ - ("layout", (T.NAME, "std_msgs/msg/MultiArrayLayout")), - ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), - ], - ), - "tf2_msgs/msg/TF2Error": ( - [ - ("NO_ERROR", "uint8", 0), - ("LOOKUP_ERROR", "uint8", 1), - ("CONNECTIVITY_ERROR", "uint8", 2), - ("EXTRAPOLATION_ERROR", "uint8", 3), - ("INVALID_ARGUMENT_ERROR", "uint8", 4), - ("TIMEOUT_ERROR", "uint8", 5), - ("TRANSFORM_ERROR", "uint8", 6), - ], - [ - ("error", (T.BASE, ("uint8", 0))), - ("error_string", (T.BASE, ("string", 0))), - ], - ), - "tf2_msgs/msg/TFMessage": ( - [], - [ - ("transforms", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/TransformStamped"), 0))), - ], - ), - "trajectory_msgs/msg/JointTrajectoryPoint": ( - [], - [ - ("positions", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("velocities", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("accelerations", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("effort", (T.SEQUENCE, ((T.BASE, ("float64", 0)), 0))), - ("time_from_start", (T.NAME, "builtin_interfaces/msg/Duration")), - ], - ), - "trajectory_msgs/msg/JointTrajectory": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("joint_names", (T.SEQUENCE, ((T.BASE, ("string", 0)), 0))), - ("points", (T.SEQUENCE, ((T.NAME, "trajectory_msgs/msg/JointTrajectoryPoint"), 0))), - ], - ), - "trajectory_msgs/msg/MultiDOFJointTrajectoryPoint": ( - [], - [ - ("transforms", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Transform"), 0))), - ("velocities", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Twist"), 0))), - ("accelerations", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Twist"), 0))), - ("time_from_start", (T.NAME, "builtin_interfaces/msg/Duration")), - ], - ), - "trajectory_msgs/msg/MultiDOFJointTrajectory": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("joint_names", (T.SEQUENCE, ((T.BASE, ("string", 0)), 0))), - ( - "points", - (T.SEQUENCE, ((T.NAME, "trajectory_msgs/msg/MultiDOFJointTrajectoryPoint"), 0)), - ), - ], - ), - "vision_msgs/msg/BoundingBox2DArray": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("boxes", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/BoundingBox2D"), 0))), - ], - ), - "vision_msgs/msg/BoundingBox3DArray": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("boxes", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/BoundingBox3D"), 0))), - ], - ), - "vision_msgs/msg/ObjectHypothesis": ( - [], - [ - ("class_id", (T.BASE, ("string", 0))), - ("score", (T.BASE, ("float64", 0))), - ], - ), - "vision_msgs/msg/Classification": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("results", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/ObjectHypothesis"), 0))), - ], - ), - "vision_msgs/msg/ObjectHypothesisWithPose": ( - [], - [ - ("hypothesis", (T.NAME, "vision_msgs/msg/ObjectHypothesis")), - ("pose", (T.NAME, "geometry_msgs/msg/PoseWithCovariance")), - ], - ), - "vision_msgs/msg/Detection2D": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("results", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/ObjectHypothesisWithPose"), 0))), - ("bbox", (T.NAME, "vision_msgs/msg/BoundingBox2D")), - ("id", (T.BASE, ("string", 0))), - ], - ), - "vision_msgs/msg/Detection2DArray": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("detections", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/Detection2D"), 0))), - ], - ), - "vision_msgs/msg/Detection3D": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("results", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/ObjectHypothesisWithPose"), 0))), - ("bbox", (T.NAME, "vision_msgs/msg/BoundingBox3D")), - ("id", (T.BASE, ("string", 0))), - ], - ), - "vision_msgs/msg/Detection3DArray": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("detections", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/Detection3D"), 0))), - ], - ), - "vision_msgs/msg/VisionClass": ( - [], - [ - ("class_id", (T.BASE, ("uint16", 0))), - ("class_name", (T.BASE, ("string", 0))), - ], - ), - "vision_msgs/msg/LabelInfo": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("class_map", (T.SEQUENCE, ((T.NAME, "vision_msgs/msg/VisionClass"), 0))), - ("threshold", (T.BASE, ("float32", 0))), - ], - ), - "vision_msgs/msg/VisionInfo": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("method", (T.BASE, ("string", 0))), - ("database_location", (T.BASE, ("string", 0))), - ("database_version", (T.BASE, ("int32", 0))), - ], - ), - "visualization_msgs/msg/ImageMarker": ( - [ - ("CIRCLE", "int32", 0), - ("LINE_STRIP", "int32", 1), - ("LINE_LIST", "int32", 2), - ("POLYGON", "int32", 3), - ("POINTS", "int32", 4), - ("ADD", "int32", 0), - ("REMOVE", "int32", 1), - ], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("ns", (T.BASE, ("string", 0))), - ("id", (T.BASE, ("int32", 0))), - ("type", (T.BASE, ("int32", 0))), - ("action", (T.BASE, ("int32", 0))), - ("position", (T.NAME, "geometry_msgs/msg/Point")), - ("scale", (T.BASE, ("float32", 0))), - ("outline_color", (T.NAME, "std_msgs/msg/ColorRGBA")), - ("filled", (T.BASE, ("uint8", 0))), - ("fill_color", (T.NAME, "std_msgs/msg/ColorRGBA")), - ("lifetime", (T.NAME, "builtin_interfaces/msg/Duration")), - ("points", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point"), 0))), - ("outline_colors", (T.SEQUENCE, ((T.NAME, "std_msgs/msg/ColorRGBA"), 0))), - ], - ), - "visualization_msgs/msg/MeshFile": ( - [], - [ - ("filename", (T.BASE, ("string", 0))), - ("data", (T.SEQUENCE, ((T.BASE, ("uint8", 0)), 0))), - ], - ), - "visualization_msgs/msg/UVCoordinate": ( - [], - [ - ("u", (T.BASE, ("float32", 0))), - ("v", (T.BASE, ("float32", 0))), - ], - ), - "visualization_msgs/msg/Marker": ( - [ - ("ARROW", "int32", 0), - ("CUBE", "int32", 1), - ("SPHERE", "int32", 2), - ("CYLINDER", "int32", 3), - ("LINE_STRIP", "int32", 4), - ("LINE_LIST", "int32", 5), - ("CUBE_LIST", "int32", 6), - ("SPHERE_LIST", "int32", 7), - ("POINTS", "int32", 8), - ("TEXT_VIEW_FACING", "int32", 9), - ("MESH_RESOURCE", "int32", 10), - ("TRIANGLE_LIST", "int32", 11), - ("ARROW_STRIP", "int32", 12), - ("ADD", "int32", 0), - ("MODIFY", "int32", 0), - ("DELETE", "int32", 2), - ("DELETEALL", "int32", 3), - ], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("ns", (T.BASE, ("string", 0))), - ("id", (T.BASE, ("int32", 0))), - ("type", (T.BASE, ("int32", 0))), - ("action", (T.BASE, ("int32", 0))), - ("pose", (T.NAME, "geometry_msgs/msg/Pose")), - ("scale", (T.NAME, "geometry_msgs/msg/Vector3")), - ("color", (T.NAME, "std_msgs/msg/ColorRGBA")), - ("lifetime", (T.NAME, "builtin_interfaces/msg/Duration")), - ("frame_locked", (T.BASE, ("bool", 0))), - ("points", (T.SEQUENCE, ((T.NAME, "geometry_msgs/msg/Point"), 0))), - ("colors", (T.SEQUENCE, ((T.NAME, "std_msgs/msg/ColorRGBA"), 0))), - ("texture_resource", (T.BASE, ("string", 0))), - ("texture", (T.NAME, "sensor_msgs/msg/CompressedImage")), - ("uv_coordinates", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/UVCoordinate"), 0))), - ("text", (T.BASE, ("string", 0))), - ("mesh_resource", (T.BASE, ("string", 0))), - ("mesh_file", (T.NAME, "visualization_msgs/msg/MeshFile")), - ("mesh_use_embedded_materials", (T.BASE, ("bool", 0))), - ], - ), - "visualization_msgs/msg/InteractiveMarkerControl": ( - [ - ("INHERIT", "uint8", 0), - ("FIXED", "uint8", 1), - ("VIEW_FACING", "uint8", 2), - ("NONE", "uint8", 0), - ("MENU", "uint8", 1), - ("BUTTON", "uint8", 2), - ("MOVE_AXIS", "uint8", 3), - ("MOVE_PLANE", "uint8", 4), - ("ROTATE_AXIS", "uint8", 5), - ("MOVE_ROTATE", "uint8", 6), - ("MOVE_3D", "uint8", 7), - ("ROTATE_3D", "uint8", 8), - ("MOVE_ROTATE_3D", "uint8", 9), - ], - [ - ("name", (T.BASE, ("string", 0))), - ("orientation", (T.NAME, "geometry_msgs/msg/Quaternion")), - ("orientation_mode", (T.BASE, ("uint8", 0))), - ("interaction_mode", (T.BASE, ("uint8", 0))), - ("always_visible", (T.BASE, ("bool", 0))), - ("markers", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/Marker"), 0))), - ("independent_marker_orientation", (T.BASE, ("bool", 0))), - ("description", (T.BASE, ("string", 0))), - ], - ), - "visualization_msgs/msg/MenuEntry": ( - [ - ("FEEDBACK", "uint8", 0), - ("ROSRUN", "uint8", 1), - ("ROSLAUNCH", "uint8", 2), - ], - [ - ("id", (T.BASE, ("uint32", 0))), - ("parent_id", (T.BASE, ("uint32", 0))), - ("title", (T.BASE, ("string", 0))), - ("command", (T.BASE, ("string", 0))), - ("command_type", (T.BASE, ("uint8", 0))), - ], - ), - "visualization_msgs/msg/InteractiveMarker": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("pose", (T.NAME, "geometry_msgs/msg/Pose")), - ("name", (T.BASE, ("string", 0))), - ("description", (T.BASE, ("string", 0))), - ("scale", (T.BASE, ("float32", 0))), - ("menu_entries", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/MenuEntry"), 0))), - ( - "controls", - (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/InteractiveMarkerControl"), 0)), - ), - ], - ), - "visualization_msgs/msg/InteractiveMarkerFeedback": ( - [ - ("KEEP_ALIVE", "uint8", 0), - ("POSE_UPDATE", "uint8", 1), - ("MENU_SELECT", "uint8", 2), - ("BUTTON_CLICK", "uint8", 3), - ("MOUSE_DOWN", "uint8", 4), - ("MOUSE_UP", "uint8", 5), - ], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("client_id", (T.BASE, ("string", 0))), - ("marker_name", (T.BASE, ("string", 0))), - ("control_name", (T.BASE, ("string", 0))), - ("event_type", (T.BASE, ("uint8", 0))), - ("pose", (T.NAME, "geometry_msgs/msg/Pose")), - ("menu_entry_id", (T.BASE, ("uint32", 0))), - ("mouse_point", (T.NAME, "geometry_msgs/msg/Point")), - ("mouse_point_valid", (T.BASE, ("bool", 0))), - ], - ), - "visualization_msgs/msg/InteractiveMarkerInit": ( - [], - [ - ("server_id", (T.BASE, ("string", 0))), - ("seq_num", (T.BASE, ("uint64", 0))), - ("markers", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/InteractiveMarker"), 0))), - ], - ), - "visualization_msgs/msg/InteractiveMarkerPose": ( - [], - [ - ("header", (T.NAME, "std_msgs/msg/Header")), - ("pose", (T.NAME, "geometry_msgs/msg/Pose")), - ("name", (T.BASE, ("string", 0))), - ], - ), - "visualization_msgs/msg/InteractiveMarkerUpdate": ( - [ - ("KEEP_ALIVE", "uint8", 0), - ("UPDATE", "uint8", 1), - ], - [ - ("server_id", (T.BASE, ("string", 0))), - ("seq_num", (T.BASE, ("uint64", 0))), - ("type", (T.BASE, ("uint8", 0))), - ("markers", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/InteractiveMarker"), 0))), - ("poses", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/InteractiveMarkerPose"), 0))), - ("erases", (T.SEQUENCE, ((T.BASE, ("string", 0)), 0))), - ], - ), - "visualization_msgs/msg/MarkerArray": ( - [], - [ - ("markers", (T.SEQUENCE, ((T.NAME, "visualization_msgs/msg/Marker"), 0))), - ], - ), -} diff --git a/packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi deleted file mode 100644 index ec2a13773fc..00000000000 --- a/packages/dimos-generated/src/dimos_generated/builtin_interfaces/msg/__init__.pyi +++ /dev/null @@ -1,5 +0,0 @@ -__all__ = ["Duration", "Time"] -from ..._types import ( - builtin_interfaces__msg__Duration as Duration, - builtin_interfaces__msg__Time as Time, -) diff --git a/packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi deleted file mode 100644 index 056431b7fa6..00000000000 --- a/packages/dimos-generated/src/dimos_generated/dimos_msgs/msg/__init__.pyi +++ /dev/null @@ -1,32 +0,0 @@ -__all__ = [ - "BoundingBox2DArray", - "BoundingBox3DArray", - "EntityMarker", - "EntityMarkers", - "GraspCandidate", - "GraspCandidateArray", - "ImuInfo", - "JointCommand", - "LineSegment3D", - "LineSegments3D", - "MotorCommandArray", - "RobotState", - "TrajectoryStatus", - "VideoStats", -] -from ..._types import ( - dimos_msgs__msg__BoundingBox2DArray as BoundingBox2DArray, - dimos_msgs__msg__BoundingBox3DArray as BoundingBox3DArray, - dimos_msgs__msg__EntityMarker as EntityMarker, - dimos_msgs__msg__EntityMarkers as EntityMarkers, - dimos_msgs__msg__GraspCandidate as GraspCandidate, - dimos_msgs__msg__GraspCandidateArray as GraspCandidateArray, - dimos_msgs__msg__ImuInfo as ImuInfo, - dimos_msgs__msg__JointCommand as JointCommand, - dimos_msgs__msg__LineSegment3D as LineSegment3D, - dimos_msgs__msg__LineSegments3D as LineSegments3D, - dimos_msgs__msg__MotorCommandArray as MotorCommandArray, - dimos_msgs__msg__RobotState as RobotState, - dimos_msgs__msg__TrajectoryStatus as TrajectoryStatus, - dimos_msgs__msg__VideoStats as VideoStats, -) diff --git a/packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi deleted file mode 100644 index 83a79d0260d..00000000000 --- a/packages/dimos-generated/src/dimos_generated/foxglove_msgs/msg/__init__.pyi +++ /dev/null @@ -1,2 +0,0 @@ -__all__ = ["CompressedVideo"] -from ..._types import foxglove_msgs__msg__CompressedVideo as CompressedVideo diff --git a/packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi deleted file mode 100644 index f63131d99af..00000000000 --- a/packages/dimos-generated/src/dimos_generated/geometry_msgs/msg/__init__.pyi +++ /dev/null @@ -1,70 +0,0 @@ -__all__ = [ - "Accel", - "AccelStamped", - "AccelWithCovariance", - "AccelWithCovarianceStamped", - "Inertia", - "InertiaStamped", - "Point", - "Point32", - "PointStamped", - "Polygon", - "PolygonInstance", - "PolygonInstanceStamped", - "PolygonStamped", - "Pose", - "Pose2D", - "PoseArray", - "PoseStamped", - "PoseWithCovariance", - "PoseWithCovarianceStamped", - "Quaternion", - "QuaternionStamped", - "Transform", - "TransformStamped", - "Twist", - "TwistStamped", - "TwistWithCovariance", - "TwistWithCovarianceStamped", - "Vector3", - "Vector3Stamped", - "VelocityStamped", - "VelocityWithCovarianceStamped", - "Wrench", - "WrenchStamped", -] -from ..._types import ( - geometry_msgs__msg__Accel as Accel, - geometry_msgs__msg__AccelStamped as AccelStamped, - geometry_msgs__msg__AccelWithCovariance as AccelWithCovariance, - geometry_msgs__msg__AccelWithCovarianceStamped as AccelWithCovarianceStamped, - geometry_msgs__msg__Inertia as Inertia, - geometry_msgs__msg__InertiaStamped as InertiaStamped, - geometry_msgs__msg__Point as Point, - geometry_msgs__msg__Point32 as Point32, - geometry_msgs__msg__PointStamped as PointStamped, - geometry_msgs__msg__Polygon as Polygon, - geometry_msgs__msg__PolygonInstance as PolygonInstance, - geometry_msgs__msg__PolygonInstanceStamped as PolygonInstanceStamped, - geometry_msgs__msg__PolygonStamped as PolygonStamped, - geometry_msgs__msg__Pose as Pose, - geometry_msgs__msg__Pose2D as Pose2D, - geometry_msgs__msg__PoseArray as PoseArray, - geometry_msgs__msg__PoseStamped as PoseStamped, - geometry_msgs__msg__PoseWithCovariance as PoseWithCovariance, - geometry_msgs__msg__PoseWithCovarianceStamped as PoseWithCovarianceStamped, - geometry_msgs__msg__Quaternion as Quaternion, - geometry_msgs__msg__QuaternionStamped as QuaternionStamped, - geometry_msgs__msg__Transform as Transform, - geometry_msgs__msg__TransformStamped as TransformStamped, - geometry_msgs__msg__Twist as Twist, - geometry_msgs__msg__TwistStamped as TwistStamped, - geometry_msgs__msg__TwistWithCovariance as TwistWithCovariance, - geometry_msgs__msg__TwistWithCovarianceStamped as TwistWithCovarianceStamped, - geometry_msgs__msg__Vector3 as Vector3, - geometry_msgs__msg__Vector3Stamped as Vector3Stamped, - geometry_msgs__msg__VelocityStamped as VelocityStamped, - geometry_msgs__msg__VelocityWithCovarianceStamped as VelocityWithCovarianceStamped, - geometry_msgs__msg__Wrench as Wrench, - geometry_msgs__msg__WrenchStamped as WrenchStamped, -) diff --git a/packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi deleted file mode 100644 index ac4e6d5ffbf..00000000000 --- a/packages/dimos-generated/src/dimos_generated/nav_msgs/msg/__init__.pyi +++ /dev/null @@ -1,20 +0,0 @@ -__all__ = [ - "Goals", - "GridCells", - "MapMetaData", - "OccupancyGrid", - "Odometry", - "Path", - "Trajectory", - "TrajectoryPoint", -] -from ..._types import ( - nav_msgs__msg__Goals as Goals, - nav_msgs__msg__GridCells as GridCells, - nav_msgs__msg__MapMetaData as MapMetaData, - nav_msgs__msg__OccupancyGrid as OccupancyGrid, - nav_msgs__msg__Odometry as Odometry, - nav_msgs__msg__Path as Path, - nav_msgs__msg__Trajectory as Trajectory, - nav_msgs__msg__TrajectoryPoint as TrajectoryPoint, -) diff --git a/packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi deleted file mode 100644 index f60aec0a657..00000000000 --- a/packages/dimos-generated/src/dimos_generated/sensor_msgs/msg/__init__.pyi +++ /dev/null @@ -1,58 +0,0 @@ -__all__ = [ - "BatteryState", - "CameraInfo", - "ChannelFloat32", - "CompressedImage", - "FluidPressure", - "Illuminance", - "Image", - "Imu", - "JointState", - "Joy", - "JoyFeedback", - "JoyFeedbackArray", - "LaserEcho", - "LaserScan", - "MagneticField", - "MultiDOFJointState", - "MultiEchoLaserScan", - "NavSatFix", - "NavSatStatus", - "PointCloud", - "PointCloud2", - "PointField", - "Range", - "RegionOfInterest", - "RelativeHumidity", - "Temperature", - "TimeReference", -] -from ..._types import ( - sensor_msgs__msg__BatteryState as BatteryState, - sensor_msgs__msg__CameraInfo as CameraInfo, - sensor_msgs__msg__ChannelFloat32 as ChannelFloat32, - sensor_msgs__msg__CompressedImage as CompressedImage, - sensor_msgs__msg__FluidPressure as FluidPressure, - sensor_msgs__msg__Illuminance as Illuminance, - sensor_msgs__msg__Image as Image, - sensor_msgs__msg__Imu as Imu, - sensor_msgs__msg__JointState as JointState, - sensor_msgs__msg__Joy as Joy, - sensor_msgs__msg__JoyFeedback as JoyFeedback, - sensor_msgs__msg__JoyFeedbackArray as JoyFeedbackArray, - sensor_msgs__msg__LaserEcho as LaserEcho, - sensor_msgs__msg__LaserScan as LaserScan, - sensor_msgs__msg__MagneticField as MagneticField, - sensor_msgs__msg__MultiDOFJointState as MultiDOFJointState, - sensor_msgs__msg__MultiEchoLaserScan as MultiEchoLaserScan, - sensor_msgs__msg__NavSatFix as NavSatFix, - sensor_msgs__msg__NavSatStatus as NavSatStatus, - sensor_msgs__msg__PointCloud as PointCloud, - sensor_msgs__msg__PointCloud2 as PointCloud2, - sensor_msgs__msg__PointField as PointField, - sensor_msgs__msg__Range as Range, - sensor_msgs__msg__RegionOfInterest as RegionOfInterest, - sensor_msgs__msg__RelativeHumidity as RelativeHumidity, - sensor_msgs__msg__Temperature as Temperature, - sensor_msgs__msg__TimeReference as TimeReference, -) diff --git a/packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi deleted file mode 100644 index 67e96a08cca..00000000000 --- a/packages/dimos-generated/src/dimos_generated/shape_msgs/msg/__init__.pyi +++ /dev/null @@ -1,7 +0,0 @@ -__all__ = ["Mesh", "MeshTriangle", "Plane", "SolidPrimitive"] -from ..._types import ( - shape_msgs__msg__Mesh as Mesh, - shape_msgs__msg__MeshTriangle as MeshTriangle, - shape_msgs__msg__Plane as Plane, - shape_msgs__msg__SolidPrimitive as SolidPrimitive, -) diff --git a/packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi deleted file mode 100644 index 7d3c8665244..00000000000 --- a/packages/dimos-generated/src/dimos_generated/std_msgs/msg/__init__.pyi +++ /dev/null @@ -1,64 +0,0 @@ -__all__ = [ - "Bool", - "Byte", - "ByteMultiArray", - "Char", - "ColorRGBA", - "Empty", - "Float32", - "Float32MultiArray", - "Float64", - "Float64MultiArray", - "Header", - "Int8", - "Int8MultiArray", - "Int16", - "Int16MultiArray", - "Int32", - "Int32MultiArray", - "Int64", - "Int64MultiArray", - "MultiArrayDimension", - "MultiArrayLayout", - "String", - "UInt8", - "UInt8MultiArray", - "UInt16", - "UInt16MultiArray", - "UInt32", - "UInt32MultiArray", - "UInt64", - "UInt64MultiArray", -] -from ..._types import ( - std_msgs__msg__Bool as Bool, - std_msgs__msg__Byte as Byte, - std_msgs__msg__ByteMultiArray as ByteMultiArray, - std_msgs__msg__Char as Char, - std_msgs__msg__ColorRGBA as ColorRGBA, - std_msgs__msg__Empty as Empty, - std_msgs__msg__Float32 as Float32, - std_msgs__msg__Float32MultiArray as Float32MultiArray, - std_msgs__msg__Float64 as Float64, - std_msgs__msg__Float64MultiArray as Float64MultiArray, - std_msgs__msg__Header as Header, - std_msgs__msg__Int8 as Int8, - std_msgs__msg__Int8MultiArray as Int8MultiArray, - std_msgs__msg__Int16 as Int16, - std_msgs__msg__Int16MultiArray as Int16MultiArray, - std_msgs__msg__Int32 as Int32, - std_msgs__msg__Int32MultiArray as Int32MultiArray, - std_msgs__msg__Int64 as Int64, - std_msgs__msg__Int64MultiArray as Int64MultiArray, - std_msgs__msg__MultiArrayDimension as MultiArrayDimension, - std_msgs__msg__MultiArrayLayout as MultiArrayLayout, - std_msgs__msg__String as String, - std_msgs__msg__UInt8 as UInt8, - std_msgs__msg__UInt8MultiArray as UInt8MultiArray, - std_msgs__msg__UInt16 as UInt16, - std_msgs__msg__UInt16MultiArray as UInt16MultiArray, - std_msgs__msg__UInt32 as UInt32, - std_msgs__msg__UInt32MultiArray as UInt32MultiArray, - std_msgs__msg__UInt64 as UInt64, - std_msgs__msg__UInt64MultiArray as UInt64MultiArray, -) diff --git a/packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi deleted file mode 100644 index 4d4ff1cbc49..00000000000 --- a/packages/dimos-generated/src/dimos_generated/tf2_msgs/msg/__init__.pyi +++ /dev/null @@ -1,2 +0,0 @@ -__all__ = ["TF2Error", "TFMessage"] -from ..._types import tf2_msgs__msg__TF2Error as TF2Error, tf2_msgs__msg__TFMessage as TFMessage diff --git a/packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi deleted file mode 100644 index 14bcc8808b1..00000000000 --- a/packages/dimos-generated/src/dimos_generated/trajectory_msgs/msg/__init__.pyi +++ /dev/null @@ -1,12 +0,0 @@ -__all__ = [ - "JointTrajectory", - "JointTrajectoryPoint", - "MultiDOFJointTrajectory", - "MultiDOFJointTrajectoryPoint", -] -from ..._types import ( - trajectory_msgs__msg__JointTrajectory as JointTrajectory, - trajectory_msgs__msg__JointTrajectoryPoint as JointTrajectoryPoint, - trajectory_msgs__msg__MultiDOFJointTrajectory as MultiDOFJointTrajectory, - trajectory_msgs__msg__MultiDOFJointTrajectoryPoint as MultiDOFJointTrajectoryPoint, -) diff --git a/packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi deleted file mode 100644 index b33ed8f8f1c..00000000000 --- a/packages/dimos-generated/src/dimos_generated/vision_msgs/msg/__init__.pyi +++ /dev/null @@ -1,36 +0,0 @@ -__all__ = [ - "BoundingBox2D", - "BoundingBox2DArray", - "BoundingBox3D", - "BoundingBox3DArray", - "Classification", - "Detection2D", - "Detection2DArray", - "Detection3D", - "Detection3DArray", - "LabelInfo", - "ObjectHypothesis", - "ObjectHypothesisWithPose", - "Point2D", - "Pose2D", - "VisionClass", - "VisionInfo", -] -from ..._types import ( - vision_msgs__msg__BoundingBox2D as BoundingBox2D, - vision_msgs__msg__BoundingBox2DArray as BoundingBox2DArray, - vision_msgs__msg__BoundingBox3D as BoundingBox3D, - vision_msgs__msg__BoundingBox3DArray as BoundingBox3DArray, - vision_msgs__msg__Classification as Classification, - vision_msgs__msg__Detection2D as Detection2D, - vision_msgs__msg__Detection2DArray as Detection2DArray, - vision_msgs__msg__Detection3D as Detection3D, - vision_msgs__msg__Detection3DArray as Detection3DArray, - vision_msgs__msg__LabelInfo as LabelInfo, - vision_msgs__msg__ObjectHypothesis as ObjectHypothesis, - vision_msgs__msg__ObjectHypothesisWithPose as ObjectHypothesisWithPose, - vision_msgs__msg__Point2D as Point2D, - vision_msgs__msg__Pose2D as Pose2D, - vision_msgs__msg__VisionClass as VisionClass, - vision_msgs__msg__VisionInfo as VisionInfo, -) diff --git a/packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi b/packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi deleted file mode 100644 index 11bb9bcc2c1..00000000000 --- a/packages/dimos-generated/src/dimos_generated/visualization_msgs/msg/__init__.pyi +++ /dev/null @@ -1,28 +0,0 @@ -__all__ = [ - "ImageMarker", - "InteractiveMarker", - "InteractiveMarkerControl", - "InteractiveMarkerFeedback", - "InteractiveMarkerInit", - "InteractiveMarkerPose", - "InteractiveMarkerUpdate", - "Marker", - "MarkerArray", - "MenuEntry", - "MeshFile", - "UVCoordinate", -] -from ..._types import ( - visualization_msgs__msg__ImageMarker as ImageMarker, - visualization_msgs__msg__InteractiveMarker as InteractiveMarker, - visualization_msgs__msg__InteractiveMarkerControl as InteractiveMarkerControl, - visualization_msgs__msg__InteractiveMarkerFeedback as InteractiveMarkerFeedback, - visualization_msgs__msg__InteractiveMarkerInit as InteractiveMarkerInit, - visualization_msgs__msg__InteractiveMarkerPose as InteractiveMarkerPose, - visualization_msgs__msg__InteractiveMarkerUpdate as InteractiveMarkerUpdate, - visualization_msgs__msg__Marker as Marker, - visualization_msgs__msg__MarkerArray as MarkerArray, - visualization_msgs__msg__MenuEntry as MenuEntry, - visualization_msgs__msg__MeshFile as MeshFile, - visualization_msgs__msg__UVCoordinate as UVCoordinate, -) diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/CMakeLists.txt deleted file mode 100644 index 12d0575bcb3..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(builtin_interfaces VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces}) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/package.xml deleted file mode 100644 index 2e1d90bbbc2..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/builtin_interfaces/package.xml +++ /dev/null @@ -1 +0,0 @@ -builtin_interfaces0.1.0DimOS message sourcesDimOSApache-2.0rosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/CMakeLists.txt deleted file mode 100644 index a920ce4ebe0..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(dimos_msgs VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -find_package(builtin_interfaces REQUIRED) -find_package(geometry_msgs REQUIRED) -find_package(std_msgs REQUIRED) -find_package(vision_msgs REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces geometry_msgs std_msgs vision_msgs) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/package.xml deleted file mode 100644 index dbdcecaa2d3..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/dimos_msgs/package.xml +++ /dev/null @@ -1 +0,0 @@ -dimos_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesgeometry_msgsstd_msgsvision_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/CMakeLists.txt deleted file mode 100644 index a41d835698e..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(foxglove_msgs VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -find_package(builtin_interfaces REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/package.xml deleted file mode 100644 index 576acc0a793..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/foxglove_msgs/package.xml +++ /dev/null @@ -1 +0,0 @@ -foxglove_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/CMakeLists.txt deleted file mode 100644 index 53b1078b5c5..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(geometry_msgs VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -find_package(std_msgs REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES std_msgs) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/package.xml deleted file mode 100644 index cfdf9a33d31..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/geometry_msgs/package.xml +++ /dev/null @@ -1 +0,0 @@ -geometry_msgs0.1.0DimOS message sourcesDimOSApache-2.0std_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/CMakeLists.txt deleted file mode 100644 index d429a44d1a3..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(nav_msgs VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -find_package(builtin_interfaces REQUIRED) -find_package(geometry_msgs REQUIRED) -find_package(std_msgs REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces geometry_msgs std_msgs) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/package.xml deleted file mode 100644 index efa14c2b878..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/nav_msgs/package.xml +++ /dev/null @@ -1 +0,0 @@ -nav_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesgeometry_msgsstd_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json deleted file mode 100644 index a82249ec698..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/packages.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - "builtin_interfaces", - "std_msgs", - "geometry_msgs", - "vision_msgs", - "dimos_msgs", - "foxglove_msgs", - "nav_msgs", - "sensor_msgs", - "shape_msgs", - "tf2_msgs", - "trajectory_msgs", - "visualization_msgs" -] diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/CMakeLists.txt deleted file mode 100644 index 50604e983bf..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(sensor_msgs VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -find_package(builtin_interfaces REQUIRED) -find_package(geometry_msgs REQUIRED) -find_package(std_msgs REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces geometry_msgs std_msgs) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/package.xml deleted file mode 100644 index fc56e4a4f5d..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/sensor_msgs/package.xml +++ /dev/null @@ -1 +0,0 @@ -sensor_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesgeometry_msgsstd_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/CMakeLists.txt deleted file mode 100644 index 50ff6e65380..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(shape_msgs VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -find_package(geometry_msgs REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES geometry_msgs) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/package.xml deleted file mode 100644 index 5c57b45765c..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/shape_msgs/package.xml +++ /dev/null @@ -1 +0,0 @@ -shape_msgs0.1.0DimOS message sourcesDimOSApache-2.0geometry_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/CMakeLists.txt deleted file mode 100644 index 03d98a1aad8..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(std_msgs VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -find_package(builtin_interfaces REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/msg/Empty.msg b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/msg/Empty.msg deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/package.xml deleted file mode 100644 index 799db5dcff6..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/std_msgs/package.xml +++ /dev/null @@ -1 +0,0 @@ -std_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/CMakeLists.txt deleted file mode 100644 index d825ff76e54..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(tf2_msgs VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -find_package(geometry_msgs REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES geometry_msgs) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/package.xml deleted file mode 100644 index e8f1b237c21..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/tf2_msgs/package.xml +++ /dev/null @@ -1 +0,0 @@ -tf2_msgs0.1.0DimOS message sourcesDimOSApache-2.0geometry_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/CMakeLists.txt deleted file mode 100644 index ecccce9ab8f..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(trajectory_msgs VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -find_package(builtin_interfaces REQUIRED) -find_package(geometry_msgs REQUIRED) -find_package(std_msgs REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces geometry_msgs std_msgs) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/package.xml deleted file mode 100644 index b9d2f8fae45..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/trajectory_msgs/package.xml +++ /dev/null @@ -1 +0,0 @@ -trajectory_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesgeometry_msgsstd_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/CMakeLists.txt deleted file mode 100644 index 0145311b9d6..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(vision_msgs VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -find_package(geometry_msgs REQUIRED) -find_package(std_msgs REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES geometry_msgs std_msgs) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/package.xml deleted file mode 100644 index 413b5cd9d33..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/vision_msgs/package.xml +++ /dev/null @@ -1 +0,0 @@ -vision_msgs0.1.0DimOS message sourcesDimOSApache-2.0geometry_msgsstd_msgsrosidl_interface_packagesament_cmake diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/CMakeLists.txt b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/CMakeLists.txt deleted file mode 100644 index 7526e7c721d..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(visualization_msgs VERSION 0.1.0) -find_package(ament_cmake REQUIRED) -find_package(rosidl_cmake REQUIRED) -find_package(rosidl_adapter REQUIRED) -find_package(rosidl_generator_type_description REQUIRED) -find_package(rosidl_generator_c REQUIRED) -find_package(rosidl_generator_cpp REQUIRED) -find_package(rosidl_typesupport_fastrtps_cpp REQUIRED) -find_package(builtin_interfaces REQUIRED) -find_package(geometry_msgs REQUIRED) -find_package(sensor_msgs REQUIRED) -find_package(std_msgs REQUIRED) -file(GLOB interfaces RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "msg/*.msg") -rosidl_generate_interfaces(${PROJECT_NAME} ${interfaces} DEPENDENCIES builtin_interfaces geometry_msgs sensor_msgs std_msgs) -ament_package() diff --git a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/package.xml b/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/package.xml deleted file mode 100644 index 959c86e74f1..00000000000 --- a/packages/dimos-generated/src/dimos_generated_schemas/package/cpp/visualization_msgs/package.xml +++ /dev/null @@ -1 +0,0 @@ -visualization_msgs0.1.0DimOS message sourcesDimOSApache-2.0builtin_interfacesgeometry_msgssensor_msgsstd_msgsrosidl_interface_packagesament_cmake diff --git a/scripts/test_message_user_story.sh b/scripts/test_message_user_story.sh index d0958934916..c199f374c92 100644 --- a/scripts/test_message_user_story.sh +++ b/scripts/test_message_user_story.sh @@ -3,17 +3,56 @@ set -euo pipefail cd "$(dirname "$0")/.." story_build="$PWD/build/message-codegen/user-story" story_python="${DIMOS_CODEGEN_PYTHON:-$PWD/.venv/bin/python}" -story_fastcdr="${DIMOS_FASTCDR_PREFIX:-$PWD/build/message-codegen/install}" -"$story_python" -m dimos_cdrgen.generate \ - --package-root examples/message-codegen/user-story \ - --type story_msgs/msg/DeviceReading --python-module story_messages \ - --output "$story_build" -c++ -std=c++17 -I"$story_fastcdr/include" -I"$story_build/cpp" \ - examples/message-codegen/user-story/consumer.cpp "$story_fastcdr/lib/libfastcdr.a" \ - -o "$story_build/cpp-consumer" -mkdir -p "$story_build/rust/src/bin" "$story_build/evidence" -cp examples/message-codegen/user-story/consumer.rs "$story_build/rust/src/bin/story-consumer.rs" +"$story_python" - <<'PY' +import json +import os +from pathlib import Path +import shutil +import subprocess +from dimos_message_project.build import local_cargo_dependency +from dimos_cdrgen.generate import generate +from dimos_cdrgen.native_build import prepare_cpp +from dimos.message_codegen.native_build import write_cmake_toolchain +from dimos_cdrgen.ownership import Dependency +from dimos_generated_schemas.provider import package_root +root = Path.cwd() +output = root / "build/message-codegen/user-story" +dependency = Dependency.load(package_root()) +generate([root / "examples/message-codegen/user-story"], output, + ["story_msgs/msg/DeviceReading"], "story_messages", shared=True, + dependencies=(dependency,)) +sources = {name: Path(path) for name, path in json.loads(os.environ.get("DIMOS_NATIVE_SOURCE_DIRS", "{}")).items()} +cache = os.environ.get("DIMOS_NATIVE_TEST_CACHE") +prefix = prepare_cpp(output, cache=Path(cache) if cache else None, + offline=os.environ.get("DIMOS_OFFLINE") == "1", source_dirs=sources or None) +toolchain = write_cmake_toolchain(prefix, output / "toolchain.cmake") +consumer = output / "consumer" +consumer.mkdir(exist_ok=True) +(consumer / "CMakeLists.txt").write_text(f'''cmake_minimum_required(VERSION 3.20) +project(story_consumer LANGUAGES CXX) +find_package(story_messages CONFIG REQUIRED) +add_executable(cpp-consumer "{root}/examples/message-codegen/user-story/consumer.cpp") +target_compile_features(cpp-consumer PRIVATE cxx_std_17) +target_include_directories(cpp-consumer PRIVATE "{root}/native/cpp/include") +target_link_libraries(cpp-consumer PRIVATE story_messages::messages) +set_target_properties(cpp-consumer PROPERTIES RUNTIME_OUTPUT_DIRECTORY "{output}") +''') +subprocess.run(["cmake", "--fresh", "-S", str(consumer), "-B", str(consumer / "build"), f"-DCMAKE_TOOLCHAIN_FILE={toolchain}"], check=True) +subprocess.run(["cmake", "--build", str(consumer / "build"), "--parallel", "2"], check=True) +# Python-only dependency wheels carry schemas; reconstruct native sources without +# changing their type ownership or rebuilding the DimOS runtime. +builtin = output / "dimos_generated" +generate([dependency.root / "schemas"], builtin, list(dependency.owned), dependency.module, + version=dependency.version, shared=True, languages=("rust",)) +manifest = output / "rust/Cargo.toml" +manifest.write_text(local_cargo_dependency(manifest.read_text(), dependency.module).replace('../dimos_generated', '../dimos_generated/rust')) +(output / "rust/src/bin").mkdir(exist_ok=True) +shutil.copy2(root / "examples/message-codegen/user-story/consumer.rs", output / "rust/src/bin/story-consumer.rs") +PY +mkdir -p "$story_build/evidence" cargo build --offline --manifest-path "$story_build/rust/Cargo.toml" --bin story-consumer -PYTHONPATH="$story_build/python:$PWD${PYTHONPATH:+:$PYTHONPATH}" \ - "$story_python" examples/message-codegen/user-story/demo_module.py --build "$story_build" \ +"${DIMOS_RUNTIME_PYTHON:-$story_python}" -m pip install --no-deps --no-build-isolation \ + --target "$story_build/site" "$story_build/python" +PYTHONPATH="$story_build/site:$PWD${PYTHONPATH:+:$PYTHONPATH}" \ + "${DIMOS_RUNTIME_PYTHON:-$story_python}" examples/message-codegen/user-story/demo_module.py --build "$story_build" \ | tee "$story_build/evidence/terminal.txt"