LQG controller and autotune for multicopter

Hi Leonard, Jon and Paul,
This looks like some very interesting work on multicopter control in TauLabs:
The code is here:
the work is being done by James Cotton (peabody124)
It uses a small EKF to learn the gains for the controller.
Do you think this is something we should be looking at?
Cheers, Tridge

I had a quick look.

If they are using this to learn PID values during flight, and it is reliable, then that could be very helpful. However, if it is an alternative control architecture then it will need to demonstrate that it offers significant advantages over the basic pid control we currently have.

In any case it doesn’t offer any advantage significant enough to make it worth prioritising for me. If it looks like a good thing as it develops then I can look at it after the next pass through the code.

They are learning in flight with an EKF. You can see the EKF prediction step here:
wikipedia introduction to the approach here:
If we wanted to experiment with this then I think what we’d do is have swappable rate controllers and be able to switch between them in flight. We could run the learning of the LQG controller while flying the old controller.
Another approach would be doing the learning based on DF logs.
I’ve been pretty impressed by the work going on in TauLabs lately. They have some great developers.

I pointed James Cotton at this discussion and he gave me a link to the derivation of the autotune KF:
they have been using the KF learning of the PIDs for a while, and the LQG controller is the next step in that development.

It is likely not well-suited to fly arbitrary multirotors with arbitrary payloads and arbitrary ESCs. ESCs without active braking (COMP_PWM) enabled are very nonlinear. Sprung masses like gimbals are very common on multirotors and represent an effect that isn’t modeled (but possibly could be!)

It probably is very well-suited to an FPV racer application because FPV racers are very simple, typically have comp_pwm enabled, typically don’t have gimbals, and they don’t require robustness guarantees (which you can’t make with LQG). It will push them to the edge on performance.

what are the views regarding plane, and in particular trad heli?

I’d like to get Pauls view on that. The obvious place to first try this is on small quads as that is the platform James has been developing it on. It could make sense for heli and plane, I don’t really know enough about the properties of the controller to know.

Matt Garratt may have some ideas too

Cool to see you guys talking about some of my work. Let me comment/clarify a few things.

The link above is to the system identification EKF that we have been running for some time primarily oriented at multi rotors. It essentially models the motor response as a low pass filtered version of the control input which then has a gain that determines the actuator efficacy. The EKF then estimates these parameters. As to model error that @jschall references, that is absolutely a possibility. In my experience the model does an extremely good job of capturing the real behavior when I use a custom board I designed that captures all the individual sensor updates.

For example here is it tracking a fast step response requested. You can see the KF trace follows the gyros quite well. I agree there are asymmetries in motor responses but when you have opposing pairs of motors those are less critical (for extremely high gains, you do start to notice increases in average throttle for rapid events).

In our older approach, we used these estimated system parameters to then calculate the optimal inner and outer loop gains. These rely on a number of (I think quite reasonable) analytic approximations to achieve an appropriately damped response and to minimize the number of “sliders” for the end user. You can find the derivation here https://github.com/TauLabs/TauLabs/blob/next/flight/Doc/Autotuning%20Derivation.pdf

All of this works with traditional PID controllers and really just optimizes gains for them.

More recently, I have been working on taking this system model to run a state estimate of the instantaneous motor torque and rotational rate. Ultimately, using these for the control system rather than the raw noisy gyros that doesn’t account for the physics of flight will perform more poorly (although is airframe-type agnostic, which is why we started on this approach to trivially switch between MR/heli/plane). Rather than just pump these state estimates into PID (which would be a reasonable approach), I’m using a more modern control technique called LQR. The combination of the state estimator with LQR is more generally called LQG – linear-quadratic-gaussian.

The short version is that it works quite well. For example this is the response on a really crappy test frame with no manual tuning: https://www.instagram.com/p/BEsDahFlqg3 and here is another one of it in flight https://www.instagram.com/p/BD9y3S7lqvj

I’m currently working on a more complete writeup of this, although naturally that has segued into a refactoring of the math so is taking longer than anticipated :slight_smile:

Thanks James, and welcome!
There are a few areas where this may be good for ArduPilot apart from the most straightforward application to multicopters.
One is in helis, where we don’t currently have an autotune system at all. Do you know if this has been applied successfully to heli swash and/or tail control? The PID controller we use for heli has an additional FF term that we have found to be essential, but we’ve also found it quite difficult to tune on some vehicles.
Another one that is giving us problems is rudder control on planes without ailerons. Our existing rudder controller doesn’t cope at all well, often leading to some fairly nasty oscillation in flight.
For your autotune method, do you do it only in-flight, or have you tried running the estimator over log files? The boards we fly on can log at high rates (assuming the microSD card isn’t too cheap), and estimating parameters for a controller based on a log file is quite attractive.

As a minor update, TauLabs now have a 2-axis sysID library here: