Quickstart¶
Install¶
pip install ssik # core: library + 13 prebuilt arms + CLI
pip install ssik[urdf] # adds urchin + sympy for ssik build / Manipulator.from_urdf
Python 3.11+. Wheels for Linux x86_64, macOS arm64, macOS x86_64, Windows x86_64.
Use a prebuilt arm¶
from ssik.prebuilt import franka_panda_ik
import numpy as np
T_target = np.eye(4)
T_target[:3, 3] = [0.5, 0.1, 0.3]
sols = franka_panda_ik.solve(T_target) # every analytical IK branch
sols is a list[Solution]. Each Solution carries q (the joint vector), fk_residual (‖FK(q) − T‖_F), and which polish path fired. Empty list = pose is unreachable.
Shipped prebuilts¶
| Module | Arm | Class | base_link | ee_link |
|---|---|---|---|---|
ur5_ik |
Universal Robots UR5 | three-parallel 6R | base_link |
ee_link |
puma560_ik |
KUKA Puma 560 | Pieper 6R (spherical wrist) | base_link |
wrist_3_link |
jaco2_ik |
Kinova JACO 2 | non-Pieper 6R | base_link |
ee_link |
iiwa14_ik |
KUKA iiwa LBR 14 | SRS 7R | base_link |
ee_link |
gen3_ik |
Kinova Gen3 7-DOF | approximate-SRS 7R | base_link |
end_effector_link |
franka_panda_ik |
Franka Panda | anthropomorphic 7R | base_link |
ee_link |
xarm7_ik |
UFactory xArm7 | 7R Pieper-wedge (jointlock → reversed:spherical) |
link_base |
link7 |
xarm6_ik |
UFactory xArm6 | non-Pieper 6R (joint 6 y-offset) | link_base |
link_eef |
z1_ik |
Unitree Z1 | three-parallel 6R (UR-class) | link00 |
link06 |
piper_ik |
AgileX PiPER | non-Pieper 6R (joints 4 & 6 tilted axis) | base_link |
link6 |
rizon4_ik |
Flexiv Rizon 4 | non-SRS 7R | base_link |
flange |
kassow_kr810_ik |
Kassow KR810 | non-SRS 7R | base |
end_effector |
rizon10_ik |
Flexiv Rizon 10 | non-SRS 7R (~1.4 m reach) | base_link |
flange |
fanuc_crx10ial_ik |
FANUC CRX-10iA/L | non-Pieper 6R (non-spherical wrist, 150 mm y-offset) | base_link |
tool0 |
Each prebuilt exposes BASE_LINK, EE_LINK, DOF, T_HOME constants so you can verify the baked geometry matches your robot:
from ssik.prebuilt import franka_panda_ik
print(franka_panda_ik.BASE_LINK, "→", franka_panda_ik.EE_LINK)
# base_link → ee_link
print(franka_panda_ik.T_HOME[:3, 3])
# array([0.088, 0., 0.926]) ← matches Franka's documented home
Trajectory tracking pattern¶
For real-time control / teleop, "give me the IK closest to where I am now":
q_current = np.array([0.0, -0.5, 0.0, 0.7, 0.0, 1.2, 0.0])
# max_solutions=1 + q_seed: visit lock-samples nearest q_current first,
# short-circuit on the first in-limits branch. ~5-6x faster than full sweep.
sols = franka_panda_ik.solve(T_target, max_solutions=1, q_seed=q_current)
q_command = sols[0].q if sols else q_current
When solve() returns an empty list¶
Use explain=True to attribute the failure:
import ssik
arm = ssik.Manipulator.from_urdf("my_arm.urdf", base="base_link", ee="tool0")
sols, diag = arm.solve(T_target, explain=True)
if not sols:
print(diag.summary())
# solver: ikgeo.three_parallel (tier 0)
# dispatch: Three consecutive parallel axes at joints (1, 2, 3) ...
# -> 0 raw candidates: pose appears unreachable
Distinguishes unreachable (zero raw candidates) from all-filtered (out-of-limits or below FK threshold) from capped (truncated by max_solutions).
Build an artifact for your own arm¶
Build time: - <1 s for tier-0 closed-form (UR-class, Pieper, SRS-class 7R) - ~30 s for non-Pieper 6R (Raghavan–Roth symbolic derivation) - 7–20 min for non-SRS 7R (cached HP per lock sample)
Then import my_arm_ik and use exactly like a prebuilt. See Setting up your robot for the full URDF-to-artifact workflow.