Projects / Kinematics Library
Python Robotics Tools Active · WIP

Kinematics Library

A serial-chain kinematics library designed to close the gap between the math on the whiteboard and code that actually runs on a robot — with symbolic expressions, batched numerics, and a live 3D visualizer built in from the start.

View on GitHub

The problem with existing tools

Most kinematics libraries are either too academic (dense notation, no interactivity) or too hardware-specific (tied to ROS, a particular robot brand, or a GUI that hides what's actually happening). When you're learning, neither helps.

This library starts from first principles — SE(3) rigid-body math, Rodrigues rotation, homogeneous transforms — and builds up to a usable API without burying the math. The goal is that reading the source code teaches you something, not just using it.


How the library is structured

The library is split into a math core and a visualization layer, kept deliberately separate so you can use the FK engine without pulling in Plotly or Dash.

User code R() / P() SerialChain fk_points() np.ndarray
Symbolic SerialChain fk_ee_symbolic() sp.Matrix (3×1)
SerialChain jacobian_symbolic() sp.Matrix (3×dof)
Workspace SerialChain fk_ee_batch() (N, 3) positions
Visualizer SerialChain preview(chain) Dash app on localhost

What's in the codebase

core.py

The math engine. SerialChain, joint definitions (R / P), SE(3) helpers (Rodrigues, skew-symmetric, homogeneous transforms), numeric FK, batched FK, symbolic FK, and the geometric Jacobian — all cached and design-change aware.

preview_scene.py

Computes all 3D geometry for the current joint configuration — joint cylinder positions, rotation-axis arrows, arc sweep indicators, and home-pose ghost. Decoupled from rendering so it can be tested without Plotly.

preview_workspace.py

Batched workspace sampler: draws random joint configs, runs vectorized FK over all samples at once, and optionally wraps the result in a SciPy convex hull to produce a solid mesh.

preview_plotly_geom.py

Low-level geometry helpers: cylinder mesh (verts + triangle indices), orthonormal frame construction from an arbitrary axis, and cheap 3D arrowheads as line segments.

preview_dash_controls.py

Reusable Dash UI components: slider + numeric-input pairs with live value pills, workspace toggle checkbox, and the overall two-panel layout (3D viewport left, controls right).

preview_plotly_modular.py

Top-level preview(chain) entry point. Builds the Dash app, registers reactive callbacks for slider sync and graph updates via Plotly Patch, and launches the local server.


Technical highlights

SE(3) via Rodrigues
Rotation matrices built from axis-angle using the Rodrigues formula. No quaternions, no gimbal ambiguity — the math maps directly to the textbook derivation.
Design compilation
Home-pose transforms are compiled once per unique design parameter set and cached. FK at runtime only pays for joint motion — not re-evaluating link geometry.
Symbolic layer
SymPy expressions for EE position and Jacobian are built once and cached. Useful for closed-form IK derivation, singularity checking, or printing the math cleanly.
Batched FK (einsum)
fk_ee_batch() propagates N configurations simultaneously using np.einsum — workspace sampling over 40,000 configs runs in under a second.
Plotly Patch updates
The live visualizer uses Plotly's Patch for partial figure updates — only changed traces are re-sent, keeping the 3D view smooth while dragging sliders.
Optional SciPy hull
If SciPy is installed, the workspace is rendered as a solid convex-hull mesh. Without it the library falls back to a point cloud — no hard dependency.

Code examples

Defining a 3-DOF arm and running forward kinematics:

example_3dof.py
import sympy as sp
from robot_sketch import SerialChain, R, P, Point

# Symbolic link lengths — fix them later
L1, L2, L3 = sp.symbols("L1 L2 L3", positive=True)

chain = SerialChain(
    joints=[
        R("z", at=(0, 0, 0), q="q1"),          # base rotation
        R("y", at=(L1, 0, 0), q="q2"),         # shoulder
        P("z", at=(L2, 0, 0), q="q3"),         # extending prismatic
    ],
    ee=(L3, 0, 0),
)

design = {L1: 0.4, L2: 0.3, L3: 0.2}
q      = {"q1": 0.5, "q2": -0.3, "q3": 0.1}

# All joint origins + EE as (N, 3) array
pts = chain.fk_points(design, q, include_ee=True)
print(pts)  # shape: (4, 3)

Getting the symbolic Jacobian — useful for IK or singularity analysis:

example_jacobian.py
# Symbolic EE position (cached after first call)
p_ee = chain.fk_ee_symbolic()
print(p_ee)  # SymPy Matrix (3×1) in terms of q1, q2, q3, L1, L2, L3

# Geometric Jacobian — ∂p_ee / ∂q
J = chain.jacobian_symbolic()
print(J)     # SymPy Matrix (3×3)

# Substitute numbers to evaluate at a config
J_num = J.subs({**design, **{sp.Symbol("q1"): 0.5,
                              sp.Symbol("q2"): -0.3,
                              sp.Symbol("q3"): 0.1}})

Sampling the reachable workspace and launching the interactive visualizer:

example_visualize.py
from robot_sketch.preview_plotly_modular import preview

# Opens a Dash app at localhost:8050
preview(
    chain,
    init_design=design,
    revolute_range_deg=(-180, 180),
    prismatic_range=(-0.5, 0.5),
    reachable_cloud_samples=40_000,   # batched FK, <1 s
    show_reachable_cloud=True,
)

What's built, what's next

SerialChain core — numeric FK, design compilation, SE(3) transforms
Done
Batched FK — vectorized einsum over N configurations simultaneously
Done
Symbolic layer — SymPy EE position expression and geometric Jacobian
Done
3D visualizer — Dash + Plotly app with live sliders, joint geometry, and workspace cloud
In progress
Numerical IK — Jacobian pseudoinverse iteration with damping and singularity handling
Planned
Velocity & force Jacobians — angular velocity components for full spatial Jacobian
Planned
Dynamics (Newton-Euler) — torque computation from inertia parameters
Planned
URDF import — parse standard robot description files into SerialChain
Planned
Status Actively developed — IK and dynamics are next on the list.