The manifest is the only contract a consumer has, since no source package is shared between node repositories, and dora validate checks a dataflow against it without running the node — so CI needs no robot. request and response are deliberately untyped. They carry request_id, and dora defines that as the marker for a pattern-correlated port where several Arrow schemas legitimately flow, one per service; the runtime skips type checks on those messages, so annotating them would claim a contract neither side keeps. examples/ carries its own manifest because dora resolves a node's manifest by walking up from its path, and a manifest applies only when <manifest dir>/<entrypoint> names the same file as the dataflow's path. Without it the example caller would be matched against the arm node's manifest and strict validation would fail on the entrypoint mismatch.
38 lines
1.0 KiB
YAML
38 lines
1.0 KiB
YAML
# The repository's own example: builds and runs the node from this checkout, so
|
|
# `dora validate` picks up the typed contract in dora-node.yml next to it.
|
|
# A consumer wires the node from a tag instead — see README.md.
|
|
#
|
|
# Run it with `--uv` so every Python node gets its own managed environment.
|
|
#
|
|
# `examples/caller.py` shows the whole convention: a non-blocking motion
|
|
# answered at once, its progress followed on `motion_state`, and a second motion
|
|
# preempting the first.
|
|
strict_types: true
|
|
|
|
nodes:
|
|
- id: ulite6
|
|
path: dora-ulite6
|
|
build: pip install .
|
|
inputs:
|
|
tick: dora/timer/millis/100
|
|
request: caller/request
|
|
outputs:
|
|
- response
|
|
- motion_state
|
|
- joint_pose
|
|
- tcp_pose
|
|
- robot_state
|
|
env:
|
|
ROBOT_IP: "192.168.1.192"
|
|
TOOL_TYPE: "vacuum"
|
|
INIT_MODE: "none"
|
|
|
|
- id: caller
|
|
path: examples/caller.py
|
|
inputs:
|
|
tick: dora/timer/millis/500
|
|
response: ulite6/response
|
|
motion_state: ulite6/motion_state
|
|
outputs:
|
|
- request
|