A minimal, single-file communication middleware built on Zenoh
Project description
ZRM (Zenoh ROS-like Middleware)
A minimal, single-file communication middleware built on Zenoh, providing a clean and simple API inspired by ROS2 patterns.
https://github.com/user-attachments/assets/3e41d9a7-f553-457b-a879-cae2af45bf63
Features
- Minimalist: Single-file implementation
- Type-safe: Protobuf-based serialization with runtime type checking
- Ergonomic: Pythonic API with sensible defaults
Installation
pip install zrm
Quick Start
import zrm
from zrm.msgs import geometry_pb2
node = zrm.Node("my_node")
# Publish
pub = node.create_publisher("robot/pose", geometry_pb2.Pose2D)
pub.publish(geometry_pb2.Pose2D(x=1.0, y=2.0, theta=0.5))
# Subscribe
sub = node.create_subscriber("robot/pose", geometry_pb2.Pose2D)
if pose := sub.latest():
print(f"Position: x={pose.x}, y={pose.y}")
node.close()
Protobuf definition:
message Pose2D {
double x = 1;
double y = 2;
double theta = 3;
}
CLI Tools
zrm-topic list # List topics
zrm-topic echo robot/pose # Echo messages
zrm-service list # List services
zrm-service call add 'a: 1 b: 2' # Call service
zrm-action list # List actions
zrm-action send fib 'order: 10' # Send action goal
zrm-node list # List nodes
More Examples
See examples/ for complete working examples including services, actions with feedback/cancellation, and graph discovery.
Services
Services use nested Request/Response messages:
import zrm
from zrm.srvs import examples_pb2
def add_callback(req):
return examples_pb2.AddTwoInts.Response(sum=req.a + req.b)
node = zrm.Node("service_node")
server = node.create_service("add_two_ints", examples_pb2.AddTwoInts, add_callback)
client = node.create_client("add_two_ints", examples_pb2.AddTwoInts)
response = client.call(examples_pb2.AddTwoInts.Request(a=5, b=3))
print(f"Sum: {response.sum}") # Output: 8
node.close()
Protobuf definition:
message AddTwoInts {
message Request { int32 a = 1; int32 b = 2; }
message Response { int32 sum = 1; }
}
Actions
Actions support long-running goals with feedback and cancellation:
import zrm
from zrm.actions import examples_pb2
def execute_fibonacci(goal_handle: zrm.ServerGoalHandle) -> None:
goal_handle.execute()
sequence = [0, 1]
for i in range(1, goal_handle.goal.order):
if goal_handle.cancel_requested:
goal_handle.cancel(examples_pb2.Fibonacci.Result(sequence=sequence))
return
sequence.append(sequence[i] + sequence[i - 1])
goal_handle.publish_feedback(examples_pb2.Fibonacci.Feedback(partial_sequence=sequence))
goal_handle.succeed(examples_pb2.Fibonacci.Result(sequence=sequence))
node = zrm.Node("action_node")
server = node.create_action_server("fibonacci", examples_pb2.Fibonacci, execute_fibonacci)
client = node.create_action_client("fibonacci", examples_pb2.Fibonacci)
goal_handle = client.send_goal(
examples_pb2.Fibonacci.Goal(order=10),
feedback_callback=lambda fb: print(f"Progress: {list(fb.partial_sequence)}")
)
result = goal_handle.get_result(timeout=30.0)
print(f"Result: {list(result.sequence)}")
node.close()
Protobuf definition:
message Fibonacci {
message Goal { int32 order = 1; }
message Result { repeated int32 sequence = 1; }
message Feedback { repeated int32 partial_sequence = 1; }
}
Message Organization & Proto Generation
Directory Structure
src/<package>/
├── proto/ # Proto definitions
│ ├── msgs/ # Message definitions
│ ├── srvs/ # Service definitions
│ └── actions/ # Action definitions
├── msgs/ # Auto-generated *_pb2.py
├── srvs/ # Auto-generated *_pb2.py
└── actions/ # Auto-generated *_pb2.py
Generating Python Code
zrm-proto # Generate from local protos
zrm-proto --dep zrm # Include dependency protos
Standard Messages
| Category | Module | Types |
|---|---|---|
| Messages | zrm.msgs.header_pb2 |
Header |
| Messages | zrm.msgs.geometry_pb2 |
Point, Vector3, Quaternion, Pose, Pose2D, Twist, PoseStamped |
| Messages | zrm.msgs.sensor_pb2 |
Imu, Image, CompressedImage, CameraInfo, JointState |
| Messages | zrm.msgs.vision_pb2 |
Point2D, BoundingBox2D |
| Services | zrm.srvs.std_pb2 |
Trigger |
| Services | zrm.srvs.examples_pb2 |
AddTwoInts |
| Actions | zrm.actions.examples_pb2 |
Fibonacci |
Development
git clone https://github.com/JafarAbdi/zrm.git
cd zrm
uv sync
# Linting
uv run pre-commit run -a
# Testing
uv run pytest tests/ -v
Acknowledgements
- Graph class inspired by ros-z
- Built on Eclipse Zenoh
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zrm-2.0.0.tar.gz.
File metadata
- Download URL: zrm-2.0.0.tar.gz
- Upload date:
- Size: 31.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15c0a7cd385be4f3635074d46475f5f795fa41628ea3c307d0593e55e49bcf6d
|
|
| MD5 |
8c944e9d56b5a757d1c024f3c469b385
|
|
| BLAKE2b-256 |
de8a4c49b99780203be27971a10ca18806711e030c263a0f9633e6f5ea70c1f1
|
File details
Details for the file zrm-2.0.0-py3-none-any.whl.
File metadata
- Download URL: zrm-2.0.0-py3-none-any.whl
- Upload date:
- Size: 44.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
95395a9e4a67bb516061d234e9e14b33b59760c82ac63da884e2806e4cf9588e
|
|
| MD5 |
f3068d030abbf779b5904f00ce2215a7
|
|
| BLAKE2b-256 |
2bf5bc76109a1e4ca4eaa811e22c3595ce7eed46fedc0ed2d84a06b0c9bcc8c8
|