# Node manifest: the typed contract a consumer wires against. # # No source package is shared between node repositories, so this file and its # type URNs are the only contract a consumer has. `dora validate` checks a # dataflow against it without running the node, so CI needs no robot. # # The `request` and `response` ports are deliberately **untyped**. They carry # dora's pattern-correlation metadata (`request_id`), and dora defines that as # the marker for a port where several Arrow schemas legitimately flow — one per # service — distinguished by metadata rather than by a fixed Arrow type. The # runtime skips type checks on such messages, so annotating them would claim a # contract neither side keeps. apiVersion: 1 name: dora-ulite6 namespace: liria description: UFactory Lite6 arm node serving motion and control services, and publishing joint and tool pose categories: [robot, actuator] keywords: [ufactory, lite6, xarm, robot-arm, manipulator, service, vacuum, gripper] runtime: python entrypoint: dora-ulite6 # `dora build --uv` / `dora run --uv` rewrites this to `uv pip install .` and # gives the node its own managed venv under `.dora/python-envs/`, so the # dependencies it sees at runtime are the ones installed here. build: pip install . dora: ">=1.0" inputs: tick: type: std/core/v1/UInt64 required: true description: >- Each tick publishes whatever the arm threads produced since the last one. It does not drive the arm — the tick rate is the publication rate, and TELEMETRY_INTERVAL_MS is how often the arm is actually read. Connect to dora/timer/millis/N. request: required: true description: >- A service request: a one-row struct {service, ...arguments}, with the caller's `request_id` in the metadata. Services: move_to, move_joints, home, home_and_clear, clear, recover, stop, freedrive, grasp, release, get_state. Answered on `response` under the same request_id, exactly once. A motion takes `wait`: true (the default) holds the caller until the arm stops; false answers at once with an acknowledgement and reports the rest on `motion_state`. jog: required: false description: >- A continuous velocity command: a one-row struct {velocity} of 6 numbers [vx, vy, vz, wx, wy, wz] in mm/s and deg/s. A topic rather than a service because it expires on the controller's own TTL and a sender must keep sending; nothing is published in answer. It drives the arm, so the first non-zero one preempts a motion in play and robot_state turns to moving. outputs: response: description: >- The answer to one service request, under its `request_id`: a struct {ok, service, message, ...extras}. get_state adds connected, ready, tool_engaged, freedrive, pose and joints. Exactly one response per request, including for one that was refused or preempted. motion_state: description: >- Where the current motion stands, published on every change: a struct {request_id, service, state, message} with state one of accepted, moving, done, failed, preempted. The request_id is in the fields rather than the metadata because this is the arm's state, not an answer to a request. A new motion preempts the one in play, so there is only ever one. joint_pose: type: std/core/v1/Float32 description: The six joint angles in degrees, base to wrist. tcp_pose: type: std/core/v1/Float32 description: >- The mounted tool's tip as [x, y, z, roll, pitch, yaw] in mm and degrees, in the robot base frame. With TOOL_TYPE none this is the flange itself. robot_state: type: std/core/v1/String description: >- One of connecting, ready, moving, recovering, unavailable. Published on every change, never repeated. env: ROBOT_IP: type: string description: Controller address. Defaults to 192.168.1.192. TOOL_TYPE: type: string description: What is mounted at the flange - none, vacuum or gripper. Defaults to none. TOOL_OFFSET_MM: type: float description: Extra reach past the flange, added to the mounted tool's own. Defaults to 0. DEFAULT_SPEED: type: float description: Cartesian speed in mm/s for a move_to with no speed of its own. Defaults to 30. DEFAULT_JOINT_SPEED: type: float description: Joint speed in deg/s for a move_joints with no speed of its own. Defaults to 20. TELEMETRY_INTERVAL_MS: type: int description: >- How often the reporter reads the arm, and so how often telemetry is produced. Keeps running through a motion. Defaults to 100. RECONNECT_INTERVAL_S: type: float description: How long to wait before trying an unreachable arm again. Defaults to 5. INIT_MODE: type: string description: Where the arm goes on startup - none, home or pose. Defaults to none. example: | - id: ulite6 git: ssh://git@gitea.liria.cl:5001/liria/dora-ulite6.git tag: v0.3.0 build: pip install . path: dora-ulite6 inputs: tick: dora/timer/millis/100 request: planner/request outputs: - response - joint_pose - tcp_pose - robot_state env: ROBOT_IP: "192.168.1.192" TOOL_TYPE: "vacuum"