Skip to content

stenwire/jointspace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Jointspace

A robotic arm kinematics simulator. An interactive, web-based tool for forward and inverse kinematics of serial robotic arms, built to make the underlying math tangible. Move a joint or drag a target and watch the Denavit-Hartenberg transforms, the Jacobian, and the IK solver update live, in 2D and 3D.

The name says what it does: it lives in the space between joint space (the angles you control) and task space (where the tool ends up). Forward kinematics maps one way, inverse the other.

Built for the person teaching themselves robotics who found FK/IK painfully abstract, and didn't want to reach for MATLAB or ROS/Gazebo just to see it. Every number on screen is computed by small, readable Python you can open and tweak. Established robotics libraries are used only to test that math, never at runtime.

UI

2D planar side view, with the editable DH table, live Jacobian + singularity measures, and the end-effector pose:

Jointspace 2D view

3D orbitable spatial arm (Z-up, RGB coordinate frames), joint controls, the trajectory planner, and the live per-joint transforms:

Jointspace 3D view

What it does: the four teaching surfaces

  • (a) Build & drive any arm. Edit a full DH-parameter table (link length a, twist α, offset d, angle θ, revolute/prismatic, joint limits) or load a preset. The per-joint homogeneous transforms Aᵢ and their product ⁰Tₙ render live as you move the joints.
  • (b) Inverse kinematics, unboxed. Drag a Cartesian target and the arm follows. Then single-step the solver to watch the error ‖e‖ fall to zero, with the live Jacobian and the joint step Δq on show. Switch between damped least squares, pseudo-inverse, and Jacobian-transpose and feel the difference near a singularity.
  • (c) Workspace & singularities. Sample the reachable workspace as a point cloud, and drive the arm into a singularity, where it turns red and the manipulability, condition number, and singular values show the lost degree of freedom.
  • (d) Trajectory playback. Capture waypoints, plan a path in joint space (smooth joints, curved tool path) or Cartesian space (straight tool line, may hit singularities), and play it back: the pick-and-place workflow.

Switch between a 2D planar view (SVG, annotation-rich) and a 3D view (Three.js, orbitable) at any time. Coordinate frames follow the robotics convention: X = red, Y = green, Z = blue, Z-up.

Architecture

Browser (React + Three.js / SVG)
   |  WebSocket   real-time: joint drags, IK target, solver steps, trajectory
   |  REST        one-shot: presets, DH validate, batch FK/IK/Jacobian, workspace, trajectory plan
   v
FastAPI  ->  kinematics engine (numpy)   <-  THE PRODUCT: clean, readable math
  • Python is the single source of truth for all kinematics. The frontend never re-derives a pose, matrix, or Jacobian; it renders what the backend computed.
  • Real-time interaction rides a WebSocket: outbound input is coalesced to one message per animation frame (tagged with a monotonic seq), and stale frames are dropped on the way in. That is what lets a Python backend feel instant.
  • Convention: standard (distal) DH, Aᵢ = Rz(θ)·Tz(d)·Tx(a)·Rx(α), stated in the code and in the UI, because a silent convention mismatch is the #1 source of "my answer disagrees with the textbook" bugs.

Getting started

Prerequisites: uv (Python 3.13, fetched automatically) and Node.js 20.19 or newer.

# 1. Backend deps (creates .venv with Python 3.13)
uv sync

# 2. Frontend deps
cd frontend && npm install && cd ..

# 3. Run both together (FastAPI :8010 + Vite :5173)
./dev.sh

Then open http://localhost:5173. (The backend runs on port 8010 to avoid a clash with other local services; the Vite dev server proxies /api and /ws to it.)

To run the pieces separately:

uv run uvicorn app.main:app --reload --app-dir backend --port 8010   # backend
cd frontend && npm run dev                                            # frontend

Testing

# Backend math + API (pytest): FK/IK/Jacobian, singularity, workspace, trajectory, WS/REST
uv run pytest

# Oracle validation against the modern_robotics library (independent PoE formulation)
uv sync --group oracle && uv run pytest backend/tests/test_oracle_modern_robotics.py

# Frontend unit tests (vitest): rAF coalescing, drop-stale, formatting
cd frontend && npm test

# End-to-end (Playwright): drives all four teaching surfaces against the real backend
cd frontend && npm run e2e

The backend math is anchored to closed-form ground truth (2-link planar FK & IK), property-based FK/IK round-trips, an analytic-vs-finite-difference Jacobian check, and agreement with modern_robotics.

Project structure

backend/app/
  kinematics/          # THE PRODUCT: small, readable numpy
    transforms.py  dh.py  fk.py  jacobian.py  ik.py
    singularity.py  workspace.py  trajectory.py  robot.py  presets.py
  api/                 # thin FastAPI layer over the engine
    rest.py  ws.py  schemas.py  session.py
  main.py
backend/tests/         # unit + oracle + API tests
frontend/src/
  viewport/            # Viewport2D (SVG) + Viewport3D (react-three-fiber)
  panels/              # DH editor, matrices, Jacobian, IK + stepper, workspace, trajectory
  net/                 # ws.ts (real-time) + rest.ts
  store/robotStore.ts  # Zustand state
  types.ts             # wire-format types only, no math
dev.sh                 # run backend + frontend together

Tech stack

Backend: FastAPI · uvicorn · numpy · pydantic · scipy · pytest · ruff Frontend: React 19 · Vite 8 · TypeScript · react-three-fiber + three · zustand · KaTeX · vitest · Playwright

The math, briefly

  • FK (fk.py): multiply each link's DH transform in order; return every intermediate frame.
  • Jacobian (jacobian.py): geometric column formula, cross-checked against a finite-difference version.
  • IK (ik.py): iterative; damped least squares by default (Δq = Jᵀ(JJᵀ+λ²I)⁻¹e), exposed as a generator that yields every iteration so the UI can step through it. Position-only by default (many arms cannot reach arbitrary orientations, surfaced rather than hidden).
  • Singularity (singularity.py): manipulability, condition number, and singular values of the effective position Jacobian.
  • Workspace (workspace.py): vectorized Monte-Carlo sampling of the reachable set.
  • Trajectory (trajectory.py): joint-space and Cartesian-space interpolation with linear / cubic / quintic blend profiles.

About

Interactive web-based forward and inverse kinematics simulator for serial robotic arms, with a readable Python engine and a React + Three.js UI.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages