Skip to main content

Add your description here

Project description

ZRM (Zenoh ROS-like Middleware)

CI

A minimal, single-file communication middleware built on Zenoh, providing a clean and simple API inspired by ROS2 patterns.

Features

  • Minimalist: Single-file implementation
  • Type-safe: Protobuf-based serialization with runtime type checking
  • Ergonomic: Pythonic API with sensible defaults

Installation

# Install from PyPI
pip install zrm

For development:

# Clone the repository and install dependencies
git clone https://github.com/yourusername/zrm.git
cd zrm
uv sync

Development

Linting

Run linting and formatting checks using pre-commit:

uv run pre-commit run -a

This runs all configured linters and formatters on all files in the repository.

Testing

Run the test suite with pytest:

uv run pytest tests/ -v

Quick Start

Publisher/Subscriber

from zrm import Node
from zrm.msgs import geometry_pb2

# Create a node
node = Node("my_node")

# Create publisher and subscriber via node factory methods
pub = node.create_publisher("robot/pose", geometry_pb2.Pose2D)
sub = node.create_subscriber("robot/pose", geometry_pb2.Pose2D)

# Publish a message
pose = geometry_pb2.Pose2D(x=1.0, y=2.0, theta=0.5)
pub.publish(pose)

# Get latest message
current_pose = sub.latest()
if current_pose:
    print(f"Position: x={current_pose.x}, y={current_pose.y}")

# Clean up
pub.close()
sub.close()
node.close()

Subscriber with Callback

def handle_pose(pose):
    print(f"Received: x={pose.x}, y={pose.y}")

node = Node("listener_node")
sub = node.create_subscriber(
    topic="robot/pose",
    msg_type=geometry_pb2.Pose2D,
    callback=handle_pose,
)

Service Server/Client

Services use namespaced Request/Response messages for better organization:

from zrm import Node
from zrm.srvs import examples_pb2

# Define service handler
def add_callback(req):
    return examples_pb2.AddTwoInts.Response(sum=req.a + req.b)

# Create node
node = Node("service_node")

# Create service server via node factory method
server = node.create_service(
    service="add_two_ints",
    service_type=examples_pb2.AddTwoInts,
    callback=add_callback,
)

# Create service client via node factory method
client = node.create_client(
    service="add_two_ints",
    service_type=examples_pb2.AddTwoInts,
)

# Call service
request = examples_pb2.AddTwoInts.Request(a=5, b=3)
response = client.call(request)
print(f"Sum: {response.sum}")  # Output: 8

# Clean up
client.close()
server.close()
node.close()

Service Definition Pattern:

// Services must have nested Request and Response messages
message AddTwoInts {
  message Request {
    int32 a = 1;
    int32 b = 2;
  }

  message Response {
    int32 sum = 1;
  }
}

Message Organization

ZRM uses a convention-based message organization:

Directory Structure

proto/
├── msgs/              # Message definitions
│   ├── geometry.proto
│   ├── sensor.proto
│   └── header.proto
└── srvs/              # Service definitions
    ├── std.proto
    └── examples.proto
src/zrm/
├── msgs/                  # Generated message modules
│   ├── geometry_pb2.py
│   ├── sensor_pb2.py
│   └── header_pb2.py
└── srvs/                  # Generated service modules
    ├── std_pb2.py
    └── examples_pb2.py

Generating Python Code

# Generate message modules
../protoc-33.0-linux-x86_64/bin/protoc --pyi_out=src --python_out=src --proto_path=zrm/msgs=proto/msgs/ $(fd -e proto . proto/msgs/)

# Generate service modules
../protoc-33.0-linux-x86_64/bin/protoc --pyi_out=src --python_out=src --proto_path=zrm/srvs=proto/srvs/ $(fd -e proto . proto/srvs/)

Standard Messages

Messages (zrm.msgs):

  • geometry: Point, Vector3, Quaternion, Pose, Pose2D, Twist, PoseStamped
  • sensor: Image, LaserScan, PointCloud2
  • header: Header

Services (zrm.srvs):

  • std: Trigger

CLI Tools

ZRM provides command-line tools for inspecting and interacting with the network:

Topic Commands

# List all topics and their publishers/subscribers
zrm-topic list

# Echo messages from a topic (auto-discovers type)
zrm-topic echo /robot/pose

# Echo with explicit type
zrm-topic echo /robot/pose -t zrm/msgs/geometry/Pose2D

# Publish to a topic
zrm-topic pub /robot/pose "x: 1.0 y: 2.0 theta: 0.5" -t zrm/msgs/geometry/Pose2D -r 10

# Measure topic frequency
zrm-topic hz /robot/pose

Node Commands

# List all nodes in the network
zrm-node list

Service Commands

# List all services in the network
zrm-service list

# Call a service (auto-discovers type)
zrm-service call add_two_ints 'a: 1 b: 2'

# Call with explicit type
zrm-service call add_two_ints 'a: 1 b: 2' -t zrm/srvs/examples/AddTwoInts

Examples

See examples/ directory for complete working examples:

  • talker.py / listener.py: Basic publisher/subscriber pattern
  • service_server.py / service_client.py: Service request/response pattern
  • Graph discovery and introspection

Acknowledgements

  • The Graph class is inspired by ros-z
  • Built on Eclipse Zenoh for efficient pub/sub and query/reply patterns

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zrm-1.0.0.tar.gz (16.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zrm-1.0.0-py3-none-any.whl (25.0 kB view details)

Uploaded Python 3

File details

Details for the file zrm-1.0.0.tar.gz.

File metadata

  • Download URL: zrm-1.0.0.tar.gz
  • Upload date:
  • Size: 16.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.14

File hashes

Hashes for zrm-1.0.0.tar.gz
Algorithm Hash digest
SHA256 d7bb07cbcd5817947d08a66d6672160ecaab212e4bf40cd6e168a4e203ca3798
MD5 3f93853d98ba618fb800bb047415f314
BLAKE2b-256 017c604148aa59b5a48537d6de5949d5081618b50f0b8df73a3062721ca2a786

See more details on using hashes here.

File details

Details for the file zrm-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: zrm-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 25.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.14

File hashes

Hashes for zrm-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e395ee377b764b5e3ca383fbc24944a277f8d0ddf6bd37f6f7ab93d1fad7ed5b
MD5 c3323c2a96425e245b6c4c28c78e46f6
BLAKE2b-256 9de75d2bf82771c323c4d5fb897dc496c27f0e7a064b25a2d93855fb44dd3e05

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page