Skip to content

Repository files navigation

Robotik-Vorlesung — Python-Port

Python port of the Julia 0.4 notebooks from Grundlagen der Robotik, Universität Leipzig, SS 2016 (github.com/kzahedi/Robotik).

The originals are Julia 0.4.5 and run on no current Julia. They are kept verbatim under julia-2016/ as the porting reference and the source of the regression oracles.

Setup

conda create -y -n robotik python=3.11 numpy scipy matplotlib pytest jupyterlab jupytext ipykernel
conda activate robotik
pip install -e ".[dev,notebooks]"

Ohne conda: pip install -e ".[dev,notebooks]" installiert zusätzlich den Jupyter-Stack (jupyterlab, jupytext, ipykernel).

Starten mit jupyter lab und dann notebooks/ öffnen.

Die *_demo.ipynb-Spielplätze brauchen für Interaktivität das [notebooks]-Extra; ohne es fallen sie auf statische Bilder zurück. Die Vorlesungsnotebooks enthalten „Selbst implementieren“-Rümpfe, deren Prüfzellen sofortiges Feedback geben. Falls Regler nur als Text erscheinen (VBox(...)): JupyterLab neu starten — der Widget-Stack wird beim Serverstart geladen, ein Kernel-Neustart genügt nicht. notebooks/stil_galerie_demo.ipynb zeigt alle sechs gestylten Demo-Diagramme (robotik.demo_plots) einmal nebeneinander an echten Daten.

Vorlesungsnotebooks

Numbering matches the slide decks, so 6_Zustandsschaetzung.pdf sits next to 06_zustandsschaetzung.ipynb.

Notebook Foliensatz Inhalt
02_kinematik 2 Transformationsmatrizen, Vorwärtskinematik, CCD, Jacobi (Spielplatz: 02_kinematik_demo.ipynb)
03_dynamik 3 Pendel, Phasenraum, chaotisches Pendel, Einzugsgebiete (Spielplatz: 03_dynamik_demo.ipynb)
06_zustandsschaetzung 6 Kalman-Filter: Kanonenkugel und GPS-Glättung, plus roboterzentrierte Filter-Animation mit schrumpfender Kovarianzellipse (Spielplatz: 06_zustandsschaetzung_demo.ipynb)
07_radgetriebene_systeme 7 Differentialantrieb, Omni-Antrieb, Holonomie (Spielplatz: 07_radgetriebene_systeme_demo.ipynb)
10_embodied_ai 10 Rekurrentes Neuron, Bifurkation, Hysterese (Spielplatz: 10_embodied_ai_demo.ipynb)

Each notebook has the same shape: Lernziele → Setup → Themen → Aufgaben. Every section runs on its own once Setup has run, so a misbehaving demo can be skipped without restarting the kernel. Solutions are in solutions/ and can be released separately.

Decks 1, 4, 5, 8, 9 and 11 have no notebook yet — they had no code in 2016.

Notebooks and git

.ipynb is the source of truth; jupytext keeps a py:percent mirror for readable diffs. Edit either side, then:

jupytext --sync notebooks/*.ipynb solutions/*.ipynb

Tests

conda activate robotik
python -m pytest -q

The suite needs no Jupyter kernel — notebook cells are executed directly under the Agg backend. 142 tests, roughly 4-5 minutes.

Three values printed by the 2016 notebooks survive as genuine numeric oracles and are pinned:

  • A(π, 1, -π, 2) — the 4×4 Denavit-Hartenberg matrix
  • ForwardKinematics([0,1,3]) — the 4×3 joint-position matrix
  • InverseKinematicsCCD([1,2], [π/2, 0.01, 0.01])[1.5608, 0, 0]

Nothing else was recoverable: 181 of the stored outputs are merely PyPlot.Figure(...) repr strings (167 of those from the omni-wheel notebook's per-frame plotting loop alone). Everything else is covered by invariants — rotation orthogonality, link-length preservation, planarity, reachability, analytic Jacobian vs. central differences, energy conservation, small-angle period, chaotic divergence, Kalman RMSE improvement and covariance positive definiteness, wheel-speed round-tripping, neuron boundedness. These target the failure mode a Julia→Python port is prone to: 1-based → 0-based index slips, which corrupt results silently rather than raising.

Notebook-level tests additionally check top-to-bottom execution, per-section independence, absence of absolute paths, mirror freshness, and that no notebook redefines an algorithm that belongs in robotik/.

Preserved quirks

  • Link lengths differ between notebooks. Forward Kinematics uses (2, 0.75, 0.5), both inverse-kinematics notebooks (2, 1, 0.75). Preserved, not unified — each notebook's stored output only reproduces with its own set. Constants: LENGTHS_FK, LENGTHS_IK.
  • CCD's asymmetric step. The original subtracts the clamped angle min(δ, acos(cθ)) but adds the raw δ. The oracle depends on it.
  • The wheeled y-sign. body_step negates the y component, as in 2016. Removing it mirrors every trajectory.
  • The GPS filter is mis-specified: measurement noise is σ = 1 while R is 1e-4. It still smooths, because only the ratio Q/R matters. Kept as a teaching point — Aufgabe 3 of notebook 06.
  • The cannonball filter's dt mismatch. Its model matrix A scales velocity by dt but the 2016 simulator advances position by the raw velocity each step, with no dt factor — a factor-of-10 inconsistency invisible at the notebook's Q/R and kept verbatim so the numbers match 2016.

Fixed bugs

  • Neuron.ipynb wrote its backward bias sweep to column 100+s instead of length(n)+s, overwriting most of the forward sweep and corrupting the hysteresis figure. It also wrote both sweeps to the same CSV filename. The port returns the two sweeps separately (sweep_bias_hysteresis returns (forward, backward)).

Changes from the originals

  • ODE.jl's ode45scipy.integrate.solve_ivp (RK45); ODE.jl has been unmaintained since roughly 2018.
  • eye(n)np.eye(n); readcsv/writecsv → not needed; squeeze on row slices removed (a Julia 0.4 slice was a 1×N matrix, a numpy slice is a vector).
  • Per-frame savefig("/Users/zahedi/Desktop/...") calls inside plotting loops (up to 1250 in a single loop, in the omni-wheel notebook) and the shell zip step that followed them, replaced by in-notebook plots and plotting.animate_poses().
  • The chaotic-pendulum basin scan defaulted to 1001×1001 = 1,002,001 integrations. basin_of_attraction takes a step parameter, defaulting to a grid that runs in seconds.
  • Globals (gravity, dt, L, g) became function parameters.

About

Robotic Lecture

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages