UFactory xArm 6 Robot Arm
Public Made by Adomby adom
UFACTORY's 6-axis, 5 kg, 700 mm collaborative arm: specs, base bolt pattern, manuals, a per-link GLB digital twin with kinematics, and AI skills for the Python SDK, web UI and ROS 2.
name: xarm-control description: >- Drive a UFACTORY xArm 6 (also xArm 5/7, Lite 6, 850) from Python with the official xArm-Python-SDK: connect by IP, clear errors, enable motion, set mode and state, joint and Cartesian moves, read joints and TCP pose, gripper, collision sensitivity, reduced mode, emergency stop and recovery, plus the safe-motion rules to follow before moving a real arm. Also covers the UFACTORY Studio web UI (port 18333), the control box ports (502, 504, 30001-30003) and the ROS 2 launch files. Trigger words: xarm, xArm 6, ufactory, move the xarm, xarm python sdk, XArmAPI, set_servo_angle, set_position, get_position, get_servo_angle, motion_enable, set_mode, set_state, clean_error, xarm error, xarm gripper, ufactory studio, xarm ip, xarm emergency stop, xarm ros2, xarm moveit.
Parent page: UFactory xArm 6 Robot Arm
Controlling the xArm with the Python SDK
Before you move a real arm (always)
- Confirm with the human that the cell is clear and someone can reach the e-stop, unless the operator has said this arm is cleared for unattended motion.
- Read the current state first (
get_servo_angle,get_position,arm.error_code,arm.warn_code,arm.state,arm.mode). Never assume where the arm is. - First move of a session: low speed (joints ≤ 20 °/s, TCP ≤ 50 mm/s),
wait=True, one move at a time. - Check the target against the joint limits (below) and the workspace before sending it.
- Check the payload and TCP offset match the tool that is actually on the flange
(
arm.tcp_load,arm.tcp_offset); wrong values break collision detection. - After any error, stop and report the code and its meaning before clearing it. Do not loop
clean_error+ retry.
Install and connect
pip install xarm-python-sdk
from xarm.wrapper import XArmAPI
arm = XArmAPI("192.168.1.xxx") # is_radian=False by default: angles in deg, lengths in mm
print(arm.version, arm.state, arm.mode, arm.error_code, arm.warn_code)
The PC must be on the same subnet as the control box. A reachable box answers on TCP 502.
Enable and get ready
arm.clean_warn()
arm.clean_error()
arm.motion_enable(enable=True)
arm.set_mode(0) # position control
arm.set_state(state=0) # ready
Modes: 0 position, 1 servo (streaming set_servo_angle_j / set_servo_cartesian), 2 joint
teach (hand-guiding), 4 joint velocity, 5 Cartesian velocity, 6 joint online planning,
7 Cartesian online planning. Re-send set_state(0) after every set_mode.
States (arm.state): 1 in motion, 2 sleeping, 3 suspended (paused), 4 stopping. set_state(0) starts motion, 3 pauses, 4 stops.
Move
# joints, degrees; speed deg/s, mvacc deg/s^2
code = arm.set_servo_angle(angle=[0, -30, -60, 0, 90, 0], speed=20, mvacc=200, wait=True)
# one joint
code = arm.set_servo_angle(servo_id=1, angle=45, speed=20, wait=True)
# Cartesian line, mm and deg; speed mm/s
code = arm.set_position(x=300, y=0, z=250, roll=180, pitch=0, yaw=0, speed=50, wait=True)
# relative move: 50 mm up
code = arm.set_position(z=50, relative=True, speed=30, wait=True)
Every call returns a code; 0 is success. Anything else: read arm.error_code and look it up
in the SDK's doc/api/xarm_api_code.md.
Read state
code, joints = arm.get_servo_angle() # [j1..j6, (j7)], deg
code, pose = arm.get_position() # [x, y, z, roll, pitch, yaw], mm, deg
code, (pos, vel, eff) = arm.get_joint_states()
At the zero pose (all joints 0) the flange reads about (207, 0, 112, 180, 0, 0).
For a live stream without polling, connect to the report ports: 30003 (100 Hz: joints, pose, joint torques, F/T), 30001 (5 Hz normal), 30002 (5 Hz rich). Formats: Developer Manual 2.1.6.
Gripper (UFACTORY xArm Gripper)
arm.set_gripper_mode(0)
arm.set_gripper_enable(True)
arm.set_gripper_speed(3000)
arm.set_gripper_position(850, wait=True) # open
arm.set_gripper_position(0, wait=True) # close
code, pos = arm.get_gripper_position()
BIO Gripper, vacuum gripper and Robotiq have their own calls (set_bio_gripper_*,
set_vacuum_gripper, robotiq_*).
Stop, errors, recovery
arm.set_state(4): stop now (clears the queue).arm.emergency_stop(): the SDK's software stop (set_state(4)then re-enable). It does not cut power and does not clear errors. The red button on the control box is the real e-stop.- After the hardware e-stop: the human releases the button, then
motion_enable(True),set_mode(0),set_state(0). - After an error (collision, joint limit, overcurrent): report it, let the human decide,
then
clean_error(),clean_warn(),motion_enable(True),set_state(0).
Safety settings
arm.set_collision_sensitivity(3) # 0 off .. 5 most sensitive
arm.set_reduced_mode(True) # apply the reduced-mode speed/range limits
arm.set_tcp_load(weight_kg, [cx, cy, cz])
arm.set_tcp_offset([x, y, z, roll, pitch, yaw])
arm.save_conf() # persist; otherwise lost on reboot
Do not lower collision sensitivity or turn off the safety boundary to get past an error without the operator's OK.
Joint limits (ROS 2 model, use these for planning)
| J1 | J2 | J3 | J4 | J5 | J6 |
|---|---|---|---|---|---|
| ±178.2° | −117.97° to 120° | −178.2° to 11° | ±178.2° | −97° to 178.2° | ±178.2° |
Hardware ranges are wider on J1, J3, J4 and J6 (see the page's spec table).
Web UI and ROS 2
- UFACTORY Studio:
http://<arm-ip>:18333(jog, Blockly, settings, safety). - ROS 2 (
xarm_ros2, branch per distro):ros2 launch xarm_moveit_config xarm6_moveit_realmove.launch.py robot_ip:=<arm-ip>; driver only:ros2 launch xarm_api xarm6_driver.launch.py robot_ip:=<arm-ip>.
Disconnect
arm.disconnect()
---
name: xarm-control
description: >-
Drive a UFACTORY xArm 6 (also xArm 5/7, Lite 6, 850) from Python with the official
xArm-Python-SDK: connect by IP, clear errors, enable motion, set mode and state, joint
and Cartesian moves, read joints and TCP pose, gripper, collision sensitivity, reduced
mode, emergency stop and recovery, plus the safe-motion rules to follow before moving a
real arm. Also covers the UFACTORY Studio web UI (port 18333), the control box ports
(502, 504, 30001-30003) and the ROS 2 launch files. Trigger words: xarm, xArm 6,
ufactory, move the xarm, xarm python sdk, XArmAPI, set_servo_angle, set_position,
get_position, get_servo_angle, motion_enable, set_mode, set_state, clean_error, xarm
error, xarm gripper, ufactory studio, xarm ip, xarm emergency stop, xarm ros2, xarm moveit.
---
Parent page: **UFactory xArm 6 Robot Arm**
# Controlling the xArm with the Python SDK
## Before you move a real arm (always)
1. Confirm with the human that the cell is clear and someone can reach the e-stop, unless the
operator has said this arm is cleared for unattended motion.
2. Read the current state first (`get_servo_angle`, `get_position`, `arm.error_code`,
`arm.warn_code`, `arm.state`, `arm.mode`). Never assume where the arm is.
3. First move of a session: low speed (joints ≤ 20 °/s, TCP ≤ 50 mm/s), `wait=True`, one move at a time.
4. Check the target against the joint limits (below) and the workspace before sending it.
5. Check the payload and TCP offset match the tool that is actually on the flange
(`arm.tcp_load`, `arm.tcp_offset`); wrong values break collision detection.
6. After any error, stop and report the code and its meaning before clearing it. Do not loop
`clean_error` + retry.
## Install and connect
```bash
pip install xarm-python-sdk
```
```python
from xarm.wrapper import XArmAPI
arm = XArmAPI("192.168.1.xxx") # is_radian=False by default: angles in deg, lengths in mm
print(arm.version, arm.state, arm.mode, arm.error_code, arm.warn_code)
```
The PC must be on the same subnet as the control box. A reachable box answers on TCP 502.
## Enable and get ready
```python
arm.clean_warn()
arm.clean_error()
arm.motion_enable(enable=True)
arm.set_mode(0) # position control
arm.set_state(state=0) # ready
```
Modes: 0 position, 1 servo (streaming `set_servo_angle_j` / `set_servo_cartesian`), 2 joint
teach (hand-guiding), 4 joint velocity, 5 Cartesian velocity, 6 joint online planning,
7 Cartesian online planning. Re-send `set_state(0)` after every `set_mode`.
States (`arm.state`): 1 in motion, 2 sleeping, 3 suspended (paused), 4 stopping. `set_state(0)` starts motion, 3 pauses, 4 stops.
## Move
```python
# joints, degrees; speed deg/s, mvacc deg/s^2
code = arm.set_servo_angle(angle=[0, -30, -60, 0, 90, 0], speed=20, mvacc=200, wait=True)
# one joint
code = arm.set_servo_angle(servo_id=1, angle=45, speed=20, wait=True)
# Cartesian line, mm and deg; speed mm/s
code = arm.set_position(x=300, y=0, z=250, roll=180, pitch=0, yaw=0, speed=50, wait=True)
# relative move: 50 mm up
code = arm.set_position(z=50, relative=True, speed=30, wait=True)
```
Every call returns a code; 0 is success. Anything else: read `arm.error_code` and look it up
in the SDK's `doc/api/xarm_api_code.md`.
## Read state
```python
code, joints = arm.get_servo_angle() # [j1..j6, (j7)], deg
code, pose = arm.get_position() # [x, y, z, roll, pitch, yaw], mm, deg
code, (pos, vel, eff) = arm.get_joint_states()
```
At the zero pose (all joints 0) the flange reads about (207, 0, 112, 180, 0, 0).
For a live stream without polling, connect to the report ports: 30003 (100 Hz: joints, pose,
joint torques, F/T), 30001 (5 Hz normal), 30002 (5 Hz rich). Formats: Developer Manual 2.1.6.
## Gripper (UFACTORY xArm Gripper)
```python
arm.set_gripper_mode(0)
arm.set_gripper_enable(True)
arm.set_gripper_speed(3000)
arm.set_gripper_position(850, wait=True) # open
arm.set_gripper_position(0, wait=True) # close
code, pos = arm.get_gripper_position()
```
BIO Gripper, vacuum gripper and Robotiq have their own calls (`set_bio_gripper_*`,
`set_vacuum_gripper`, `robotiq_*`).
## Stop, errors, recovery
- `arm.set_state(4)`: stop now (clears the queue).
- `arm.emergency_stop()`: the SDK's software stop (`set_state(4)` then re-enable). It does not cut
power and does not clear errors. The red button on the control box is the real e-stop.
- After the hardware e-stop: the human releases the button, then `motion_enable(True)`,
`set_mode(0)`, `set_state(0)`.
- After an error (collision, joint limit, overcurrent): report it, let the human decide,
then `clean_error()`, `clean_warn()`, `motion_enable(True)`, `set_state(0)`.
## Safety settings
```python
arm.set_collision_sensitivity(3) # 0 off .. 5 most sensitive
arm.set_reduced_mode(True) # apply the reduced-mode speed/range limits
arm.set_tcp_load(weight_kg, [cx, cy, cz])
arm.set_tcp_offset([x, y, z, roll, pitch, yaw])
arm.save_conf() # persist; otherwise lost on reboot
```
Do not lower collision sensitivity or turn off the safety boundary to get past an error
without the operator's OK.
## Joint limits (ROS 2 model, use these for planning)
| J1 | J2 | J3 | J4 | J5 | J6 |
|---|---|---|---|---|---|
| ±178.2° | −117.97° to 120° | −178.2° to 11° | ±178.2° | −97° to 178.2° | ±178.2° |
Hardware ranges are wider on J1, J3, J4 and J6 (see the page's spec table).
## Web UI and ROS 2
- UFACTORY Studio: `http://<arm-ip>:18333` (jog, Blockly, settings, safety).
- ROS 2 (`xarm_ros2`, branch per distro):
`ros2 launch xarm_moveit_config xarm6_moveit_realmove.launch.py robot_ip:=<arm-ip>`;
driver only: `ros2 launch xarm_api xarm6_driver.launch.py robot_ip:=<arm-ip>`.
## Disconnect
```python
arm.disconnect()
```