zrm 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zrm-0.0.1/PKG-INFO +187 -0
- zrm-0.0.1/README.md +176 -0
- zrm-0.0.1/pyproject.toml +20 -0
- zrm-0.0.1/src/zrm/__init__.py +1102 -0
- zrm-0.0.1/src/zrm/cli/node.py +99 -0
- zrm-0.0.1/src/zrm/cli/service.py +74 -0
- zrm-0.0.1/src/zrm/cli/topic.py +76 -0
- zrm-0.0.1/src/zrm/generated_protos/example_services_pb2.py +40 -0
- zrm-0.0.1/src/zrm/generated_protos/example_services_pb2.pyi +21 -0
- zrm-0.0.1/src/zrm/generated_protos/geometry_pb2.py +49 -0
- zrm-0.0.1/src/zrm/generated_protos/geometry_pb2.pyi +73 -0
- zrm-0.0.1/src/zrm/generated_protos/header_pb2.py +36 -0
- zrm-0.0.1/src/zrm/generated_protos/header_pb2.pyi +13 -0
- zrm-0.0.1/src/zrm/generated_protos/sensor_pb2.py +46 -0
- zrm-0.0.1/src/zrm/generated_protos/sensor_pb2.pyi +93 -0
- zrm-0.0.1/src/zrm/generated_protos/services_pb2.py +40 -0
- zrm-0.0.1/src/zrm/generated_protos/services_pb2.pyi +19 -0
zrm-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: zrm
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Author: JafarAbdi
|
|
6
|
+
Author-email: JafarAbdi <jafar.uruc@gmail.com>
|
|
7
|
+
Requires-Dist: eclipse-zenoh>=1.6.2
|
|
8
|
+
Requires-Dist: protobuf>=6.33.0
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# ZRM (Zenoh ROS-like Middleware)
|
|
13
|
+
|
|
14
|
+
A minimal, single-file communication middleware built on Zenoh, providing a clean and simple API inspired by ROS2 patterns.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Minimalist**: Single-file implementation
|
|
19
|
+
- **Type-safe**: Protobuf-based serialization with runtime type checking
|
|
20
|
+
- **Ergonomic**: Pythonic API with sensible defaults
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Install dependencies using uv
|
|
26
|
+
uv sync
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
### Publisher/Subscriber
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from zrm import Node
|
|
35
|
+
from zrm.generated_protos import geometry_pb2
|
|
36
|
+
|
|
37
|
+
# Create a node
|
|
38
|
+
node = Node("my_node")
|
|
39
|
+
|
|
40
|
+
# Create publisher and subscriber via node factory methods
|
|
41
|
+
pub = node.create_publisher("robot/pose", geometry_pb2.Pose2D)
|
|
42
|
+
sub = node.create_subscriber("robot/pose", geometry_pb2.Pose2D)
|
|
43
|
+
|
|
44
|
+
# Publish a message
|
|
45
|
+
pose = geometry_pb2.Pose2D(x=1.0, y=2.0, theta=0.5)
|
|
46
|
+
pub.publish(pose)
|
|
47
|
+
|
|
48
|
+
# Get latest message
|
|
49
|
+
current_pose = sub.latest()
|
|
50
|
+
if current_pose:
|
|
51
|
+
print(f"Position: x={current_pose.x}, y={current_pose.y}")
|
|
52
|
+
|
|
53
|
+
# Clean up
|
|
54
|
+
pub.close()
|
|
55
|
+
sub.close()
|
|
56
|
+
node.close()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Subscriber with Callback
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
def handle_pose(pose):
|
|
63
|
+
print(f"Received: x={pose.x}, y={pose.y}")
|
|
64
|
+
|
|
65
|
+
node = Node("listener_node")
|
|
66
|
+
sub = node.create_subscriber(
|
|
67
|
+
topic="robot/pose",
|
|
68
|
+
msg_type=geometry_pb2.Pose2D,
|
|
69
|
+
callback=handle_pose,
|
|
70
|
+
)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Service Server/Client
|
|
74
|
+
|
|
75
|
+
Services use namespaced Request/Response messages for better organization:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from zrm import Node
|
|
79
|
+
from zrm.generated_protos import example_services_pb2
|
|
80
|
+
|
|
81
|
+
# Define service handler
|
|
82
|
+
def add_callback(req):
|
|
83
|
+
return example_services_pb2.AddTwoInts.Response(sum=req.a + req.b)
|
|
84
|
+
|
|
85
|
+
# Create node
|
|
86
|
+
node = Node("service_node")
|
|
87
|
+
|
|
88
|
+
# Create service server via node factory method
|
|
89
|
+
server = node.create_service(
|
|
90
|
+
service="add_two_ints",
|
|
91
|
+
service_type=example_services_pb2.AddTwoInts,
|
|
92
|
+
callback=add_callback,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Create service client via node factory method
|
|
96
|
+
client = node.create_client(
|
|
97
|
+
service="add_two_ints",
|
|
98
|
+
service_type=example_services_pb2.AddTwoInts,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Call service
|
|
102
|
+
request = example_services_pb2.AddTwoInts.Request(a=5, b=3)
|
|
103
|
+
response = client.call(request)
|
|
104
|
+
print(f"Sum: {response.sum}") # Output: 8
|
|
105
|
+
|
|
106
|
+
# Clean up
|
|
107
|
+
client.close()
|
|
108
|
+
server.close()
|
|
109
|
+
node.close()
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Service Definition Pattern:**
|
|
113
|
+
```protobuf
|
|
114
|
+
// Services must have nested Request and Response messages
|
|
115
|
+
message AddTwoInts {
|
|
116
|
+
message Request {
|
|
117
|
+
int32 a = 1;
|
|
118
|
+
int32 b = 2;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
message Response {
|
|
122
|
+
int32 sum = 1;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Protobuf Workflow
|
|
128
|
+
|
|
129
|
+
ZRM uses protobuf for all message serialization. Standard message definitions are in `proto/`.
|
|
130
|
+
|
|
131
|
+
### Generating Python Code
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Generate Python code from proto files
|
|
135
|
+
./protoc-33.0-linux-x86_64/bin/protoc \
|
|
136
|
+
--pyi_out=src/zrm/generated_protos \
|
|
137
|
+
--python_out=src/zrm/generated_protos \
|
|
138
|
+
-Iproto \
|
|
139
|
+
$(fd --extension proto)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Standard Messages
|
|
143
|
+
|
|
144
|
+
- **geometry.proto**: Point, Vector3, Quaternion, Pose, Pose2D, Twist, PoseStamped
|
|
145
|
+
- **services.proto**: Trigger
|
|
146
|
+
|
|
147
|
+
## Architecture
|
|
148
|
+
|
|
149
|
+
### Node-Based Design
|
|
150
|
+
- **Node as factory**: All Publishers, Subscribers, Services, and Clients are created through `Node` factory methods
|
|
151
|
+
- **Context management**: Global `Context` holds the Zenoh session and domain configuration
|
|
152
|
+
- **Lazy initialization**: Global context created on first node instantiation
|
|
153
|
+
|
|
154
|
+
### Session Management
|
|
155
|
+
- **Single session**: One Zenoh session shared across all nodes and components
|
|
156
|
+
- **Thread-safe**: Context creation uses double-checked locking
|
|
157
|
+
|
|
158
|
+
### Serialization
|
|
159
|
+
- **Protobuf-based**: All messages serialized with `msg.SerializeToString()`
|
|
160
|
+
- **Type enforcement**: Runtime validation via `isinstance()`
|
|
161
|
+
|
|
162
|
+
## CLI Tools
|
|
163
|
+
|
|
164
|
+
ZRM provides command-line tools for inspecting the network:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# List all nodes in the network
|
|
168
|
+
uv run zrm-nodes
|
|
169
|
+
|
|
170
|
+
# List all topics and their publishers/subscribers
|
|
171
|
+
uv run zrm-topics
|
|
172
|
+
|
|
173
|
+
# List all services in the network
|
|
174
|
+
uv run zrm-services
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Examples
|
|
178
|
+
|
|
179
|
+
See `examples/` directory for complete working examples:
|
|
180
|
+
- `talker.py` / `listener.py`: Basic publisher/subscriber pattern
|
|
181
|
+
- `service_server.py` / `service_client.py`: Service request/response pattern
|
|
182
|
+
- Graph discovery and introspection
|
|
183
|
+
|
|
184
|
+
## Acknowledgements
|
|
185
|
+
|
|
186
|
+
- The Graph class is inspired by [ros-z](https://github.com/ZettaScaleLabs/ros-z)
|
|
187
|
+
- Built on [Eclipse Zenoh](https://zenoh.io/) for efficient pub/sub and query/reply patterns
|
zrm-0.0.1/README.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# ZRM (Zenoh ROS-like Middleware)
|
|
2
|
+
|
|
3
|
+
A minimal, single-file communication middleware built on Zenoh, providing a clean and simple API inspired by ROS2 patterns.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Minimalist**: Single-file implementation
|
|
8
|
+
- **Type-safe**: Protobuf-based serialization with runtime type checking
|
|
9
|
+
- **Ergonomic**: Pythonic API with sensible defaults
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Install dependencies using uv
|
|
15
|
+
uv sync
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
### Publisher/Subscriber
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from zrm import Node
|
|
24
|
+
from zrm.generated_protos import geometry_pb2
|
|
25
|
+
|
|
26
|
+
# Create a node
|
|
27
|
+
node = Node("my_node")
|
|
28
|
+
|
|
29
|
+
# Create publisher and subscriber via node factory methods
|
|
30
|
+
pub = node.create_publisher("robot/pose", geometry_pb2.Pose2D)
|
|
31
|
+
sub = node.create_subscriber("robot/pose", geometry_pb2.Pose2D)
|
|
32
|
+
|
|
33
|
+
# Publish a message
|
|
34
|
+
pose = geometry_pb2.Pose2D(x=1.0, y=2.0, theta=0.5)
|
|
35
|
+
pub.publish(pose)
|
|
36
|
+
|
|
37
|
+
# Get latest message
|
|
38
|
+
current_pose = sub.latest()
|
|
39
|
+
if current_pose:
|
|
40
|
+
print(f"Position: x={current_pose.x}, y={current_pose.y}")
|
|
41
|
+
|
|
42
|
+
# Clean up
|
|
43
|
+
pub.close()
|
|
44
|
+
sub.close()
|
|
45
|
+
node.close()
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Subscriber with Callback
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
def handle_pose(pose):
|
|
52
|
+
print(f"Received: x={pose.x}, y={pose.y}")
|
|
53
|
+
|
|
54
|
+
node = Node("listener_node")
|
|
55
|
+
sub = node.create_subscriber(
|
|
56
|
+
topic="robot/pose",
|
|
57
|
+
msg_type=geometry_pb2.Pose2D,
|
|
58
|
+
callback=handle_pose,
|
|
59
|
+
)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Service Server/Client
|
|
63
|
+
|
|
64
|
+
Services use namespaced Request/Response messages for better organization:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from zrm import Node
|
|
68
|
+
from zrm.generated_protos import example_services_pb2
|
|
69
|
+
|
|
70
|
+
# Define service handler
|
|
71
|
+
def add_callback(req):
|
|
72
|
+
return example_services_pb2.AddTwoInts.Response(sum=req.a + req.b)
|
|
73
|
+
|
|
74
|
+
# Create node
|
|
75
|
+
node = Node("service_node")
|
|
76
|
+
|
|
77
|
+
# Create service server via node factory method
|
|
78
|
+
server = node.create_service(
|
|
79
|
+
service="add_two_ints",
|
|
80
|
+
service_type=example_services_pb2.AddTwoInts,
|
|
81
|
+
callback=add_callback,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Create service client via node factory method
|
|
85
|
+
client = node.create_client(
|
|
86
|
+
service="add_two_ints",
|
|
87
|
+
service_type=example_services_pb2.AddTwoInts,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Call service
|
|
91
|
+
request = example_services_pb2.AddTwoInts.Request(a=5, b=3)
|
|
92
|
+
response = client.call(request)
|
|
93
|
+
print(f"Sum: {response.sum}") # Output: 8
|
|
94
|
+
|
|
95
|
+
# Clean up
|
|
96
|
+
client.close()
|
|
97
|
+
server.close()
|
|
98
|
+
node.close()
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Service Definition Pattern:**
|
|
102
|
+
```protobuf
|
|
103
|
+
// Services must have nested Request and Response messages
|
|
104
|
+
message AddTwoInts {
|
|
105
|
+
message Request {
|
|
106
|
+
int32 a = 1;
|
|
107
|
+
int32 b = 2;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
message Response {
|
|
111
|
+
int32 sum = 1;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Protobuf Workflow
|
|
117
|
+
|
|
118
|
+
ZRM uses protobuf for all message serialization. Standard message definitions are in `proto/`.
|
|
119
|
+
|
|
120
|
+
### Generating Python Code
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Generate Python code from proto files
|
|
124
|
+
./protoc-33.0-linux-x86_64/bin/protoc \
|
|
125
|
+
--pyi_out=src/zrm/generated_protos \
|
|
126
|
+
--python_out=src/zrm/generated_protos \
|
|
127
|
+
-Iproto \
|
|
128
|
+
$(fd --extension proto)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Standard Messages
|
|
132
|
+
|
|
133
|
+
- **geometry.proto**: Point, Vector3, Quaternion, Pose, Pose2D, Twist, PoseStamped
|
|
134
|
+
- **services.proto**: Trigger
|
|
135
|
+
|
|
136
|
+
## Architecture
|
|
137
|
+
|
|
138
|
+
### Node-Based Design
|
|
139
|
+
- **Node as factory**: All Publishers, Subscribers, Services, and Clients are created through `Node` factory methods
|
|
140
|
+
- **Context management**: Global `Context` holds the Zenoh session and domain configuration
|
|
141
|
+
- **Lazy initialization**: Global context created on first node instantiation
|
|
142
|
+
|
|
143
|
+
### Session Management
|
|
144
|
+
- **Single session**: One Zenoh session shared across all nodes and components
|
|
145
|
+
- **Thread-safe**: Context creation uses double-checked locking
|
|
146
|
+
|
|
147
|
+
### Serialization
|
|
148
|
+
- **Protobuf-based**: All messages serialized with `msg.SerializeToString()`
|
|
149
|
+
- **Type enforcement**: Runtime validation via `isinstance()`
|
|
150
|
+
|
|
151
|
+
## CLI Tools
|
|
152
|
+
|
|
153
|
+
ZRM provides command-line tools for inspecting the network:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# List all nodes in the network
|
|
157
|
+
uv run zrm-nodes
|
|
158
|
+
|
|
159
|
+
# List all topics and their publishers/subscribers
|
|
160
|
+
uv run zrm-topics
|
|
161
|
+
|
|
162
|
+
# List all services in the network
|
|
163
|
+
uv run zrm-services
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Examples
|
|
167
|
+
|
|
168
|
+
See `examples/` directory for complete working examples:
|
|
169
|
+
- `talker.py` / `listener.py`: Basic publisher/subscriber pattern
|
|
170
|
+
- `service_server.py` / `service_client.py`: Service request/response pattern
|
|
171
|
+
- Graph discovery and introspection
|
|
172
|
+
|
|
173
|
+
## Acknowledgements
|
|
174
|
+
|
|
175
|
+
- The Graph class is inspired by [ros-z](https://github.com/ZettaScaleLabs/ros-z)
|
|
176
|
+
- Built on [Eclipse Zenoh](https://zenoh.io/) for efficient pub/sub and query/reply patterns
|
zrm-0.0.1/pyproject.toml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "zrm"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Add your description here"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{ name = "JafarAbdi", email = "jafar.uruc@gmail.com" }]
|
|
7
|
+
requires-python = ">=3.11"
|
|
8
|
+
dependencies = ["eclipse-zenoh>=1.6.2", "protobuf>=6.33.0"]
|
|
9
|
+
|
|
10
|
+
[dependency-groups]
|
|
11
|
+
dev = ["pre-commit>=4.2.0", "pytest>=8.4.1"]
|
|
12
|
+
|
|
13
|
+
[project.scripts]
|
|
14
|
+
zrm-nodes = "zrm.cli.node:main"
|
|
15
|
+
zrm-topics = "zrm.cli.topic:main"
|
|
16
|
+
zrm-services = "zrm.cli.service:main"
|
|
17
|
+
|
|
18
|
+
[build-system]
|
|
19
|
+
requires = ["uv_build>=0.8.14,<0.9.0"]
|
|
20
|
+
build-backend = "uv_build"
|