After a day of tweaking control loop settings, I've been able to fly 4pcb for at least several seconds at a time before crash landing or hitting a wall. I tried out two different control loop styles, PD control and nested angle/rate control. It's hard to tell from the video which one looks more promising. I want to say the PD control led to longer, more stable flights, but that was also earlier in the day and I was a bit hyper from coffee, so that may have had an effect.
Proportional-Derivative (PD) control would be my first instinct for stabilizing a quadrotor, since it deals directly with the two physical quantities at hand, angle (P), and angular rate (D). Each term gets multiplied by a constant, or gain, and then the sum is sent out as a command to the relevant motors. For pitch angle, the front and rear motors are used. For roll angle, the left and right motors are used. The control structure is straightforward:
If there is a net external torque on the quadrotor, for example due to an off-center C.G., it may also be necessary to include an integral control term that ramps up the motor command over time. With this, one motor would spin faster even when the quadrotor is level, canceling out the net external torque. Then the structure would be that of a full PID controller. I've left the integral term out for now.
There's another subtlety: because the motors and props have inertia, they can't instantly spin up to the commanded speed. The sensors, microcontroller, and ESCs also have built-in delay. So, if the gains are too high, the simple model breaks down and the quadrotor will just oscillate. This type of oscillation tends to be faster and twitchier than the proportional-only mass-spring oscillations. So yes, even more tweaking.
After tuning the PD controller for a while, I got a tip from David B. about www.openpilot.org. Now, I'm usually more of a do-it-myself-and-ignore-everyone-else's-version person, but the quadrotor loop tuning guide on openpilot is truly excellent. The video especially is really, really well done. Props (lolpun) to the creator, who can also be seen here demonstrating my ultimate goal for 4pcb, a frisbee launch.
The openpilot control loop uses a different structure, which I would call a nested or inner/outer control loop. The inner loop controls (angular) rate, and the outer loop controls angle. Both the inner and the outer loop contain a proportional (P) and an integral (I) gain, but for simplicity I will leave out the integral term.
What happens in this case is that the angle error gets multiplied by a proportional gain, Kpo, to create a desired rate. The desired rate goes into a second proportional gain, Kpi, to create the motor command. There integral terms would come in at each step, one in the outer loop and one in the inner loop. Though the documentation suggests using only one of the two possible integral terms. (In the video, both are explained.)
So, I tested this loop structure as well. In both cases, I left out the integral terms and I tweaked the gains until I was satisfied that I was getting the most stable flight I could. The values I get for PD control were Kp:1.2 and Kd:0.4. The units are a bit funky. Starting from degrees or degrees per second, these gains give you a motor command from 0 to 255. So, a 10º error would give a motor command increase of 12/255. A -20º/s error would give a motor command of -8/255.
For the nested loop, I settled on Kpo:4.0 and Kpi:0.5. Kpi has the same units a Kd from the PD controller. Kpo, though, is now in (deg/s)/deg. Confused? Well then now might be a good time for the plot twist.
They're actually the same thing.
When you ignore the integral terms, anyway, the two different control structures are actually equivalent. Kpi is Kd and the product of Kpi*Kpo is Kp. I didn't know this while I was testing, so the fact that I settled on slightly different gains (0.5 instead of 0.4 for Kpi/Kd and 4.0*0.5=2.0 instead of 1.2 for Kpi*Kpo/Kp) is probably due to the coffee. Interestingly, the gains I settled on are not far from the suggested gains on openpilot, when you convert to their unit scheme.
When you add in the integral terms, though, I think two control structures do have important differences. I couldn't exactly tell you what they are, but it's an interesting thing to think about. Since the main problem I'm seeing now is drift, integral control might be an important part of making it fly better. So that will be one of the things I'll be testing next. Along with that:
- Landing gear. As suggested by Max H., I'll be trying out some nylon standoffs on the four corners. If nothing else, it will help keep the quadrotor level during takeoff. It also might minimize the motor damage on slight-to-moderate crash landings.
- x-configuration. I've been using +-configuration, where forward is in line with one of the four appendages of the quadrotor. But when I think of a quadrotor, my mind sees x-configuration, where forward is halfway between two appendages. I don't know why. Also the openpilot video demonstrates x-configuration. The only possible technical advantage I can think of is that all four motors are involved in both pitch and roll, so perhaps any individual motor anomalies will be averaged out more. Or that might just be total BS.
- Flying with a gamepad instead of a joystick, as suggested by Ryan A. Reaction time and precision may be improved with something more closely resembling a normal RC transmitter.
- Supply voltage offset correction. I'm not sure if this is actually a problem or not, but the analog-to-digital converter references all signals to the supply voltage. If there is some deviation in the supply voltage under load, the zeros may drift. The gyros have a reference voltage that can be measured to correct for this offset, so I may at least test that voltage to see if its ADC value is varying under load. If it is, I can scale the other signals to compensate.
I would eventually like to be able to fly it in a small room. Whether I get there by tweaking the control or by practice, I don't really care...