Hi, I have been lurking for a while, but recently I got my quad up in the air on ardupirates, and just this week, I started getting successful flights with AC2. I am very impressed with the progress since early this year.
Now, what is the yoyo effect? when manually or automatically attempting to control the throttle of a multirotor, the craft will have a tendency to slowly oscillate in a fairly wide altitude range. That is, given a step throttle input, a quad will not go up to some height, instead it will overshoot its equilibrium height, and oscillate for a long time before settling (if it settles at all) so to hold a position, very careful operator input is required.
While many experienced pilots probably know how to hover at a specified altitude, the fact is, there is an inherent instability in the system. Here is my analysis and my proposal on how to deal with this issue.
Consider typical second order systems: A weight hanging from a spring in a frictional medium: pluck the weight and it will bob up and down. The oscillation will die out only as quickly as the frictional medium (air, honey, water?) is able to dissipate the energy.
I believe the process of attempting to hold altitude in a quad is a second order system: The quad has a mass (which will hold kinetic energy) but where is the spring that holds the potential energy? well, it turns out that the thrust your propellers are able to create is proportional to air pressure, and for all intents and purposes, we can say that thrust will vary linear over the range of oscillation: the higher the quad is, the lower the thrust. This efect is quite obvious closer to the ground, where the oscillations become more rapid, but regardless of altitude, thrust varies.
Now, when we model the system as if it was a spring, it is easy to see why it oscillates, but also, it is clear that the rate of oscillation will be rather slow, and DECEIVING, since an inexperienced pilot (or hypothetically an autopilot) would not quite realize what is happening and will produce throttle inputs that are always reactive, amplifying the problem.
Now, if the system had greater damping, these oscillations would die out quickly and it would be easier to maintain altitude, but we can't just make air "thicker" or put a sail on the quad to do this. We can produce a damping force by applying a differential term to thrust, in other words, create a little extra thrust in direct proportion to how fast the quad is moving and in opposition to it: When the quad is bobbing up, automatically create a little "downward" force by cutting thrust, and vice-versa.
There is a problem though: For this to work we need an accurate vertical speed to derive the term from. And neither of the altitude sensors (sonar or baro) has the responsiveness required to achieve a well behaved damping.
My approach (which I have tested for a number of weeks now) is to derive the differential throttle term from the accelerometer Z axis.
Here is the pseudo code:
th_dampK = 0.05;
th_dampP = -0.10;
leakRate = 0.1;
deltaZ = Z - lowPass_Z;
lowPass += Z * th_dampK;
speed_estimate += deltaZ;
speed_estimate *= 1 - leakRate; // leak 10 percent each iteration
throttle_damping = speed_estimate * th_dampP;
From physics class you will remember that the integral of acceleration is speed. So we can integrate the accelerometer output to obtain a value that is proportional to speed. There is a little problem with this method: The accelerometer will give a constant negative reading because there is gravity. If we were to merely integrate, we would come up with a speed that is always getting larger and larger, as if the quad was under free fall.
So that won't work without a small change: we high pass filter the accelerometer signal before integration, or use something called a "leaky" integrator. On every iteration the integrator looses a percentage of the total integral.
But will that work? The leaks have effectively highpassed the accelerometer's integral reading, We now only have "high passed" vertical velocity, or relative changes in velocity over the short term, but we never get an absolute velocity. Well, it turns out that this still works very well, because our goal here is not to read velocity but to create a "loss" in the yoyo effect. As long as there is yoyo effect to be dealt with, there is a short term velocity reading worth using.
There are a couple of last things to make this method safe: First, its range of influence has to be limited, so the damping term has to be constrained to some reasonable range, Otherwise, the throttle response will be adversely affected and the user will feel like they are fighting molasses on the way up or down; we want the pilot to feel like they are fighting molasses vertically when they are *trying* to hold the quad still (a good thing, because this "friction is helping hold still as well), but not when they are trying to climb quickly or drop quickly (not that you should be trying to drop quickly!, but that is another story)
throttle_damping = constrain(throttle_damping, -200, 100);
The end result is a throttle response that is much closer to "do what I mean" and not "do what I told you to" and I happen to believe that it doesn't only benefit manual control, but that automated means of throttle control *should* be wrapped around a "rate throttle controller" which is exactly what this method describes. We already do this for other axes of control, why not do it with throttle?
And the last thing: I have not tested this method at a tilted angle, nor do I think it is necessary for it to work at an angle.
So throttle_damping is scaled down gradually as the quad deviates from the horizontal plane. That way, rapid forward flight won't be affected. Remember the point of this is to facilitate keeping the quad still.
I haven't fully tested altitude hold in AC2 due to tuning, but I hope to get it working today. I am not necessarily proposing that this method be used in the altitude holding loop, my main objective with this method is to use it as manual throttle augmentation to smooth inputs, but I have a very strong feeling that the performance of altitude holding control methods is likely to drastically improve with this term added to the throttle. I will be testing this both ways once I have fully tested and tuned altitude holding as it is now.
I welcome feedback!
Replies
Hi guys, I've been interested in this problem too, because I find the altitude hold to be... well it just doesn't work. I'm flying a 600 size trad. heli outdoors. Wind gusts really have a bad effect on the Baro sensor, which is one problem. I get height swings of up to 20m showing up while the heli is just sitting on the ground on a windy day.
As for the yo-yo effect, I don't see that at all with my heli when I'm in Stabilize mode. In Alt-Hold though, it's all over the place.
As I understand it, the Throttle_Rate_PI and Alt_Hold_PI are both driven by the baro (or sonar) sensors yes? I'm not really sure why it's like that. Clearly the signal is way too "noisy" to work well.
I'm trying to follow the math that you guys are doing, but it's a bit difficult, and I'm not really even sure it's necessary. If I knew how to code well enough, I'd simply change the Throttle_Rate_PI to be driven by the virtual Z axis accelerometer, and then have the Alt_Hold_PI terms driven by the baro after heavy filtering.
To anybody following this discussion, I have started work on an improved version of this algorithm. Namely, instead of leaking the velocity away, the velocity drift is controlled by fusing the low frequency component of sonar derived velocity (constrained) and the error term from the difference between measured altitude and the altitude integrated from the velocity estimate.
Lag in the sensors is dealt with by filtering the dead reckoned position prior to calculating the error. This subject probably deserves its own blog post and I will try to find time this weekend to make a detailed description.
This is god timing. I have just started building this for AC2. I started a few months ago, but didn't get far. I do have a rotated Z value from the DCM so it works at angles.
I've taken a similar approach, but have not had success yet.
I wonder if you could combine this idea, and also add some configurable controls to limit or scale max vertical speeds when under a certain altitude. By doing so, you might create very precise vertical movement, create a "virtual airbag", and simultaneously improve automatic landing and takeoff routines.