Skip to content

About

Run real electric-unicycle firmware in a 3D simulation with a physical rider. Inspect it, compare it, improve it. (Source-available, PolyForm Noncommercial)

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

EUC Studio

ci-engine ci-firmware app vendor-guard License: PolyForm Noncommercial 1.0.0

Run real electric-unicycle firmware in a 3D simulation with a physical rider. Inspect it, compare it, improve it.

EUC Studio replaying real runs: a Free Ride through the city, a pothole, a cut-out at top speed, and stock against our firmware

The studio itself, filmed headless, replaying real runs of the stock firmware (26 s). With sound: showcase.mp4. How it is made: video/.

EUC Studio is a workbench for people who want better and safer EUC controller firmware. It runs the controller's actual firmware image on an emulated microcontroller. Motor, battery, wheel, rider and city models supply its inputs. The simulator helps you inspect behavior under stated conditions. It does not establish real riding safety.

Free Ride in the generated city: the rider on the simulated Begode Extreme, seen from the Chase camera

Free Ride in the generated city (seed 42): the stock firmware (GW1825007) on the real engine carries the rider through a left turn at 20 km/h in drive mode, on the neutral pedal preset. Chase camera, with the HUD, the pitch gauge and the wheel's display replica; replayed from a recording. Some physical parameters are estimates.

Warning

Custom firmware can make a wheel cut out, injure its rider or destroy its power stage. Read SAFETY.md before you build, flash or ride anything from this repository. Today no build of this repository flashes a real wheel (flasher rules).

What it is for

  • See the firmware work. Watch balance, motor control, tiltback and cutoffs react to a rider in 3D, with scopes, an event timeline and the firmware's own variables live.
  • Compare stock and custom firmware. Run both on the same ride, side by side, and find the first moment they differ.
  • Change one thing at a time. Our own firmware for the Begode Extreme reproduces the stock behavior, quirks included (the compat profile), and then fixes them one by one (the clean profile), each fix shown in a scenario.
  • Ride it yourself. Free Ride puts you on the simulated wheel in an endless generated city, with the keyboard or a gamepad, while the real firmware balances it.
  • Grow to other wheels. Wheels, boards and processors are described as data, so new models and brands can follow.
Ride Compare
Ride workspace: scopes show the spike of a pothole Compare workspace: stock and our compat build ride the same pothole
The stock firmware about 1 s after a 5 cm pothole at 20 km/h: the PWM, modulation and phase-current scopes show the spike. Recording playback. Stock against our compat build on the 20 km/h pothole scenario: run B rides as a ghost, the charts are synced, and the comparison is within tolerance so far.

How it works

 firmware image ─▶ emulated MCU (ARMv7-M core + peripheral models)
                        │ PWM ▲ currents, halls, voltages, IMU
                        ▼     │
                   inverter ─▶ motor ─▶ battery          (electrical plant, 5 µs steps)
                        │ torque ▲ wheel speed
                        ▼        │
              wheel, tyre, shell, human rider, ground    (MuJoCo, 0.5 ms steps; flat floor,
                        │                                 terrain strip or streamed city)
                        ▼
          EUC Studio app · CLI `euc` · Python bindings

Everything runs on one deterministic clock counted in microcontroller cycles, so every run can be replayed exactly. Our firmware can also run as a host library (SIL) in place of the emulated image, with its quirks switched at run time. See docs/architecture.md.

The first wheel is the Begode Extreme. Its stock firmware boots unchanged in the Rust engine. The simulator reproduces the observed interfaces. Unknown hardware values remain explicit estimates.

Status

Updated 2026-10-23. Open work lives on the public EUC Studio Roadmap board, grouped by milestone. docs/project-status.md has the evidence and the checks for each area.

Milestone State Done Open
M0 Foundation Done Repository, CI, vendor guard, pinned stock fetch, image gate Keep the gates for new features
M1 Stock boots Done Stock firmware boots, sends telemetry and answers app commands faster than real time Broader hardware calibration
M2 Stock rides in 3D Done Electrical plant, MuJoCo body, rear suspension linkage, terrain, display, lights, sound, Ride workspace Measured motor, battery and suspension values (calibration)
M3 Own CPU core Done Own ARMv7-M core, lock-step checks against Unicorn, a selectable per-instruction flash timing model Exact peripheral timestamps inside a quantum; Tune memory writes and gain edits
M4 Human rider Most done Articulated rider (the default), opt-in contact feet and lateral rider (L1-L3), 26 scenarios, .eucrec recordings, Python bindings, Free Ride Rider balance without external aids (lateral rider L4-L6), measured human response
M5 Our firmware Most done Compat and clean images boot and ride; the SIL library switches every quirk at run time (SIL) The 50 % charge full-effort difference (#42), firmware findings, hardware validation
M6 Flasher Simulator only Gated flasher against a simulated wheel with an emulated bootloader; 320-run fault campaign with no unrecoverable run (spec) Image signing, the emulator ride of gate 3, bootloader facts from the SWD dump, the app wizard; no real flash (M6)
M7 Release Started Desktop source builds, a local macOS package (guide), the wheel onboarding guide Signed bundles, docs site, browser demo, a second wheel (M7)
M8 Bench Planned The safety procedure only Controlled bench work and trace comparison (M8)

Current work:

Track State Open
W2 Scenarios in the city Done (2026-10-23) The shipped scenarios ride the generated city (world model, #11)
P1 Physics realism bundle Draft PR #62 A rubber tyre at 25 psi with rolling resistance, a finer city grid, the motor fit, the roll fix, and kerb absorb and brace are in the draft (epic #57). The open step is the re-baseline of every scenario, #18: a good task for a contributor
Lateral rider L4-L6 L1-L3 done The rider balances and turns with its own body instead of external aids (epic #58)
Free Ride polish Play mode, drive mode, Chase camera, daylight, sound and HUD done Impact sounds, city look up close, buildings, trees, a minimap (milestone)
Calibration Open Tools and measurements that tie the simulator to real wheels (epic #59)

Plans and limits per milestone: docs/roadmap.md. All documents: docs/README.md.

Quick start

You need:

  • Rust through rustup. The toolchain version is pinned in rust-toolchain.toml; rustup installs it on the first cargo command.
  • Python 3.11 or newer.
  • For the desktop app: Node 20.19 or newer, pnpm 10, and the Tauri prerequisites for your OS.
  • For our firmware: CMake 3.25 or newer, Ninja, and the Arm GNU Toolchain (see firmware/README.md).

The engine and the CLI build on macOS, Linux and Windows. The BLE radio features run on macOS only.

git clone https://github.com/tarikbc/euc-studio && cd euc-studio
git config core.hooksPath tools/hooks          # once per clone: the vendor guard runs before each commit
python3 tools/fetch-mujoco/fetch.py            # once per clone: the pinned MuJoCo library the physics links

cargo run --release -p euc-cli -- fetch begode-extreme   # download and verify the official Begode Extreme build

Run a scenario on the stock firmware. Motor, battery, body, rider and city are simulated, and the scenario's checks are judged at the end:

cargo run --release -p euc-cli -- sim run --scenario scenarios/ride-20kmh-stop.toml

Build our firmware, then ride it and compare it with stock:

(cd firmware && cmake --workflow --preset target-compat && cmake --workflow --preset target-clean)
cargo run --release -p euc-cli -- sim run --scenario scenarios/ride-20kmh-stop.toml --firmware clean
cargo run --release -p euc-cli -- sim compare --scenario scenarios/ride-20kmh-stop.toml --b compat \
    --tolerance scenarios/compare/compat-vs-stock.toml

Start the desktop studio (the first build takes several minutes):

cd app && pnpm install && pnpm tauri dev

More: cargo run -p euc-cli -- --help lists every command, docs/scenarios/writing-scenarios.md explains the scenario files, docs/compare.md the comparison, docs/python.md the Python API, and docs/spec/flasher.md the simulated flasher (euc flash --sim --synthetic). The checks for each area are in CONTRIBUTING.md.

Free Ride

In the desktop app, open the Ride workspace and press Free ride above the 3D view. The ride starts at once in the generated city: the firmware boots (about 1.5 s of simulated time) and the keys work. A crash never pauses; press R to respawn.

Key Gamepad Action
W / ↑, S / ↓ Left stick, RT / LT Ride forward, brake
A / ←, D / → Left stick Turn
Space (hold) LB (hold) Crouch; at speed also a tuck (less drag)
X B Step off
R, Shift+R X, Back Respawn here, at the start
P (hold), H (hold) The wheel's power and handle buttons
L, B, M Light, horn, pedal mode
Esc Start Pause, go on
C Y Camera

Keys can be rebound in the panel. The full reference, including drive mode and lean mode, is in app/src/workspaces/freeRide/README.md. Free Ride is a simulation for firmware work, not a riding trainer.

How work is organised

Open work lives as issues on the public roadmap board, grouped into milestones; a large topic has an epic issue that lists its parts. Comment on an issue before you start larger work, so the plan is agreed first. Every change goes in as a pull request: CI runs the checks of the areas it touches (engine, firmware, app, Python bindings, the stock-against-compat comparison and the vendor guard), every commit carries a DCO sign-off (git commit -s), and a safety-relevant change brings its scenario evidence. CONTRIBUTING.md has the details.

Where to start

Skills that help, and where they fit:

You know Where it helps Labels
Rust, CPU emulation, microcontroller peripherals The ARMv7-M core, STM32F1 peripherals, engine speed (crates/euc-armv7m, crates/euc-stm32f1, crates/euc-sim) area: engine
MuJoCo, rigid-body physics, biomechanics Tyre, suspension, the rider models and their controllers (crates/euc-physics) area: physics, area: tyre, area: rider
Motors, inverters, batteries The electrical plant and its calibration (crates/euc-plant) area: plant, area: calibration
Embedded C, motor control Our firmware's compat and clean profiles (firmware/) area: firmware
three.js, React, TypeScript The studio, Free Ride and the city's look (app/) area: studio, area: world, area: model
Audio synthesis Free Ride's sound, made from the simulator's signals (app/src-tauri/src/engine/ride_sound.rs) area: sound
Python, data analysis Comparing simulated runs with real ride logs (python/; the tool is #35) area: calibration
A Begode wheel (or another EUC) Measurements and ride numbers that check the simulator needs: data
  • Read CONTRIBUTING.md for the ground rules, the area map and the checks per area.
  • Read docs/architecture.md, then the guide of the area you work on (docs/README.md maps every document).
  • Own a wheel? Measurements and ride data help most. Use the real-wheel data issue form, and never post GPS tracks or raw logs that show where you ride.

Stock firmware is never in this repository

euc fetch <wheel> downloads the official image from the manufacturer's own update server to your machine and checks it against the sha256 pins built into the tool. Nothing from the vendor image is stored here, and a guard blocks it on every commit and in CI.

Repository

Path What
crates/ Rust engine: CPU core, peripherals, plant, physics, world, recordings, flasher, CLI euc, Python bindings
firmware/ Our controller firmware in C11 (compat and clean profiles, SIL library)
app/ The EUC Studio desktop app (Tauri, React, three.js) and its design system
scenarios/ Scenario files with their checks, and the compare tolerances
profiles/ Wheel definitions: board, plant, geometry, probes, stock firmware pins
python/ The euc_studio Python package and its tests
docs/ Architecture, roadmap, specifications, model notes, findings (index)
tests/data/ Real-wheel captures used as test data
tools/ Vendor guard, git hooks, MuJoCo fetch

Contributing

See CONTRIBUTING.md. In short: sign off your commits (git commit -s), never add vendor material, and back every safety-relevant change with a scenario. Report a behavior that could hurt a rider privately, as SAFETY.md explains.

License

EUC Studio is source-available under the PolyForm Noncommercial License 1.0.0. You may use, study, change and share it for any noncommercial purpose. Commercial use is not allowed. See NOTICE for third-party components and trademarks.

EUC Studio is an independent project and is not affiliated with, endorsed by or sponsored by Begode or any other EUC manufacturer.

About

Run real electric-unicycle firmware in a 3D simulation with a physical rider. Inspect it, compare it, improve it. (Source-available, PolyForm Noncommercial)

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages