main
John Lauer UFactory xArm 6: specs, mounting, docs, digital twin, skills 2add613 4d ago

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:

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.