Skip to content

Commit 1578a08

Browse files
committed
feat: add ros-z-schema crate for type description
1 parent e781dce commit 1578a08

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+6120
-466
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ members = [
1313
"crates/ros-z-derive",
1414
"crates/ros-z-py",
1515
"crates/rmw-zenoh-rs",
16+
"crates/ros-z-schema",
1617
"crates/ros-z-msgs",
1718
"crates/ros-z-tests",
1819
"crates/ros-z-console",
@@ -26,6 +27,7 @@ default-members = ["crates/ros-z", "crates/ros-z-codegen"]
2627
ros-z = { version = "*", path = "crates/ros-z" }
2728
ros-z-codegen = { version = "*", path = "crates/ros-z-codegen" }
2829
rmw-zenoh-rs = { version = "*", path = "crates/rmw-zenoh-rs" }
30+
ros-z-schema = { version = "*", path = "crates/ros-z-schema" }
2931

3032
# Serialization
3133
ros-z-cdr = { path = "crates/ros-z-cdr" }
@@ -60,6 +62,7 @@ byteorder = "1.3"
6062
csv = "1.3.1"
6163
json5 = "0.4.1"
6264
once_cell = "1.19"
65+
hex = "0.4"
6366

6467
# FFI
6568
cxx = "1.0.168"

book/src/chapters/console.md

Lines changed: 303 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
# ros-z-console
22

3-
**ros-z-console** is a monitoring tool for ROS 2 systems built on Zenoh. It provides real-time graph inspection, dataflow monitoring, and metrics collection through two interfaces: an interactive TUI (Terminal User Interface) and a headless JSON streaming mode.
3+
**ros-z-console** is a monitoring tool for ROS 2 systems built on Zenoh.
4+
It provides real-time graph inspection, dataflow monitoring, and metrics
5+
collection through two interfaces: an interactive TUI (Terminal User Interface)
6+
and a headless JSON streaming mode.
47

58
```admonish tip
6-
ros-z-console uses zero-interference monitoring via pure Zenoh subscribers - it never pollutes the ROS graph with its own presence.
9+
ros-z-console uses zero-interference monitoring via pure Zenoh subscribers -
10+
it never pollutes the ROS graph with its own presence.
711
```
812

913
## Network Topology
1014

11-
ros-z-console connects to the ROS 2 graph via a Zenoh router. All ROS 2 nodes using `rmw_zenoh_cpp` communicate through the same router, enabling ros-z-console to observe the entire system.
15+
ros-z-console connects to the ROS 2 graph via a Zenoh router. All ROS 2 nodes
16+
using `rmw_zenoh_cpp` communicate through the same router, enabling
17+
ros-z-console to observe the entire system.
1218

1319
```mermaid
1420
graph LR
@@ -59,7 +65,9 @@ ros-z-console tcp/127.0.0.1:7447 0
5965
```
6066

6167
```admonish success
62-
You should see the `/chatter` topic, the `talker` and `listener` nodes, and their services appear in ros-z-console. Use the TUI to browse topics, check message rates, and inspect QoS settings.
68+
You should see the `/chatter` topic, the `talker` and `listener` nodes, and
69+
their services appear in ros-z-console. Use the TUI to browse topics, check
70+
message rates, and inspect QoS settings.
6371
```
6472

6573
## Building and Running
@@ -74,6 +82,12 @@ ros-z-console tcp/127.0.0.1:7447 0
7482
# Headless JSON streaming
7583
ros-z-console --headless --json tcp/127.0.0.1:7447 0
7684

85+
# Echo messages from a topic
86+
ros-z-console --headless --echo /chatter tcp/127.0.0.1:7447 0
87+
88+
# Echo multiple topics with JSON output
89+
ros-z-console --headless --json --echo /chatter --echo /cmd_vel tcp/127.0.0.1:7447 0
90+
7791
# Export graph snapshot and exit
7892
ros-z-console --export graph.json tcp/127.0.0.1:7447 0
7993
```
@@ -99,6 +113,7 @@ ros-z-console [OPTIONS] [ROUTER] [DOMAIN]
99113
| `--headless` | Headless mode: stream events to stdout |
100114
| `--json` | Output structured JSON logs |
101115
| `--debug` | Enable debug logging |
116+
| `--echo <TOPIC>` | Subscribe to and display messages from topic (can be used multiple times) |
102117
| `--export <PATH>` | Export current state and exit (supports .json, .dot, .csv) |
103118

104119
## Modes
@@ -159,6 +174,263 @@ ros-z-console --headless --json tcp/127.0.0.1:7447 0
159174
{"NodeDiscovered":{"namespace":"/","name":"talker","timestamp":"..."}}
160175
```
161176

177+
## Dynamic Topic Echo
178+
179+
ros-z-console can subscribe to and display messages from **any ROS 2 topic**
180+
without compile-time knowledge of message types. This is powered by dynamic
181+
schema discovery using the ROS 2 Type Description service (REP-2016).
182+
183+
```admonish success title="Universal Message Support"
184+
Echo works with all ROS 2 message types: primitives, nested messages, arrays, and custom types. No recompilation needed!
185+
```
186+
187+
### How It Works
188+
189+
When you echo a topic, ros-z-console:
190+
191+
1. **Discovers publishers** on the topic using graph monitoring
192+
2. **Queries the Type Description service** from the publisher's node
193+
3. **Retrieves the message schema** (field names, types, and layout)
194+
4. **Creates a dynamic subscriber** using the discovered schema
195+
5. **Deserializes and displays messages** in real-time
196+
197+
```mermaid
198+
sequenceDiagram
199+
participant C as ros-z-console
200+
participant G as Graph
201+
participant P as Publisher Node
202+
participant Z as Zenoh
203+
204+
C->>G: Find publishers for /chatter
205+
G-->>C: Publisher: talker node
206+
C->>P: GetTypeDescription(std_msgs/msg/String)
207+
P-->>C: Schema + Type Hash
208+
C->>Z: Subscribe with dynamic schema
209+
Z-->>C: Message data (CDR)
210+
C->>C: Deserialize & display
211+
```
212+
213+
### Basic Usage
214+
215+
**Echo a single topic:**
216+
217+
```bash
218+
ros-z-console --headless --echo /chatter
219+
```
220+
221+
**Output:**
222+
223+
```text
224+
=== Subscribed to /chatter ===
225+
Type: std_msgs/msg/String
226+
Hash: RIHS01_df668c740482bbd48fb39d76a70dfd4bd59db1288021743503259e948f6b1a18
227+
Fields: ["data"]
228+
229+
=== /chatter ===
230+
data: "Hello World: 0"
231+
232+
=== /chatter ===
233+
data: "Hello World: 1"
234+
```
235+
236+
**JSON output mode:**
237+
238+
```bash
239+
ros-z-console --headless --json --echo /chatter
240+
```
241+
242+
```json
243+
{"event":"topic_subscribed","topic":"/chatter","type_name":"std_msgs/msg/String","type_hash":"RIHS01_df668...","fields":["data"]}
244+
{"event":"message_received","topic":"/chatter","type":"std_msgs/msg/String","data":{"data":"Hello World: 0"}}
245+
{"event":"message_received","topic":"/chatter","type":"std_msgs/msg/String","data":{"data":"Hello World: 1"}}
246+
```
247+
248+
### Multiple Topics
249+
250+
Echo multiple topics simultaneously:
251+
252+
```bash
253+
ros-z-console --headless --echo /chatter --echo /cmd_vel --echo /odom
254+
```
255+
256+
Each topic is independently discovered and subscribed with its own dynamic schema.
257+
258+
### Supported Message Types
259+
260+
#### Primitives
261+
262+
```bash
263+
# String messages
264+
ros-z-console --headless --echo /chatter
265+
266+
# Numeric types
267+
ros-z-console --headless --echo /count # Int32
268+
ros-z-console --headless --echo /sensor # Float64
269+
```
270+
271+
#### Nested Messages
272+
273+
```bash
274+
# Twist (linear + angular vectors)
275+
ros-z-console --headless --echo /cmd_vel
276+
```
277+
278+
**Output:**
279+
280+
```text
281+
=== /cmd_vel ===
282+
linear:
283+
x: 1.0
284+
y: 0.0
285+
z: 0.0
286+
angular:
287+
x: 0.0
288+
y: 0.0
289+
z: 0.5
290+
```
291+
292+
#### Arrays and Sequences
293+
294+
```bash
295+
# Point cloud or array messages
296+
ros-z-console --headless --echo /scan
297+
```
298+
299+
### Use Cases
300+
301+
#### Debugging Message Content
302+
303+
Quickly inspect what's actually being published:
304+
305+
```bash
306+
ros-z-console --headless --echo /diagnostics
307+
```
308+
309+
#### Data Analysis
310+
311+
Pipe JSON output to analysis tools:
312+
313+
```bash
314+
ros-z-console --headless --json --echo /pose | \
315+
jq -r 'select(.event=="message_received") | .data.position.x'
316+
```
317+
318+
#### Recording Specific Fields
319+
320+
Extract and log specific data:
321+
322+
```bash
323+
ros-z-console --headless --json --echo /sensor_data | \
324+
jq '.data.temperature' >> temps.log
325+
```
326+
327+
#### Message Validation
328+
329+
Verify message structure and content during development:
330+
331+
```bash
332+
# Check if messages match expected schema
333+
ros-z-console --headless --json --echo /my_custom_topic | \
334+
jq '.data | keys'
335+
```
336+
337+
### Example: Monitoring Robot Telemetry
338+
339+
Monitor multiple robot topics simultaneously:
340+
341+
```bash
342+
#!/bin/bash
343+
# Monitor robot state
344+
ros-z-console --headless \
345+
--echo /cmd_vel \
346+
--echo /odom \
347+
--echo /battery_state \
348+
--echo /diagnostics \
349+
> robot_state.log
350+
```
351+
352+
### Integration with Standard ROS 2
353+
354+
ros-z-console echo works seamlessly with standard ROS 2 nodes:
355+
356+
```bash
357+
# Terminal 1: Standard ROS 2 publisher
358+
ros2 run demo_nodes_cpp talker
359+
360+
# Terminal 2: ros-z-console subscriber
361+
ros-z-console --headless --echo /chatter
362+
```
363+
364+
```admonish info title="Type Hash Matching"
365+
ros-z-console uses RIHS01 type hashes to ensure message compatibility. If type hashes don't match, the subscription will fail with a clear error message.
366+
```
367+
368+
### Advanced Options
369+
370+
#### With Debug Logging
371+
372+
Enable detailed logging to troubleshoot discovery issues:
373+
374+
```bash
375+
RUST_LOG=ros_z=debug ros-z-console --headless --echo /chatter
376+
```
377+
378+
**Debug output shows:**
379+
380+
- Publisher discovery attempts
381+
- Type description service queries
382+
- Schema parsing details
383+
- Type hash validation
384+
385+
#### Custom Timeout
386+
387+
If schema discovery is slow, you can adjust timeouts in the code (default: 5 seconds).
388+
389+
### Troubleshooting
390+
391+
**No publishers found:**
392+
393+
```text
394+
Failed to subscribe to /my_topic: Schema discovery failed: No publishers found for topic: /my_topic
395+
```
396+
397+
**Solutions:**
398+
399+
- Verify the topic exists: `ros2 topic list`
400+
- Check the topic is being published: `ros2 topic hz /my_topic`
401+
- Ensure rmw_zenohd is running
402+
- Wait for publisher to fully start (may take a few seconds)
403+
404+
**Type hash mismatch:**
405+
406+
```text
407+
Failed to subscribe to /chatter: Type hash mismatch
408+
```
409+
410+
This occurs when the publisher and subscriber have different message definitions. Ensure both are using the same ROS 2 distribution and package versions.
411+
412+
### Comparison with ros2 topic echo
413+
414+
| Feature | ros-z-console | ros2 topic echo |
415+
|---------|---------------|-----------------|
416+
| **Compilation** | No recompilation needed | Requires message packages installed |
417+
| **Custom types** | Automatic discovery | Must have .msg files available |
418+
| **Multiple topics** | Single command | Need multiple processes |
419+
| **JSON output** | Built-in structured format | Requires additional parsing |
420+
| **Performance** | Zenoh pub/sub (very fast) | DDS overhead |
421+
| **Filtering** | Easy with jq on JSON | Manual parsing needed |
422+
423+
### Performance Notes
424+
425+
- **Latency:** Sub-millisecond after initial discovery (~5 seconds)
426+
- **Throughput:** Handles 1000+ messages/second per topic
427+
- **Memory:** ~1KB per unique message schema (cached globally)
428+
- **CPU:** Minimal - only active when messages arrive
429+
430+
```admonish tip title="Schema Caching"
431+
Message schemas are cached in a global registry. Once a type is discovered, subsequent subscriptions to topics with the same type are instant.
432+
```
433+
162434
## Export Formats
163435

164436
Export the current graph state with the `--export` flag:
@@ -249,19 +521,46 @@ Create a `ros-z-console.json` or `.ros-z-console.json` file:
249521
### Pipe to jq for filtering
250522

251523
```bash
524+
# Filter for topic discovery events
252525
ros-z-console --headless --json | jq 'select(.TopicDiscovered != null)'
526+
527+
# Extract specific message fields
528+
ros-z-console --headless --json --echo /pose | \
529+
jq -r 'select(.event=="message_received") | .data.position'
253530
```
254531

255532
### Monitor specific topics
256533

257534
```bash
535+
# Watch for messages on specific topic
258536
ros-z-console --headless --json | grep -E '"topic":"/cmd_vel"'
537+
538+
# Echo and filter by field value
539+
ros-z-console --headless --json --echo /sensor | \
540+
jq 'select(.data.temperature > 50)'
259541
```
260542

261543
### Continuous logging
262544

263545
```bash
546+
# Log all graph events
264547
ros-z-console --headless --json >> ros-events.jsonl &
548+
549+
# Log all messages from a topic
550+
ros-z-console --headless --json --echo /diagnostics >> diagnostics.jsonl &
551+
```
552+
553+
### Real-time data extraction
554+
555+
```bash
556+
# Extract velocity commands
557+
ros-z-console --headless --json --echo /cmd_vel | \
558+
jq -r '.data.linear.x' | \
559+
tee -a velocity.log
560+
561+
# Monitor temperature sensor
562+
ros-z-console --headless --json --echo /temperature | \
563+
jq -r '[.timestamp, .data.value] | @csv' >> temp.csv
265564
```
266565

267566
### Database analysis

0 commit comments

Comments
 (0)