# How to Convert ROS Messages to LCM in DimOS for Cross-Language Interoperability

> Learn how to convert ROS messages to LCM in DimOS using the Bridge class for seamless cross-language interoperability. Discover the simple steps to establish communication.

- Repository: [Dimensional/dimos](https://github.com/dimensionalOS/dimos)
- Tags: how-to-guide
- Published: 2026-03-15

---

**DimOS converts ROS messages to LCM by bridging `ROSTransport` subscribers to `LCMTransport` publishers using the `Bridge` class or functional `bridge()` helper defined in [`dimos/protocol/pubsub/bridge.py`](https://github.com/dimensionalOS/dimos/blob/main/dimos/protocol/pubsub/bridge.py).**

The dimensionalOS/dimos repository abstracts all inter-process communication through unified pub-sub transports, enabling seamless conversion between ROS and LCM protocols. This architecture allows systems running C++, Java, or other LMC-compatible clients to consume ROS data without requiring a full ROS runtime environment.

## Understanding Pub-Sub Transports in DimOS

DimOS defines all messaging interactions through the generic `Transport[T]` interface implemented in [`dimos/core/transport.py`](https://github.com/dimensionalOS/dimos/blob/main/dimos/core/transport.py). Two critical implementations handle the protocol conversion:

- **`ROSTransport`** (lines 51-84): Wraps ROS 1/2 topics using `dimos.msgs.*` types for publishing and subscribing within the ROS ecosystem.
- **`LCMTransport`** (lines 12-41): Implements Lightweight Communications and Marshalling (LCM) multicast messaging for high-performance, language-agnostic data distribution.

Both classes inherit from `PubSubTransport[T]`, providing standardized `broadcast()` and `subscribe()` methods that make protocol bridging possible through simple composition rather than complex adapters.

## The Bridging Architecture

The conversion logic resides in [`dimos/protocol/pubsub/bridge.py`](https://github.com/dimensionalOS/dimos/blob/main/dimos/protocol/pubsub/bridge.py), which offers two implementation patterns:

**`bridge()` function** (lines 50-66): A low-level functional helper for immediate, imperative bridging between two transports.

**`Bridge` class** (lines 70-98): A service-oriented wrapper configured via `BridgeConfig` for lifecycle-managed conversion suitable for long-running applications.

Both approaches operate by subscribing to the source transport, applying a translator function to map topics and messages, and publishing results to the destination transport. When converting ROS to LCM, `ROSTransport` serves as the source and `LCMTransport` as the destination.

## Implementing ROS to LCM Conversion

Follow these three steps to establish message flow from ROS topics to LCM channels:

1. **Instantiate transports**: Create `ROSTransport` for the ROS source topic and `LCMTransport` for the LCM destination topic.
2. **Configure the bridge**: Use `BridgeConfig` to wire source to destination, specifying a translator function (identity for same message types).
3. **Start the service**: Call `start()` on the bridge instance to begin asynchronous message forwarding.

Here is a minimal implementation converting ROS Image messages to LCM:

```python
from dimos.core.transport import ROSTransport, LCMTransport
from dimos.msgs.sensor_msgs import Image
from dimos.protocol.pubsub.bridge import Bridge, BridgeConfig

# 1. Define transports

ros_image = ROSTransport("/camera/image_raw", Image)
lcm_image = LCMTransport("/camera_image", Image)

# 2. Configure bridge with identity translator

bridge_cfg = BridgeConfig(
    source=ros_image,               # ROS side (subscribe)

    destination=lcm_image,          # LCM side (publish)

    translator=lambda topic, msg: (topic, msg),  # Pass through unchanged

    subscribe_topic=None,           # Bridge all messages on this transport

)

# 3. Initialize and start

ros_to_lcm = Bridge(bridge_cfg)
ros_to_lcm.start()   # Messages now flow from ROS → LCM

# ... system operation ...

ros_to_lcm.stop()

```

The identity translator `lambda topic, msg: (topic, msg)` works when both systems utilize identical ROS message definitions (e.g., `sensor_msgs/Image`). For heterogeneous conversions—such as mapping ROS `Image` to custom LCM structures—implement a translator that constructs the target message type from the source data.

## Integrating Bridges into Blueprints

Production deployments typically extend existing blueprints to expose ROS streams on LCM topics. The Unitree Go2 ROS blueprint in [`dimos/robot/unitree/go2/blueprints/smart/unitree_go2_ros.py`](https://github.com/dimensionalOS/dimos/blob/main/dimos/robot/unitree/go2/blueprints/smart/unitree_go2_ros.py) demonstrates this pattern by adding LCM mirror transports:

```python
from dimos.core.transport import ROSTransport, LCMTransport
from dimos.msgs.geometry_msgs import PoseStamped
from dimos.msgs.sensor_msgs import PointCloud2
from dimos.protocol.pubsub.bridge import Bridge, BridgeConfig

# Define both ROS and LCM transports

transports = {
    ("lidar", PointCloud2): ROSTransport("lidar", PointCloud2),
    ("odom", PoseStamped): ROSTransport("odom", PoseStamped),
    ("lidar_lcm", PointCloud2): LCMTransport("/lidar_lcm", PointCloud2),
    ("odom_lcm", PoseStamped): LCMTransport("/odom_lcm", PoseStamped),
}

# Bridge helper function

def _bridge_pair(ros_transport, lcm_transport):
    cfg = BridgeConfig(
        source=ros_transport,
        destination=lcm_transport,
        translator=lambda t, m: (t, m)
    )
    bridge = Bridge(cfg)
    bridge.start()
    return bridge

# Initialize bridges in blueprint construction

bridges = [
    _bridge_pair(transports[("lidar", PointCloud2)], transports[("lidar_lcm", PointCloud2)]),
    _bridge_pair(transports[("odom", PoseStamped)], transports[("odom_lcm", PoseStamped)]),
]

```

This pattern enables any LCM client—including C++ or Java implementations—to subscribe to `/lidar_lcm` or `/odom_lcm` without ROS dependencies, creating true cross-language interoperability.

## Bidirectional Conversion Support

The bridge architecture supports bidirectional flows. To convert LCM messages back to ROS, instantiate `LCMTransport` as the `source` and `ROSTransport` as the `destination` in the `BridgeConfig`. This flexibility allows DimOS to serve as a universal protocol adapter in heterogeneous robotic systems.

## Summary

- **DimOS** unifies ROS and LCM through the `Transport[T]` interface defined in [`dimos/core/transport.py`](https://github.com/dimensionalOS/dimos/blob/main/dimos/core/transport.py).
- **Conversion** relies on `ROSTransport` (lines 51-84) receiving messages and `LCMTransport` (lines 12-41) publishing them.
- **Bridging** implementations reside in [`dimos/protocol/pubsub/bridge.py`](https://github.com/dimensionalOS/dimos/blob/main/dimos/protocol/pubsub/bridge.py), offering both functional (`bridge()`) and object-oriented (`Bridge` class) APIs.
- **Configuration** requires a `BridgeConfig` with source, destination, and translator parameters.
- **Integration** into existing blueprints follows the pattern demonstrated in [`unitree_go2_ros.py`](https://github.com/dimensionalOS/dimos/blob/main/unitree_go2_ros.py), enabling incremental LCM exposure of ROS topics.

## Frequently Asked Questions

### What is the purpose of the translator function in DimOS bridges?

The translator function maps source topic names and message objects to the destination format required by the target transport. It accepts `(topic, message)` tuples and returns transformed `(new_topic, new_message)` pairs. When converting ROS to LCM with identical message schemas, an identity lambda suffices; for protocol mismatches, implement custom conversion logic to build target-specific message structures.

### Can I convert LCM messages back to ROS using the same bridge?

Yes. Reverse the source and destination assignments in `BridgeConfig` by setting `source` to your `LCMTransport` instance and `destination` to your `ROSTransport` instance. The bridge is protocol-agnostic and handles message flow in either direction, though you may need to adjust the translator function to accommodate LCM-specific message structures.

### Which file contains the transport implementations for ROS and LCM?

The transport implementations are located in [`dimos/core/transport.py`](https://github.com/dimensionalOS/dimos/blob/main/dimos/core/transport.py). `ROSTransport` occupies lines 51-84, while `LCMTransport` is defined at lines 12-41. Low-level client implementations reside in [`dimos/protocol/pubsub/impl/rospubsub.py`](https://github.com/dimensionalOS/dimos/blob/main/dimos/protocol/pubsub/impl/rospubsub.py) (ROS) and [`dimos/protocol/pubsub/impl/lcmpubsub.py`](https://github.com/dimensionalOS/dimos/blob/main/dimos/protocol/pubsub/impl/lcmpubsub.py) (LCM).

### How do I handle message type differences between ROS and LCM?

Implement a custom translator function in `BridgeConfig` that constructs the destination message type from the source data fields. For example, when converting ROS `Image` to a custom LCM image structure, the translator would extract height, width, and encoding fields from the ROS message and instantiate the equivalent LCM object with those values mapped to the appropriate fields.