Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions dimos/core/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
cast,
)

from dimos_cdrgen.registry import message_types
import numpy as np

from dimos.core.stream import Stream, Transport
Expand Down Expand Up @@ -199,21 +200,23 @@ class ROSTransport(PubSubTransport[DimosMsg]):
_ros: DimosROS | None = None

def __init__(self, topic: str, msg_type: type[DimosMsg], **kwargs: Any) -> None:
# TODO: Revisit generated-message adapters; ROS also uses CDR encoding.
if hasattr(msg_type, "__msgtype__") and describe_message(msg_type).encoding == "cdr":
raise TypeError(
"Generated messages require a ROS type adapter; raw CDR is not a ROS message"
)
# Generated values require a canonical registry identity and a ROS type adapter.
if hasattr(msg_type, "__msgtype__"):
name = getattr(msg_type, "__msgtype__", None)
if not isinstance(name, str) or message_types().get(name) is not msg_type:
raise TypeError("ROS transport requires a registry-owned generated message class")
# rclpy (about 0.1 s with rospubsub): only loaded when a ROSTransport exists.
from dimos.protocol.pubsub.impl.rospubsub import ROSTopic

super().__init__(ROSTopic(topic, msg_type))
self._kwargs = kwargs

def __reduce__(self) -> tuple[Any, ...]:
return (ROSTransport, (self.topic.topic, self.topic.msg_type))
return (partial(ROSTransport, **self._kwargs), (self.topic.topic, self.topic.msg_type))

def broadcast(self, _: Stream[DimosMsg] | None, msg: DimosMsg) -> None:
if not isinstance(msg, self.topic.msg_type):
raise TypeError("Message does not match the ROS transport declared type")
if self._ros is None:
self.start()
assert self._ros is not None # for type narrowing
Expand Down
11 changes: 7 additions & 4 deletions dimos/hardware/drive_trains/transport/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@
from typing import Any

from dimos.core.transport_factory import make_transport
from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped
from dimos.msgs.geometry_msgs.Twist import Twist
from dimos.msgs.geometry_msgs.Vector3 import Vector3
from dimos.message_utils.geometry import quaternion_euler
from dimos.messages.geometry_msgs.msg import PoseStamped, Twist, Vector3
from dimos.utils.logging_config import setup_logger

logger = setup_logger()
Expand Down Expand Up @@ -141,7 +140,11 @@ def read_enabled(self) -> bool:

def _on_odom(self, msg: PoseStamped) -> None:
with self._lock:
self._latest_odom = [msg.x, msg.y, msg.yaw]
self._latest_odom = [
msg.pose.position.x,
msg.pose.position.y,
quaternion_euler(msg.pose.orientation)[2],
]


def transport_lcm_factory(**kwargs: Any) -> TransportTwistAdapter:
Expand Down
25 changes: 16 additions & 9 deletions dimos/hardware/whole_body/transport/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
"""Transport-based whole-body adapter: bridges coordinator ↔ Module via pub/sub.

Subscribes /{hardware_id}/motor_states + /{hardware_id}/imu, publishes
/{hardware_id}/motor_command. ``network_interface`` is accepted but ignored.
/{hardware_id}/motor_command. The normal factory selects generated CDR on the
configured LCM/Zenoh backend. ``network_interface`` is accepted but ignored.
The existing ``transport_lcm`` registry key keeps its name and API; encoding
follows the canonical message type, while internal MotorState/MotorCommand
numerical values are adapted explicitly at these three wire edges.
"""

from __future__ import annotations
Expand All @@ -24,12 +28,14 @@
import threading
from typing import Any

import numpy as np

from dimos.core.transport_factory import make_transport
from dimos.hardware.spec import JointLimits
from dimos.hardware.whole_body.spec import IMUState, MotorCommand, MotorState
from dimos.msgs.sensor_msgs.Imu import Imu
from dimos.msgs.sensor_msgs.JointState import JointState
from dimos.msgs.sensor_msgs.MotorCommandArray import MotorCommandArray
from dimos.message_utils.time import header_now
from dimos.messages.dimos_msgs.msg import MotorCommandArray
from dimos.messages.sensor_msgs.msg import Imu, JointState
from dimos.utils.logging_config import setup_logger

logger = setup_logger()
Expand Down Expand Up @@ -135,11 +141,12 @@ def write_motor_commands(self, commands: list[MotorCommand]) -> bool:
return False

msg = MotorCommandArray(
q=[c.q for c in commands],
dq=[c.dq for c in commands],
kp=[c.kp for c in commands],
kd=[c.kd for c in commands],
tau=[c.tau for c in commands],
header=header_now(),
q=np.asarray([c.q for c in commands], dtype=np.float64),
dq=np.asarray([c.dq for c in commands], dtype=np.float64),
kp=np.asarray([c.kp for c in commands], dtype=np.float64),
kd=np.asarray([c.kd for c in commands], dtype=np.float64),
tau=np.asarray([c.tau for c in commands], dtype=np.float64),
)
self._motor_command_transport.publish(msg)
return True
Expand Down
Loading
Loading