Tuesday, June 28, 2011

Quad tuning

I made a post to the diydrones website some days ago, explaining some modifications I made to the Arducopter source code. A colleague of mine explained me a couple of things about issues related to aircraft control. The standard Arducopter code has the attitude controller in place and the GPS Hold. I added the velocity controller. As you can see from the diagram, this means that the GPS Hold controller immediately changes the attitude of the quad on the basis of some difference in position. The attitude controller itself just maintains a certain angle setting.

The attitude of the quad may induce a certain acceleration into some direction. When you steer a quad to some location by hand, you don't maintain the angle until you get there, but steer towards the other direction for a brief moment to zero the velocity with the intention to have zero velocity on the intended position.

My experiences with the GPS Hold code in the arducopter are poor. Others have had more success, but I could never find the right settings that made the quad behave correctly in all circumstances.

Because the GPS Hold controller controls the angles directly, but doesn't look at the velocity, it will only zero the velocity after it has passed through the setpoint. This means that with some larger drifts around a setpoint, overshoot cannot be avoided. Aggressive settings then cause overshoot into one direction; the quad then slows down, reverses direction and overshoots the other direction. Thus it oscillates around a position. Higher D-gains help in this regard, but I couldn't get this to calibrate correctly. The I-term does more evil than good and should be used very sparingly.

With the velocity controller in the middle I had more success. The velocity controller is also a better means to control where one is going. Letting go of the sticks means that the quad already attempts to hover around doing nothing. With little wind you'll see that this leads to a near-perfect GPS Hold operation. The GPS Hold code that you do put in than only removes the little offset that does take place due to small disturbances and other inaccuracies due to some dampening filter on the GPS course/speed readings.

In order to calibrate things correctly, start with the last controller going backwards. The attitude of the quad must be maintained with near perfection. Indoors in a large enough area, it should not travel significantly in any direction. If the quad does that, it may indicate:
  • most likely cause: too many vibrations in the quad causing the IMU to get slightly confused at times or over time. It may then tilt somewhat into any direction causing speed to build up.
  • motors not pointing straight up, so that propellers have thrust in the xy-plane.
  • Incorrect response of ESC / motor due to incorrect ESC calibration, defect motor, etc.
I cannot stress enough how important it is to remove vibrations as best as you can, because you get much better results that way. In my case, I've flown with the quad in a situation where it was moving about quite a bit in outdoor environments and making a sound like a lawn mower (you know, where the mower blades cut reeds, those kinds of 'graty' sounds). I found out eventually that my bolts appeared to be tightened, but with a proper spanner could still tighten it further by 1/4 turn. This improvement for about 5 bolts resolved the graty sounds entirely and on the next launch, it hummed perfectly. That is how much bolts / nuts may impact stability, the way how motors are balanced and in turn impact the vibrations on the IMU. So make sure that works ok.

To calibrate the attitude controller, set the tx into attitude control mode of course. Then zero I and D and start with the P setting. You're looking for a P-setting that is just high enough to cause the quad to just about oscillate. Then lower the P setting a little notch (this is a relative operation) and work on the I and D terms next. The I-gain has two purposes:
  • Increase the speed at which you find your setpoint.
  • Resolve any bias that may accumulate in your system.
The bias for example is wind. If your quad already remains very level, in outdoor environments a level quad will drift away slowly on the wind. Suppose that you're activating the GPS Hold controller. Without the I-gain, you'll drift downwind until proportionally speaking, your quad has such an angle that it finds an equilibrium with the wind conditions. The I-gain will start to kick in, increase the angle and the idea is that the build-up of the I-gain over time and the decrease of the P-gain eventually establish a new equilibrium on the exact setpoint. That would be perfect.

The D-gain is there to reduce the speed of approximation towards some setpoint, such that it reduces overshoot of the setpoint (similar to how the GPS Hold working on angles should work).

For the attitude controller, I'm using some suggested values that are not special at all: P=3.4, I=0.015, D=1.2. These are the values for my quad and mine is custom built with relatively large distances between props. It's likely that if you have a smaller quad, you can sustain some more aggressive values.

Soon as the attitude controller is stable, work on the velocity controller. This only has two variables to adjust: P and I. At some point, especially with systems that have low frequency of reads, there's no point to use D-terms anymore. The P-gain for the velocity controller should not be too high to prevent instability. The velocity controller depends on the GPS information and this is basically some complicated piece of hardware nowadays with its own filters, dampeners and other algorithms. It's likely that a high frequency GPS (10Hz) together with doppler shift readings for speed give the best results. I set the P-gain to 0.04, which equates to a 4 degree angle when speed is 1 meter per second. If this is set more aggressive, it's possible that you see a circling motion occur due to the way how ground course is calculated in some GPS's. The I-term is basically determined on the basis of how much 'angle' one would need to compensate for windy conditions (in order to still develop a certain velocity).

Since the velocity controller is already very effective in keeping the quad fixed in place, the GPS Hold controller is just there to resolve any difference in position that still does occur over times in the 20-30 second area. It slowly develops a certain velocity that the quad should have towards the setpoint and slowly retargets the quad towards a certain position. My GPS hold controller only uses a P-setting. An I-term could be added to make it slightly more aggressive, but I never felt a need to do that.

Wednesday, June 08, 2011

Declaring multiple variables one line of code

Quiz time! Consider the following variable declaration in a C program:

float x, y = 0.0f;

What is the value of x?

Answer: undetermined

This issue hit me, after so many years of ultra-explicit programming. A colleague way back in the UK taught me to prefer the explicit style of programming, since it's less likely to fall into traps like these. So coding programs in that style looks like:

char temp[ 512 ] = {"\0"};
int x = 0;
float y = 1.0f;

Everything gets initialized immediately after it is declared, so there is much less of a probability of picking up rogue / uninitialized values that way. This style also caused me to declare one variable per line.

I decided to take a shortcut after so many years for a quick experiment. Not just that... I decided to do this within a piece of embedded code running on a quadrotor.

The above shortcut led to the uninitialized value picking up the negative maximum value for an Arduino float: -2,147,483,648. Subsequently, this value was used in a calculation to add this particular value to an existing position. The result was a negative max float for latitude and longitude. This led to a quadrotor immediately hitting the limiter of the control system (-20 degree bank angle) and taking off to some undetermined location fractions after it was told to go into a position hold mode (where it stays in the same location in the xy plane at least).

After this line was changed to:

float x = 0.0f;
float y = 0.0f;

Things started working again. Since debugging on embedded systems is a huge pain in the *&(@#$, it took me some time to find and slap my head in disbelief.

This kind of thing is really easy to read over when you review code and definitely has the potential to have immense consequences... Another thing to seriously look out for.
( the assumption is that reviewers assume x = 0.0f as well, since it's part of the same line).

Proper code for multiple declarations in the same line look like this:

float x = 0.0f, y = 1.0f;


float x = y = 0.0f;