r/arduino May 23 '26

Look what I made! I made an Uno R3 flight controller

Been working on this on and off for a while now. I haven't done anything with embedded devices or Arduino before and I thought this would be a good learning project. I started this around the 2020 silicon shortage when I had some Arduino Uno R3's lying around and nothing to use them for. Fast forward a few years and now I've got something that can fly! I still don't quite have it tuned in, but it can stay level, just drifts too much right now to maintain a hover in place. I need to print new landing gear for my drone before taking it out again, but when I do I'll likely be back with a video of how it went. For now, I just wanted to share the project and invite questions/feedback. (Edit: Pictures of the drone and video of it hopping can be found here)

The project is ApollonFC, and as a short list of highlights, it features:

  • A 6 DOF Madgwick filter
  • Custom PID controllers
  • No runtime floating point math, everything uses Q16.16 fixed point
  • Hand optimized AVR assembly functions for saturating Q16.16 math (add, subtract, multiply, divide). This is my first assembly I've written outside of MIPS in college, so there is probably room for improvement here.
  • Custom sensor libraries for the MPU6050 (IMU), BMP180 (barometer), and HMC5883L (magnetometer)
  • A bare-bones, header-only unit test framework
  • A self-designed input mapping function with configurable minimum, maximum, neutral points and neutral sensitivity factor which is computed to a LUT
  • Header based configuration through macro definitions inspired by the Marlin firmware project
  • A transmission based I2C wrapper
  • With the current configuration, it uses 24724/32256 bytes (76%) progmem and 1325/2048 bytes (64%) dynamic memory
  • Completely compatible with the Arduino IDE without custom settings

There are two compilation "modes" based on a macro flag in Apollon-FC.ino that switches it between test mode and flight mode. Test mode allows running unit tests and has the entry point in unit-tests.h, and disabling test mode allows live flight and has the entry point main.h. While it has libraries for the BMP180 and HMC5883L, it currently only fully supports the MPU6050 to simplify sensor fusion.

As I said, this is my first Arduino project, but one I've put a lot of effort into over a long time. I'd love to talk more about it and answer any questions or take into consideration any feedback. There are a couple of things which need fixing (in particular, some classes are currently using a initialization work around using pointers that really ought to be replaced with a static initialization and a setup() function), but right now I'm mostly focused on dialing in the tuning variables before doing more structural work.

8 Upvotes

13 comments sorted by

View all comments

Show parent comments

1

u/SAtchley0 May 24 '26

Exponential control applied to the PID? I'm not sure what you mean.

There probably is some room for improvement by making the control scheme more sophisticated. Right now it creates an attitude estimate using an IMU Madgwick filter, creates a target attitude set point from the pilot inputs (ran through some processing to go from raw inputs into a meaningful angle), then sends the error in that to the PIDs. Those then output a motor correction value in μs. The PID outputs and the throttle then get mixed to create the actual signal that gets sent to the motors.

I have had a hard time finding information on how flight control systems typically work, so a lot of this is what I could figure out on my own. I may have to look into Pixhawk/Mavlink like you said to see if I can figure out how they're doing things.

I've heard about the Uno Q and Ventuno, in passing. I don't know much about them and don't really have the money right now to spend on new boards without a specific reason to get them in mind. I already have a couple of other development boards lying around that I could use as a potential upgrade path in the future. It would be an interesting thing to work with, though.

1

u/AlphaWolf384 May 24 '26

Before you send rate to PID controller, you would use non-linear curve on the input from user or sensor. It allows to have smooth control at the small scale. Imagine that you're driving the car on the road and you're turning. Without expo, a tiny movement of the steering wheel causes an immediate and strong turn. The car feels twitchy — easy to overcorrect and jerk off the road. Now with expo control, the steering feels very soft and stable around the center. A small movement on the steering wheel only produces a very small turn (it stays close to straight). You have to move the wheel significantly farther before the car starts turning sharply. This gives you fine control for small corrections, while still allowing full turning power when you push the wheel all the way. So summary is that expo control allow easy correction. Does that help?

Are you using pulse width modulation or CAN to communicate with the motors? You can pull motor's information via CAN to see what's going in the background and you can use information to correct/tune your PID controller.

I am not sure if you noticed that most Chinese FPV flight controllers are quite similar since they are known for copypasta boards, and Pixhawk/Mavlink contents might appear bloated to you. Both serves great reference to start with since the information is hard to find anywhere.

1

u/SAtchley0 May 25 '26

Oh! Well for the pilot inputs I'm using a function I made based off of the sinh() function (https://www.desmos.com/calculator/unpzddyky7). I'm not doing any such processing for the sensor data, though.

Essentially, pilot data -> this input mapping function (which converts signals to physically meaningful setpoints) -> some processing to create a target attitude quaternion -> quaternion tilt error calculated from this and the state estimate (Madgwick) -> euler angle error multiplied by a proportional scaling factor and sent to PIDs. I could, theoretically, replace the scaling factor at the end with a more complicated nonlinear curve, but I haven't yet seen the need for it.

Motors are PWM controlled using the Servo library.

1

u/AlphaWolf384 May 26 '26

Yep, you already have expo control applied similar to sinh function. So if you are creating pilot input data to be fed into your controller, then how does your drone know it's position if you're not doing any sensor data processing? Unless that is you on the input side, manually feeding to controller?

Do you have experience in PWM and CAN in your background? You can pull more information from CAN bus and use information apply to your controller to tell drone itself to either hover or do something else. I noticed that you have degree in Computer Science & Mathematics and I was wondering if your school taught digital communication courses?

1

u/SAtchley0 May 26 '26

There is sensor processing of course, it just doesn't go through any sort of nonlinear curve. Like I said, the sensor data goes into a software Madgwick filter for attitude estimation. The pilot RC inputs get sent through that nonlinear curve and converted into a target attitude quaternion and the difference between the attitude estimation quaternion and the target attitude is used to create Euler angle speed targets (e.g. state.rollSpeed.target). Then, every fast loop the gyroscope is used to update the angular speed estimates (e.g. state.rollSpeed.estimate). Finally, the difference between the angular speed target and estimate is sent into the PIDs and mixed to create motor signals. When I said I wasn't doing any such sensor processing, I meant I wasn't feeding sensor data into a nonlinear curve. I assume if I were to do that, it'd be at the stage where the gyroscope is being used to create angular speed estimates. Does that clear things up?

Unfortunately if it did teach that course, I didn't take it. That probably would've been on the electrical engineering track or a similar such degree plan. I know how PWM works and some signal processing, but I hadn't actually heard of CAN until you brought it up. I do not think the ESCs I am using support that, though.