Metadata-Version: 2.4
Name: rosless
Version: 0.1.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: System :: Networking
Summary: Talk to ROS 2 topics without installing ROS
Keywords: ros,ros2,dds,rtps,robotics
Author: Jeff Hykin
License-Expression: Apache-2.0
Requires-Python: >=3.10
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/jeff-hykin/rosless
Project-URL: Repository, https://github.com/jeff-hykin/rosless

# rosless

Talk to ROS 2 topics without installing ROS.

ROS 2 has no wire protocol of its own. It is plain DDS/RTPS plus two naming
conventions, so a program that speaks RTPS and knows those conventions is
indistinguishable from a ROS node on the wire. This package does exactly that,
from Rust, with no rclpy, no sourced workspace, and no ROS installation.

```sh
pip install rosless
```

## Usage

```python
import rosless

for topic in rosless.topics(wait=3.0):
    print(topic.name, topic.type_name, topic.publishers, topic.subscribers)

with rosless.subscribe("/imu") as imu:
    for message in imu:
        print(message["angular_velocity"]["z"])
```

Messages whose type is in the built-in catalogue (248 definitions across 24
packages, including `sensor_msgs/msg/PointCloud2`, `nav_msgs/msg/Odometry`, and
`tf2_msgs/msg/TFMessage`) arrive as plain dicts. `uint8[]` sequences arrive
base64 encoded, so an image or a point cloud stays one compact string instead of
a million-element list.

Anything not catalogued arrives as `bytes` holding the raw CDR body:

```python
subscription = rosless.subscribe("/widgets")
if not subscription.is_catalogued:
    body = subscription.read()          # bytes, encapsulation header stripped
```

## API

| Call | What it does |
| --- | --- |
| `discover(domain=0, wait=2.0)` | Topics, services, and participant count |
| `topics(...)` / `services(...)` | Just one half of the graph |
| `subscribe(topic, domain=0, wait=2.0)` | A `Subscription`, iterable and a context manager |
| `decode(type_name, payload)` | Decode CDR including the 4-byte header |
| `decode_body(type_name, body, little_endian=True)` | Decode a header-stripped body |
| `type_names()` / `lookup(type_name)` | Browse the catalogue |
| `mangle_topic` / `demangle_topic` | `/chatter` ⇄ `rt/chatter` |
| `mangle_type` / `demangle_type` | `std_msgs/msg/String` ⇄ `std_msgs::msg::dds_::String_` |

`Subscription.read(timeout=None)` returns `None` when the timeout expires. Every
blocking call releases the GIL and stays interruptible with Ctrl-C.

Source and the matching command line tool: <https://github.com/jeff-hykin/rosless>

