I wanted to build a quadcopter for years and never had a good entry point. The hobby market is dominated by Betaflight on dedicated F-class flight controllers. That is the right pick for performance, and the wrong pick if what you want is to understand the stack. The boards are too tuned, the firmware is too far along. You learn how to fly a quad, not how a quad works.

The entry point that clicked was okalachev/flix. It is an ESP32-based flight controller, simulated in Gazebo, with the actual code small enough to read in an afternoon. flix is honest about being a learning project. Not optimised for race, not for cinematic. Optimised for "you can read every line and understand what it does".

This post is about taking that as a starting point, printing a frame, and finding out what every layer of "a thing that hovers" actually costs.

The stack#

The frame is a 3D-printed quad with 5-inch arms in PETG-CF. The motors are 2207 brushless, 2400 KV, the kind that costs eight dollars each on the right Sunday. The ESCs are 4-in-1 BLHeli32 30A on a small board. The flight controller is an ESP32-S3-WROOM on a custom carrier PCB that breaks out four ESC PWM lines, a UART for telemetry, and an SPI to a BMI088 IMU. Power is a 4S LiPo.

The flight code is the flix firmware with my modifications. flix targets PlatformIO. The repo includes a SITL build for Gazebo, which is what saved me from crashing the real quad ten times. Everything I changed got tested in sim first.

What flix actually does#

A flight controller does four things in a loop:

  1. Read the IMU. Get gyro rates and accelerometer readings.
  2. Run the rate controller. Take the difference between the pilot's stick input (or autonomy setpoint) and the measured rates, compute a desired motor mix.
  3. Update the attitude estimate. Complementary or Kalman fusion of gyro + accel.
  4. Write the motor mix to the four ESCs as DShot or PWM.
       +-----------+
   +-->| read IMU  |   gyro + accel, ~500 Hz fast loop
   |   +-----------+
   |         |
   |         v
   |   +-----------+
   |   | rate ctrl |   stick/setpoint - measured -> motor mix
   |   +-----------+
   |         |
   |         v
   |   +-----------+
   |   | attitude  |   fuse gyro + accel
   |   +-----------+
   |         |
   |         v
   |   +-----------+
   +---| write ESC |   DShot / PWM to 4 motors
       +-----------+

That loop runs at ~250 Hz to 1 kHz depending on the controller. flix runs it at 500 Hz on the ESP32-S3, leaving headroom for radio polling, telemetry, and the slow loop (~50 Hz) that does barometer reads, GPS parsing, and high-level mode switching.

The whole codebase is about 4,000 lines. You can read it in an afternoon and change anything in it in another afternoon. That is what makes it a learning project instead of a product.

What surprised me#

The motor mix is trivial. Six lines of maths: take desired throttle, roll, pitch, yaw rates, emit four motor commands as a linear combination. Anyone with a high-school grasp of vectors can write it.

The IMU pipeline is the part that drains hours. The MPU6050 datasheet looks straightforward, then you use the raw readings and find they drift, ring, alias, and tilt with temperature. The standard fixes are well-documented: complementary filter for the cheap path, EKF for the proper path. The work is making them converge with your specific sensor on your specific frame at your specific vibration spectrum. The "trust the IMU" line in the textbook is about fifty hours of mounting, isolating, and tuning.

The accelerometer fights you at every level. A quad in level hover sees gravity plus motor vibration. The vibration peaks at the prop's rotational frequency and its harmonics. Your accelerometer reads "gravity + a 280 Hz noise floor" and your attitude estimator integrates that noise into a drift. Three things help: rubber-mount the FC, low-pass the accel reading at maybe 30 Hz, and notch out the propeller frequency dynamically. flix has all three. Tuning the notch to your specific build is the thing that takes a week.

Third surprise: the radio. The ELRS link worked fine in sim. On the real board it dropped packets the instant I powered the ESCs. The motors radiate at the switching frequency, the receiver picks it up, the packet rate collapses to ten per second, the quad falls out of the sky. The fix is ferrite chokes on the ESC power leads, the receiver antenna clear of the power harness, and shielded twisted pair from the receiver to the FC. None of this is in the textbook either.

What flix taught me that the manuals did not#

PID tuning is the part everyone writes about. It is also the easiest part. Once the IMU is clean and the radio is reliable, PID tuning is methodical: raise P until oscillation, back off 30%, raise D to damp, raise I just enough to hold attitude under wind. An hour with a setpoint sweep and a log analyser gets you there.

The hard parts are upstream: clean IMU readings, vibration management, a radio link that does not glitch under power. Get those right and the controller is forgiving. Get them wrong and no PID gains help.

The other thing flix taught me is why Betaflight makes the choices it does. Its dynamic notch filter, its gyro filter cascade, its motor-output protocol: every one is a mitigation for something the simpler flix code does not handle. After reading flix's IMU code and watching it fight a noisy quad, every Betaflight tuning guide reads differently. The flags I used to memorise map to specific failures on the bench.

The printed parts#

The frame is a True-X layout with 5-inch arms. The arm thickness is 6 mm in PETG-CF, which sounds excessive and is necessary. PETG flexes under hover load, and the flex shows up in the IMU as low-frequency noise that no amount of filtering removes cleanly. Stiffer arms is the only real fix.

The top plate carries the FC and the receiver. I printed three versions before settling:

VersionProblem
Firsttoo thin, resonance
Secondtoo thick, mass
Thirdisolation pad cut into the FC mount with TPU vibration dampers

That isolation pad is the single biggest gain I made on noise figures.

Battery strap, antenna mounts, GPS standoff: all generic Printables files with minor edits. The FreeCAD source for the custom plate is in my notes. Nothing about it is special, it is a 2 mm flat with mounting holes and a TPU-pad pocket.

What I would change next time#

Start in sim, longer. flix has a Gazebo SITL faithful enough to catch most of my early code bugs. I rushed past it on the way to the physical build and paid for it in broken props. Two weeks of sim before powering the real ESCs would have saved a propeller set.

Pick the IMU first. I started with an MPU6050 because every tutorial used one. The BMI088 I ended up with is far less work to filter. The cost difference is twelve dollars. The time difference is a week.

Build the harness as if every wire is an antenna. Ground returns close to power leads, shielded radio harness, ferrite where it costs nothing. The cost of doing this from the start is half an hour. The cost of doing it after the first radio failure is rebuilding the harness from scratch with the quad on the bench.

flix is a good starting point. Most of what I learned came from the physical build, not the code.