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-twin description: >- Use the UFACTORY xArm 6 digital twin from the xArm 6 wiki page: per-link GLBs (link_base..link6) plus kinematics.json in millimetres, Z-up, composed into a joint chain you can pose from live joint angles; forward kinematics in Python; mounting the twin on a plate or table in a larger scene; matching the twin to the real arm's SDK readings. Trigger words: xarm twin, xarm 6 glb, xarm digital twin, xarm 3d model, pose the xarm model, xarm forward kinematics, xarm fk, xarm kinematics.json, xarm urdf to glb, xarm in babylon, xarm in three.js, mount the xarm model, xarm base frame.
Parent page: UFactory xArm 6 Robot Arm
The xArm 6 digital twin
Files (page folder models/)
| File | Use |
|---|---|
link_base.glb, link1.glb … link6.glb |
one mesh per URDF link, in that link's own frame |
xarm6_home.glb |
whole arm at the zero pose, static preview only |
kinematics.json |
chain, joint origins, axes, limits, home pose, TCP |
LICENSE-xarm_ros2.txt |
BSD-3-Clause, keep it next to the meshes when you redistribute |
Conventions
- Millimetres, +Z up. Vertex coordinates are the URDF metres × 1000.
links[]is ordered base to tip. Each non-base link has ajointwithorigin_xyz_mm,origin_rpy(rad, URDF fixed-axis: R = Rz(yaw)·Ry(pitch)·Rx(roll)),axis(always [0, 0, 1]) andlimit_deg.- Child world pose = parent world × T(origin_xyz_mm) × R(origin_rpy) × Rz(q).
- Base frame origin: centre of the bottom face of the base. +X is where the arm reaches at zero; the cable connectors face −X. J2's axis is 267 mm up.
- TCP =
link6origin = flange face, +Z out of the flange. Add the tool offset there. - Zero pose: flange at (207, 0, 112) mm, pointing down. This equals the SDK's
get_position()at joints all 0, so SDK joint angles drive the twin directly (deg → rad).
Forward kinematics (Python)
fk.py in this folder:
import json
from fk import fk
kin = json.load(open("models/kinematics.json"))
poses = fk(kin, [30, 10, -40, 0, 60, 0]) # degrees in, {link: 4x4 mm} out
print(poses["link6"][:3, 3])
Self-check: fk(kin, [0]*6)["link6"] translation must be (207, 0, 112). If it is not, the
RPY order or the axis is wrong.
Building the chain in a 3D scene
For each link in order:
originnode, child of the parent link node: position =origin_xyz_mm, rotation = Rz(yaw)·Ry(pitch)·Rx(roll) as a quaternion.jointnode, child oforigin: rotation about local Z = q.- Load the link GLB under the
jointnode with no extra transform.
glTF loaders (Babylon.js, three.js) wrap a file in a root node that converts glTF +Y-up into their scene space. In a Z-up scene, cancel that root transform (or re-parent the mesh children and drop the root), otherwise every link is rotated 90° about X.
To animate from the real arm: poll get_servo_angle() (or read the 30003 report at 100 Hz)
and set each joint node's Z rotation.
Mounting the twin
- The base's bottom face is z = 0 in the arm frame. On a plate of thickness t, place the arm root at (plate centre x, plate centre y, plate top z) = (…, …, t + plate base z).
- Yaw the arm root so its +X points where the real arm reaches at zero. The cable side (−X) usually faces the back of the cell.
- Bolt pattern for the plate: 5 × M5 on a Ø110 circle at 0°, ±60°, ±120° from +X, none at 180°, plus Ø5 locating holes at (−10, ±55). See the page's "Base mounting" section.
Limits for animation and planning
Use limit_deg from kinematics.json (the ROS 2 model ranges). Clamp or reject targets
outside them; the real controller will refuse them anyway.
Attribution
Meshes and kinematics: UFACTORY xarm_ros2, xarm_description (xarm6_1305 visual meshes,
xarm6_default_kinematics.yaml), commit 62936f7, BSD-3-Clause, Copyright (c) 2018 UFACTORY Inc.
---
name: xarm-twin
description: >-
Use the UFACTORY xArm 6 digital twin from the xArm 6 wiki page: per-link GLBs
(link_base..link6) plus kinematics.json in millimetres, Z-up, composed into a joint
chain you can pose from live joint angles; forward kinematics in Python; mounting the
twin on a plate or table in a larger scene; matching the twin to the real arm's SDK
readings. Trigger words: xarm twin, xarm 6 glb, xarm digital twin, xarm 3d model, pose
the xarm model, xarm forward kinematics, xarm fk, xarm kinematics.json, xarm urdf to glb,
xarm in babylon, xarm in three.js, mount the xarm model, xarm base frame.
---
Parent page: **UFactory xArm 6 Robot Arm**
# The xArm 6 digital twin
## Files (page folder `models/`)
| File | Use |
|---|---|
| `link_base.glb`, `link1.glb` … `link6.glb` | one mesh per URDF link, in that link's own frame |
| `xarm6_home.glb` | whole arm at the zero pose, static preview only |
| `kinematics.json` | chain, joint origins, axes, limits, home pose, TCP |
| `LICENSE-xarm_ros2.txt` | BSD-3-Clause, keep it next to the meshes when you redistribute |
## Conventions
- Millimetres, +Z up. Vertex coordinates are the URDF metres × 1000.
- `links[]` is ordered base to tip. Each non-base link has a `joint` with `origin_xyz_mm`,
`origin_rpy` (rad, URDF fixed-axis: R = Rz(yaw)·Ry(pitch)·Rx(roll)), `axis` (always
[0, 0, 1]) and `limit_deg`.
- Child world pose = parent world × T(origin_xyz_mm) × R(origin_rpy) × Rz(q).
- Base frame origin: centre of the bottom face of the base. +X is where the arm reaches at
zero; the cable connectors face −X. J2's axis is 267 mm up.
- TCP = `link6` origin = flange face, +Z out of the flange. Add the tool offset there.
- Zero pose: flange at (207, 0, 112) mm, pointing down. This equals the SDK's
`get_position()` at joints all 0, so SDK joint angles drive the twin directly (deg → rad).
## Forward kinematics (Python)
`fk.py` in this folder:
```python
import json
from fk import fk
kin = json.load(open("models/kinematics.json"))
poses = fk(kin, [30, 10, -40, 0, 60, 0]) # degrees in, {link: 4x4 mm} out
print(poses["link6"][:3, 3])
```
Self-check: `fk(kin, [0]*6)["link6"]` translation must be (207, 0, 112). If it is not, the
RPY order or the axis is wrong.
## Building the chain in a 3D scene
For each link in order:
1. `origin` node, child of the parent link node: position = `origin_xyz_mm`, rotation =
Rz(yaw)·Ry(pitch)·Rx(roll) as a quaternion.
2. `joint` node, child of `origin`: rotation about local Z = q.
3. Load the link GLB under the `joint` node with no extra transform.
glTF loaders (Babylon.js, three.js) wrap a file in a root node that converts glTF +Y-up into
their scene space. In a Z-up scene, cancel that root transform (or re-parent the mesh
children and drop the root), otherwise every link is rotated 90° about X.
To animate from the real arm: poll `get_servo_angle()` (or read the 30003 report at 100 Hz)
and set each `joint` node's Z rotation.
## Mounting the twin
- The base's bottom face is z = 0 in the arm frame. On a plate of thickness t, place the arm
root at (plate centre x, plate centre y, plate top z) = (…, …, t + plate base z).
- Yaw the arm root so its +X points where the real arm reaches at zero. The cable side
(−X) usually faces the back of the cell.
- Bolt pattern for the plate: 5 × M5 on a Ø110 circle at 0°, ±60°, ±120° from +X, none at 180°,
plus Ø5 locating holes at (−10, ±55). See the page's "Base mounting" section.
## Limits for animation and planning
Use `limit_deg` from `kinematics.json` (the ROS 2 model ranges). Clamp or reject targets
outside them; the real controller will refuse them anyway.
## Attribution
Meshes and kinematics: UFACTORY `xarm_ros2`, `xarm_description` (`xarm6_1305` visual meshes,
`xarm6_default_kinematics.yaml`), commit 62936f7, BSD-3-Clause, Copyright (c) 2018 UFACTORY Inc.