Controller for UFactory xArm robotic arms.
Manages two TCP connections to the arm:
- Port 502 — command socket: sends register frames, receives responses, sends the 1-second heartbeat to keep the connection alive.
- Port 30003 — real-time report socket: receives arm-pushed state frames
at ~100 Hz. The socket is opened in
active: truemode so incoming frames arrive as{:tcp, socket, data}messages without polling.
ETS Table
An ETS table (:public, :set) is created on init/1 and shared with
actuators. Per-joint rows are keyed by joint index (1-based integer):
{joint_index, current_position :: float | nil, current_torque :: float | nil,
set_position :: float | nil}The arm-level row is keyed by :arm:
{:arm, state :: non_neg_integer, mode :: non_neg_integer, tcp_pose :: {x, y, z, roll, pitch, yaw} | nil}Actuators write set_position into the ETS table. The 100 Hz control loop
reads all pending positions and batches them into a single cmd_move_joints
frame per tick.
Safety
On arm transition → :armed, the controller runs the full xArm init
sequence: cmd_clean_error → cmd_enable(true) → cmd_set_mode(0) →
cmd_set_state(0). On any transition away from :armed it sends
cmd_enable(false) (hold) or cmd_stop depending on disarm_action.
The disarm/1 safety callback opens a fresh TCP connection so it can
send cmd_stop even if the GenServer process has crashed. It never raises.
Summary
Functions
Opens a fresh TCP connection and sends a stop command.