fdabf7e241d76c5898936dc5dc291d24b74fe19c
Replaces the command/status JSON pair with dora's own service pattern: one request, one response, correlated by the request_id dora puts in the message metadata. Motions take a wait flag, and their lifecycle is published as the arm's state on motion_state rather than as a per-goal stream — the arm is one resource, so a new motion preempts the one in play and a state describes that exactly. motion_state is keyed by request_id and publishes accepted before the control thread reaches the motion. Both exist to close one race: a caller polling a bare moving/idle flag right after its request would read "not moving" and conclude the motion had already finished. Three threads, because the SDK blocks. The control thread carries out one job at a time and may block; the reporter thread only ever reads the report cache, so telemetry keeps flowing through a ten-second move; the stopper thread exists because a stop fits nowhere else — it must not queue behind the motion it aborts, and emergency_stop re-commands the controller for up to three seconds, which is far too long to stop routing a dataflow. The event loop never calls anything that can block, get_state included: that one is allowed there only because it reads the cache. The node is built before the arm threads start, so INIT_MODE cannot move a robot before the process has joined the dataflow, and a restart leaves the arm where it is rather than driving it home unasked. Shutdown halts the arm first — a motion lives in the controller, and dropping the connection does not abort it.
Dora ULite6 Node
Dora node for controlling a UFactory Lite6 robot via REST API, web UI, and publishing joint/TCP state.
Installation
uv pip install -e .
Dataflow
nodes:
- id: ulite6
git: ssh://git@gitea.liria.cl:5001/liria/dora-ulite6.git
git_checkout: v0.1.0
build: uv pip install -e .
path: dora_ulite6/main.py
inputs:
tick: dora/timer/millis/10
outputs: [status, joint_pose, tcp_pose]
inputs: [command]
env:
ROBOT_IP: "192.168.1.192"
DEFAULT_SPEED: "30"
DEFAULT_UNITS: "mm"
API_HOST: "0.0.0.0"
API_PORT: "8080"
VACUUM_ENABLED: "false"
Configuration
| Env Variable | Default | Description |
|---|---|---|
ROBOT_IP |
192.168.1.192 |
Robot IP address |
DEFAULT_SPEED |
30 |
Movement speed (mm/s) |
DEFAULT_UNITS |
mm |
Position units (mm or m) |
API_HOST |
0.0.0.0 |
API server host |
API_PORT |
8080 |
API server port |
VACUUM_ENABLED |
false |
Enable vacuum gripper controls |
TOOL_TYPE |
none |
Mounted tool: none, vacuum, gripper |
TOOL_OFFSET_MM |
0.0 |
Additional Z-offset in mm added on top of the tool preset |
INIT_MODE |
none |
Startup positioning: home, pose, or none |
INIT_X/Y/Z |
300/0/250 |
Initial pose coordinates (mm) |
INIT_ROLL/PITCH/YAW |
180/0/0 |
Initial pose orientation (deg) |
INIT_SPEED |
50 |
Startup movement speed (mm/s) |
Web UI
Access at http://localhost:8080/
- Live status, TCP pose, and joint angles
- Home and Reset buttons
- Move to position form
- Vacuum gripper controls (when enabled)
REST API
Interactive docs at http://localhost:8080/docs
| Method | Endpoint | Description |
|---|---|---|
| GET | / |
Web control interface |
| GET | /api/status |
Robot status (connected, errors) |
| GET | /api/pose |
Current TCP pose |
| GET | /api/joints |
Current joint angles |
| GET | /api/config |
API configuration |
| POST | /api/home |
Go to home position |
| POST | /api/reset |
Clear errors and reset state |
| POST | /api/move_to |
Move to position |
| POST | /api/move_to_pose |
Move to full pose |
| POST | /api/disconnect |
Disconnect from robot |
Vacuum Gripper (when VACUUM_ENABLED=true)
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/vacuum |
Get vacuum status |
| POST | /api/vacuum/on |
Turn vacuum on |
| POST | /api/vacuum/off |
Turn vacuum off |
CLI Examples
# Get pose
curl http://localhost:8080/api/pose
# Go home
curl -X POST http://localhost:8080/api/home
# Move to position
curl -X POST http://localhost:8080/api/move_to \
-H "Content-Type: application/json" \
-d '{"x": 200, "y": 0, "z": 300}'
# Move with orientation
curl -X POST http://localhost:8080/api/move_to_pose \
-H "Content-Type: application/json" \
-d '{"x": 200, "y": 0, "z": 300, "roll": 180, "pitch": 0, "yaw": 0}'
Dora Outputs
status- JSON:{ok, action, message, timestamp_ns}joint_pose- 6 joint angles in degreestcp_pose-[x, y, z, roll, pitch, yaw]in mm/deg — reflects tool tip whenTOOL_TYPEis set
Dora Inputs
command- JSON string:{id, action, payload}id: unique command id (required)action:home,move_to, ormove_to_posepayload: fields for move (x,y,z,roll,pitch,yaw,speed)
status will include command_id for command responses.