# ferrolho/rotary-inverted-pendulum architecture

> Architecture diagram of the GitHub repository ferrolho/rotary-inverted-pendulum, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-28). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/ferrolho/rotary-inverted-pendulum
- Repository: https://github.com/ferrolho/rotary-inverted-pendulum

## Overview

This repository builds a rotary inverted pendulum and its learned controller. The principal workflow measures a physical rig, trains in simulation, fine-tunes and evaluates on real hardware, distills and exports a compact policy, then runs it standalone on an Arduino; the website also demonstrates the deployed policy in browser-based simulation. The README documents the end-to-end stages, while sampled source confirms the simulation environment, SAC trainer, serial client, and demo components. Firmware sketches and several pipeline implementations are outside the supplied tree or excerpts, so their internal wiring is not shown.

Main entry points: [`website/src/demo/index.ts`](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/demo/index.ts) (Demo orchestrator), [`policy/real_env.py`](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/real_env.py) (Real rig interface), [`policy/export_weights.py`](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/export_weights.py) (Weight export), [`policy/train_sac.py`](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/train_sac.py) (SAC training)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_modeling["Rig modeling"]
  node_sysid["System identification<br/>[sysid_core.py]"]
  node_sysid_wizard["Sysid workflow<br/>[sysid_wizard.py]"]
  node_real_env["Real rig interface<br/>[real_env.py]"]
  node_serial_client["Serial client<br/>[lowlevel_client.py]"]
  node_sim_env["Simulation environment<br/>[pendulum_env.py]"]
end

subgraph group_learning["Policy learning"]
  node_trainer["SAC training<br/>[train_sac.py]"]
  node_fine_tune["Real fine-tuning<br/>[finetune_real.py]"]
  node_async_fine_tune["Async fine-tuning<br/>[finetune_async.py]"]
  node_evaluation["Policy evaluation<br/>[analyze_run.py]"]
  node_distill["Policy distillation<br/>[distill.py]"]
  node_dagger["DAgger distillation<br/>[dagger_distill.py]"]
end

subgraph group_deployment["Deployment"]
  node_arduino["Arduino rig"]
  node_export["Weight export<br/>[export_weights.py]"]
  node_firmware_weights["Embedded policy weights"]
end

subgraph group_web["Browser demo"]
  node_docs["Project documentation<br/>[content.config.ts]"]
  node_demo["Demo orchestrator<br/>[index.ts]"]
  node_controller["Demo controller<br/>[control.ts]"]
  node_policy["Demo policy<br/>[policy.ts]"]
  node_renderer["3D renderer<br/>[renderer.ts]"]
  node_plots["Demo plots<br/>[sparkline.ts]"]
end

node_builder(("Rig builder"))
node_visitor(("Website visitor"))

node_builder -->|"starts measurement"| node_sysid_wizard
node_sysid_wizard -->|"fits rig parameters"| node_sysid
node_sysid -->|"provides parameters"| node_sim_env
node_trainer -->|"trains against"| node_sim_env
node_builder -->|"starts fine-tuning"| node_fine_tune
node_fine_tune -->|"controls real rig"| node_real_env
node_async_fine_tune -->|"controls real rig"| node_real_env
node_real_env -->|"exchanges state and commands"| node_serial_client
node_serial_client -->|"serial protocol"| node_arduino
node_trainer -->|"evaluates checkpoints"| node_evaluation
node_distill -->|"exports student"| node_export
node_dagger -->|"exports student"| node_export
node_export -->|"generates weights"| node_firmware_weights
node_visitor -->|"reads guidance"| node_docs
node_visitor -->|"interacts with"| node_demo
node_demo -->|"loads and poses"| node_renderer
node_demo -->|"creates and steps"| node_controller
node_demo -->|"loads policy"| node_policy
node_demo -->|"updates plots"| node_plots
node_controller -->|"gets action"| node_policy

click node_sysid "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/sysid_core.py"
click node_sysid_wizard "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/sysid_wizard.py"
click node_real_env "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/real_env.py"
click node_serial_client "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/lowlevel_client.py"
click node_sim_env "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/pendulum_env.py"
click node_trainer "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/train_sac.py"
click node_fine_tune "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/finetune_real.py"
click node_async_fine_tune "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/finetune_async.py"
click node_evaluation "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/analyze_run.py"
click node_distill "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/distill.py"
click node_dagger "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/dagger_distill.py"
click node_export "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/export_weights.py"
click node_firmware_weights "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/firmware/RLControl/policy_weights_rig1_tmc2209_32.h"
click node_docs "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/content.config.ts"
click node_demo "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/demo/index.ts"
click node_controller "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/demo/control.ts"
click node_policy "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/demo/policy.ts"
click node_renderer "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/demo/renderer.ts"
click node_plots "https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/demo/sparkline.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_sysid,node_sysid_wizard,node_real_env,node_serial_client,node_sim_env toneBlue
class node_trainer,node_fine_tune,node_async_fine_tune,node_evaluation,node_distill,node_dagger toneAmber
class node_arduino,node_export,node_firmware_weights toneMint
class node_docs,node_demo,node_controller,node_policy,node_renderer,node_plots toneRose
class node_builder,node_visitor toneIndigo
```

## Components

### Rig modeling

- [System identification](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/sysid_core.py): `policy/sysid_core.py`
- [Sysid workflow](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/sysid_wizard.py): `policy/sysid_wizard.py`
- [Real rig interface](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/real_env.py): `policy/real_env.py`
- [Serial client](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/lowlevel_client.py): `policy/lowlevel_client.py`
- [Simulation environment](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/pendulum_env.py): `policy/pendulum_env.py`

### Policy learning

- [SAC training](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/train_sac.py): `policy/train_sac.py`
- [Real fine-tuning](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/finetune_real.py): `policy/finetune_real.py`
- [Async fine-tuning](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/finetune_async.py): `policy/finetune_async.py`
- [Policy evaluation](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/analyze_run.py): `policy/analyze_run.py`
- [Policy distillation](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/distill.py): `policy/distill.py`
- [DAgger distillation](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/dagger_distill.py): `policy/dagger_distill.py`

### Deployment

- **Arduino rig**
- [Weight export](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/policy/export_weights.py): `policy/export_weights.py`
- [Embedded policy weights](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/firmware/RLControl/policy_weights_rig1_tmc2209_32.h): `firmware/RLControl/policy_weights_rig1_tmc2209_32.h`

### Browser demo

- [Project documentation](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/content.config.ts): `website/src/content.config.ts`
- [Demo orchestrator](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/demo/index.ts): `website/src/demo/index.ts`
- [Demo controller](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/demo/control.ts): `website/src/demo/control.ts`
- [Demo policy](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/demo/policy.ts): `website/src/demo/policy.ts`
- [3D renderer](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/demo/renderer.ts): `website/src/demo/renderer.ts`
- [Demo plots](https://github.com/ferrolho/rotary-inverted-pendulum/blob/main/website/src/demo/sparkline.ts): `website/src/demo/sparkline.ts`

### Other components

- **Rig builder**
- **Website visitor**

## Connections

- Rig builder → Sysid workflow: starts measurement
- Sysid workflow → System identification: fits rig parameters
- System identification → Simulation environment: provides parameters
- SAC training → Simulation environment: trains against
- Rig builder → Real fine-tuning: starts fine-tuning
- Real fine-tuning → Real rig interface: controls real rig
- Async fine-tuning → Real rig interface: controls real rig
- Real rig interface → Serial client: exchanges state and commands
- Serial client → Arduino rig: serial protocol
- SAC training → Policy evaluation: evaluates checkpoints
- Policy distillation → Weight export: exports student
- DAgger distillation → Weight export: exports student
- Weight export → Embedded policy weights: generates weights
- Website visitor → Project documentation: reads guidance
- Website visitor → Demo orchestrator: interacts with
- Demo orchestrator → 3D renderer: loads and poses
- Demo orchestrator → Demo controller: creates and steps
- Demo orchestrator → Demo policy: loads policy
- Demo orchestrator → Demo plots: updates plots
- Demo controller → Demo policy: gets action
