Skip to the content
PCBKitNew board
4 layers64 × 64 mmFlight computer, the printed circuit board in 3D

Flight computer

daniel360kim/ember

Thrust vector control rocket via differentiable simulation and reinforcement learning.

Size
64 × 64 mm
Copper layers
4
Thickness
1.6 mm
Parts
96
Nets
93
Pads
309
Tracks, vias
730, 141
Pours
9
Routed
Yes
KiCad
KiCad 10.0 (file 20260206)
Created
7 Jun 2026
Updated
18 Aug 2026

Overview

Flight computer is an open-source printed circuit board by daniel360kim, from the daniel360kim/ember repository on GitHub. It is a 4-layer board of 64 × 64 mm with 96 parts on 93 nets, routed with 730 tracks and 141 vias.

It is built around the TEENSY 4.1, NRF24L01 and BMP388, with the TPS563201DDCR, TPS73633DRBR and BAT54 among its other parts. Its parts include 37 resistors, 23 capacitors, 8 diodes, 8 connectors and 7 transistors. It belongs with the NXP (LPC, Kinetis, i.MX RT) boards of this library.

Main components

9

README

README.md

Ember

A differentiable 6-DOF rocket simulator that trains a neural flight controller by backpropagating through physics.

Ember is an end-to-end platform for developing thrust-vector-controlled (TVC) model rockets: a fully differentiable PyTorch flight dynamics engine, a neural attitude-control policy trained directly through the simulated physics, and a custom flight computer to fly the learned controller on real hardware.

The core idea is differentiable simulation (a.k.a. "diffsim"). Instead of treating the physics engine as an opaque, non-differentiable black box and learning a controller with reinforcement learning, Ember implements the entire 6-DOF rigid-body simulation in PyTorch so that gradients flow through every integration step, every aerodynamic force, and every actuator model. The attitude error at the end of a flight can be differentiated all the way back to the neural network's weights, letting the controller be optimized with plain gradient descent — the same way you would train any other neural network.


Project status

Ember is an active work in progress. The current state:

Working today

  • Complete, batched, GPU-ready 6-DOF differentiable physics (motor, TVC gimbal, aerodynamics, time-varying mass), integrated with RK4 and quaternion attitude kinematics.
  • Batched rollout stack (RocketEnv + EpisodeManager) with flight-phase termination (burnout, ground impact, excessive tilt).
  • A neural MLP attitude controller trained end-to-end through the physics via autograd, plus a PID baseline.
  • Declarative YAML vehicle configuration.
  • An extensive test suite (~40+ tests) including explicit gradient-flow verification.
  • A custom Teensy-based flight computer designed in KiCad (hardware/).

On the roadmap

  • Fully config-driven training/eval runners (task and hyperparameter YAML layers).
  • Domain randomization over motor thrust, mass, servo lag, and drag for robust sim-to-real transfer.
  • Trajectory-length masking of the loss past episode termination.
  • Experiment logging, checkpointing, and a dedicated evaluation runner.
  • Export of the trained policy to run in real time on the flight computer, closing the sim-to-hardware loop.

Why differentiable simulation?

Learning a controller for an unstable, fast, safety-critical system like a TVC rocket is hard. The two conventional options each have a major drawback:

  • Reinforcement learning (RL) treats the simulator as a black box and estimates gradients from scalar rewards. This works, but it is notoriously sample-inefficient — it throws away all the structure of the physics and needs enormous numbers of rollouts to converge.
  • Classical control (PID, LQR) is sample-free but requires hand-tuning and a linearized model, and it struggles with the strongly time-varying, nonlinear dynamics of a rocket whose mass, center of gravity, and inertia change every millisecond as propellant burns.

Differentiable simulation gets the best of both. Because the physics engine is written in an autodiff framework, the analytic gradient of the flight outcome with respect to the controller parameters is available for free. Training becomes a direct optimization problem:

"Given this rocket, what network weights minimize the attitude error over the boost phase?"

This is dramatically more sample-efficient than RL and far more flexible than classical control, because the exact gradient — not a noisy estimate — points the optimizer in the right direction on every single rollout.

text
                            ┌─────────────────────────────────────────────┐
   setpoint (upright) ─────►│  Neural Policy (MLP)                         │
                            │  attitude error + body rates → gimbal command│
                            └───────────────────┬─────────────────────────┘
                                                │  U (2-axis TVC torque cmd)
                                                ▼
        ┌───────────────────────────────────────────────────────────────┐
        │  Differentiable 6-DOF Physics (PyTorch)                        │
        │  motor thrust · TVC gimbal · aerodynamics · time-varying mass  │
        │  RK4 integration · quaternion attitude kinematics              │
        └───────────────────────────┬───────────────────────────────────┘
                                     │  trajectory X(t)   (fully differentiable)
                                     ▼
                            ┌────────────────────┐
                            │  Attitude-error    │
                            │  loss              │
                            └─────────┬──────────┘
                                      │
     ◄────────────────────────────────┘
        loss.backward(): gradient flows through the ENTIRE rollout,
        through every RK4 step and physics term, back to the MLP weights.

How the differentiable simulation works

Everything in the physics path is a torch.Tensor operation, so the whole rollout is a single differentiable computation graph. A few deliberate engineering choices keep that graph intact and its gradients well-behaved:

  • Autograd through the integrator. The RK4 step chains four evaluations of the vehicle dynamics per timestep, and every one is differentiable — the full trajectory is one continuous graph from initial condition to final state.
21
def rk4_step(...):
    k1 = dynamics_fn(X, U, t)
    k2 = dynamics_fn(X + dt / 2 * k1, U, t + dt / 2)
    k3 = dynamics_fn(X + dt / 2 * k2, U, t + dt / 2)
    k4 = dynamics_fn(X + dt * k3, U, t + dt)
    X_new = X + (dt / 6) * (k1 + 2 * k2 + 2 * k3 + k4)
  • Out-of-place quaternion normalization. After each step the attitude quaternion is renormalized by constructing a new tensor rather than mutating in place, so backpropagation through the projection is safe (in-place writes are a classic way to silently break an autograd graph).

  • Branch-free physics. Discontinuous logic — like the piecewise F15 thrust curve — is written with torch.where instead of Python if statements, so gradients propagate across every phase of the burn.

  • Gradient-safe numerics. Operations that can produce infinite gradients (e.g. arccos at ±1 when computing angle of attack) clamp their inputs away from the singularity, keeping training stable.

Because the physics is written this way, loss.backward() on the training loss populates gradients on the neural network's parameters through thousands of chained physics operations, and a standard Adam optimizer step improves the controller. There is no reward function, no value network, and no policy-gradient estimator — just supervised optimization of a trajectory-level loss.

53
        for i in range(N_EPOCHS):
            initial_state = torch.zeros(BATCH_DIM, S.DIM)
            initial_state[..., S.ORI] = start_orientation

            history = episode_runner.run(
                initial_state=initial_state,
                setpoint=setpoint,
                policy=policy,
                vehicle=self.vehicle,
            )

            loss = self.calculate_loss(history.to_episode_result(), setpoint=setpoint)

            print(f"Epoch {i + 1}/{N_EPOCHS} — loss: {loss.item():.6f}")
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

The physics model

Ember simulates a full six-degree-of-freedom rigid body with a compact, batched 15-dimensional state vector (simulation/src/vehicle/state.py):

StateIndicesDescription
Position0:3World-frame position (Z up)
Orientation3:7Attitude quaternion, scalar-last [x, y, z, w]
Velocity7:10World-frame linear velocity
Angular velocity10:13Body-frame angular rates
Gimbal angle13:152-axis TVC deflections (δx, δy)

Each timestep, the vehicle sums the physical forces and torques and integrates the rigid-body equations of motion. The physics is decomposed into independently-testable, composable components:

  • Motor — a piecewise-polynomial F15 thrust curve with analytic total impulse and a time-varying propellant mass / moment-of-inertia model (inside-out burn).
  • Cartesian TVC gimbal — a 2-axis thrust-vectoring actuator that tilts the thrust vector, with a first-order servo lag between commanded and actual deflection.
  • Aerodynamics — quadratic drag, Barrowman-style normal force, and a pitch-damping moment.
  • Mass properties — combines the dry airframe and burning motor, shifting the center of gravity and inertia tensor (via the parallel-axis theorem) as propellant is consumed.
  • Rigid-body core — Newton–Euler dynamics including the gyroscopic term ω × (Iω), integrated with swappable explicit-Euler or RK4 schemes.

The entire vehicle is specified declaratively in YAML (simulation/configs/vehicles/atlas.yaml) — mass, motor, geometry, aero coefficients, and gimbal limits — so a rocket is fully described by data rather than code.


The neural controller

The policy is a small multilayer perceptron (simulation/src/policy/mlp.py) — deliberately kept tiny so it can eventually be exported and run in real time on a microcontroller. It observes the shortest-path body-frame attitude error (the x/y components of the error quaternion) together with the body angular rates, and outputs a 2-axis gimbal torque command squashed through tanh to respect the actuator's physical limits.

26
    def forward(self, X, setpoint):
        q  = normalize_quat(X[..., S.ORI])
        w_b = X[..., S.ANG_VEL]
        setpoint = normalize_quat(setpoint.expand(*q.shape[:-1], 4))

        q_error = quat_mul(quat_inv(q), setpoint)
        q_error = q_error * torch.where(q_error[..., 3:4] < 0, -1., 1.)
        error   = q_error[..., :2]

        input = torch.cat([error, X[..., S.ANG_VEL]], dim=-1)
        output = self.network(input)
        return self.max_output * torch.tanh(output)

A conventional PID controller (simulation/src/policy/pid.py) is included as a baseline for comparison against the learned policy.


Quick start

Requires Python 3.10+.

bash
git clone https://github.com/daniel360kim/ember.git
cd ember/simulation
pip install -e .

This installs torch, numpy, matplotlib, and pyyaml, and puts src/ on the import path so from vehicle.atlas_v1 import Atlas-style imports resolve.

Train the neural controller through the physics

bash
cd ember/simulation
PYTHONPATH=src python src/runners/train_runner.py

This builds the Atlas vehicle, rolls it out under the MLP policy from a slightly tilted initial attitude, computes the attitude-error loss over the boost, and backpropagates through the entire flight to update the network — for 100 epochs. It plots the orientation and gimbal histories at the first, middle, and last epoch so you can watch the controller learn to stabilize the rocket.

Run the test suite

The physics engine is covered by an extensive suite of unit and integration tests, including explicit checks that gradients flow correctly through the integrators, the rigid-body core, and the full vehicle dynamics.

bash
cd ember/simulation
pytest                 # everything
pytest tests/vehicle/  # physics component & dynamics tests
pytest tests/runners/  # environment & rollout integration tests

Repository layout

text
ember/
├── simulation/                     # Differentiable PyTorch simulator (main project)
│   ├── src/
│   │   ├── vehicle/                # 6-DOF physics
│   │   │   ├── atlas_v1.py         # Concrete rocket: assembles the full dynamics
│   │   │   ├── base_vehicle.py     # Vehicle interface + quaternion projection
│   │   │   ├── rigid_body.py       # Newton–Euler derivative core
│   │   │   ├── mass_properties.py  # Time-varying mass / CG / inertia
│   │   │   ├── integrators.py      # euler_step, rk4_step (differentiable)
│   │   │   ├── state.py            # 15-D state-vector layout
│   │   │   └── components/         # motor, cartesian_gimbal (TVC), aero
│   │   ├── policy/
│   │   │   ├── mlp.py              # Neural attitude controller
│   │   │   └── pid.py              # Classical baseline
│   │   ├── runners/
│   │   │   ├── rocket_env.py       # Batched, Gym-like physics environment
│   │   │   ├── episode_manager.py  # Policy-in-the-loop rollout engine
│   │   │   └── train_runner.py     # Differentiable training entry point
│   │   └── utils/math.py           # Quaternion algebra & kinematics
│   ├── configs/vehicles/atlas.yaml # Declarative vehicle definition
│   └── tests/                      # Physics unit tests + gradient-flow checks
│
├── hardware/                       # Custom flight computer (KiCad)
│   └── pcb/flight_computer/        # Teensy-based board: IMU, barometer,
│                                   # servo drivers, pyro channels, power
└── background/                     # Early diffsim prototypes & experiments

Hardware

The hardware/ directory contains the KiCad design for a custom rocket flight computer — a Teensy-class board with an IMU, barometer, servo drivers for the TVC gimbal, pyro channels for recovery, and power management. The long-term goal of Ember is zero-shot sim-to-real transfer: train the attitude controller entirely in the differentiable simulator, then deploy the exact learned weights to this board to fly a physical rocket.

Parts

96
QtyValueFootprintReferences
120.1 uFCapacitor_SMD:C_0603_1608MetricC1, C4, C5, C10, C12, C13, C14, C15, C16, C18, C19, C20
610kResistor_SMD:R_0603_1608MetricR1, R8, R14, R23, R26, R38
610k 1%Resistor_SMD:R_0603_1608MetricR7, R17, R18, R19, R30, R32
5100kResistor_SMD:R_0603_1608MetricR9, R12, R21, R24, R37
410 uFCapacitor_SMD:C_0603_1608MetricC7, C17, C21, C22
4100Resistor_SMD:R_0603_1608MetricR10, R11, R20, R22
44.7kResistor_SMD:R_0603_1608MetricR13, R15, R25, R27
4BAT54footprints:SOT95P240X120-3ND2, D3, D4, D5
4MountingHole_PadMountingHole:MountingHole_3mm_PadH1, H2, H3, H4
31KResistor_SMD:R_0603_1608MetricR28, R31, R41
3AO3401Afootprints:SOT95P240X120-3NQ1, Q2, Q6
2220Resistor_SMD:R_0603_1608MetricR29, R36
2220 uFfootprints:CAP_UCD_6P3X7P7_NCHC24, C25
222uFCapacitor_SMD:C_0603_1608MetricC2, C3
22N7002footprints:SOT95P240X111-3NQ3, Q5
2AO3400Afootprints:SOT95P240X120-3NQ4, Q7
2LEDLED_SMD:LED_0603_1608MetricD8, D9
2RResistor_SMD:R_0603_1608MetricR33, R35
2ServoConnector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_VerticalJ6, J7
110 nFCapacitor_SMD:C_0603_1608MetricC9
1100 uFfootprints:WCAP-ASLI_6.3X7.7_DXL_C11
110K 1%Resistor_SMD:R_0603_1608MetricR16
110uFCapacitor_SMD:C_0603_1608MetricC6
1110K 1%Resistor_SMD:R_0603_1608MetricR2
116K 1%Resistor_SMD:R_0603_1608MetricR3
118k 1%Resistor_SMD:R_0603_1608MetricR6
13.3 uHInductor_SMD:L_0603_1608MetricL1
15V Terminalfootprints:691502710002J3
1AZ1117-5.0footprints:SOT223-5_DIOU7
1Aux PortsConnector_PinHeader_2.54mm:PinHeader_2x04_P2.54mm_VerticalJ9
1BATT_TERMINALfootprints:691502710002J2
1BMP388footprints:XDCR_BMP388U4
1BZT52C5V1footprints:P35_SOD-123FD7
1BuzzerBuzzer_Beeper:Buzzer_Murata_PKMCS0909EBZ1
1G***kibuzzard-6A2E09ACkibuzzard-6A2E09AC
1LED_RGBLED_SMD:LED_RGB_5050-6D6
1LSM6DSRXTRfootprints:LGA-14L_STMU5
1NRF24L01Connector_PinHeader_2.54mm:PinHeader_2x04_P2.54mm_VerticalJ1
1Pyro 1footprints:691502710002J4
1Pyro 2footprints:691502710002J5
1TPS563201DDCRfootprints:SOT95P280X110-6NU2
1TPS73633DRBRfootprints:SOT95P280X145-5NU3
1Teensy4.1footprints:Teensy41U6
1~Resistor_SMD:R_0603_1608MetricR34

Questions

How big is the Flight computer PCB?

It measures 64 × 64 mm and has 4 copper layers, 1.6 mm thick.

What parts does the Flight computer use?

96 parts, built around the TEENSY 4.1, NRF24L01, BMP388 and TPS563201DDCR. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Flight computer KiCad files?

From the daniel360kim/ember repository on GitHub, at the commit this page was made from: the board is hardware/pcb/flight_computer/flight_computer.kicad_pcb and its schematic hardware/pcb/.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Flight computer design in my own project?

Its repository states no licence, so its author keeps all rights: ask daniel360kim before reusing the design.

Similar boards

  • 4 layers100 × 80 mmPellet burner, the printed circuit board in 3D

    Pellet burner

    Weyla/pellet-burner-pcb

    171 parts
  • 4 layers18 × 40 mmLEO, the printed circuit board in 3D

    LEO

    prs2026/Lyra-flight-computer

    repo for the lyra flight computer

    76 parts3GPL-3.0
  • 4 layers150 × 90 mmMisrc v2.5-rounded, the printed circuit board in 3D

    Misrc v2.5-rounded

    Stefan-Olt/MISRC

    MISRC Is a multi channel RF capture device for FM RF, S-Video, CVBS RAW capture and anything else, but intended and supported for the decode family of projects vhs-decode, ld-decode, hifi-decode.

    328 parts236CC-BY-4.0
  • 4 layers172.5 × 85 mmDevhub, the printed circuit board in 3D

    Devhub

    mpolci/devhub

    Switchable USB Hub

    216 partsMIT
  • 4 layers50 × 36 mmPower dual buck, the printed circuit board in 3D

    Power dual buck

    HeyPCB/power-kit

    Six open power and charging boards: KiCad 10, JLCPCB-ready, CERN-OHL-S-2.0

    34 partsCERN-OHL-S-2.0
  • 4 layers150 × 40 mmLinklite v2, the printed circuit board in 3D

    Linklite v2

    WeasalCrafter/linklite-v2

    Programming and KiCad files for LinkLite v2: a modular lighting system with wireless control and syncing.

    116 partsMIT
  • 2 layers50 × 50 mmMysensorsGW, the printed circuit board in 3D

    MysensorsGW

    mysensors/SensebenderGW

    Gateway for MySensors

    76 parts7
  • 2 layers105 × 142.5 mmTestStand, the printed circuit board in 3D

    TestStand

    ibsal/LERT

    LERT will launch humans to space in 2 months, please give me 10 trillion dollars pls

    116 parts1