1
\$\begingroup\$

I am doing a project on self balancing quadcopter with Autonomous control. I am using Arduino Mega 2560 and MPU6050. I have obtained the roll and pitch angles from MPU6050 without the help of DMP and applied complementery filter to omit the noise due to vibration. Also Configured and able to run the BLDC motors with Flysky Transmitter and receiver with the help of arduino interrupts. Now for balancing I am focusing on only one axis(i.e. roll). I have also constructed a balancing stand for the free movement of roll axis by the motor.

For the controlling part, I am implementing PID algorithm. I tried using only the kp value so that, somehow I can balance and then move on to ki and kd term. But unfortunately, for Kp itself, the quadcopter is undergoing aggressive oscillation and is not settling at all.

Some of my queries are,

  • whether a single PID loop is enough, or we have to add another
  • what type of tuning method, i can implement, to find the kp, ki, kd other than trial and error
  • I programmed my ESC for 1000 to 2000 microseconds. My PID input angles will be within the range +/- 180. Whether I can directly set the pid output limits for range -1000 to 1000 or -180 to 180 or any other value.

The code can read from the url https://github.com/antonkewin/quadcopter/blob/master/quadpid.ino

\$\endgroup\$
  • \$\begingroup\$ Your "complex filtering" of roll & pitch could affect PID control adversely. \$\endgroup\$ – glen_geek Mar 9 '17 at 18:04
  • \$\begingroup\$ "I programmed my ESC for 1000 to 2000 microseconds." Standard frequency (repetition rate) for a 1~2ms servo pulse is 50Hz, but could theoretically be almost 500Hz (2ms on, >0mS off). The faster you can send the pulses the quicker the ESC will respond. What is the highest servo frequency your ESC can handle? \$\endgroup\$ – Bruce Abbott Mar 9 '17 at 21:12
1
\$\begingroup\$

PID isn't a magic tool to accomplish all tasks, rather an universal method of control. Your oscillations are probably due to too much high Kp setting. Probably your control loop is missing some trivial part which is feedforward control path that would help a lot.

The picture below is representing a static characteristics where two world differ: the closed loop control theory (ger. Regulierung) and open loop theory (ger. Steuerung) The small letters refer to closed loop, which is superimposed on static characteristics in the working point.

enter image description here

These two worlds can be combined together by means of feedforward control path. The closed loop is trying to reject the disturbance, while the feedforward path is injected to the output of the controller. This feedforward path could be a static value as well dynamically changing value. For example if you know the speed of the copter blades "a priori" then you can fed this information right at the output. This would now be your working point as depicted in above characteristics.

enter image description here

\$\endgroup\$
1
\$\begingroup\$

Lots of oscillation is usually a clue that Kp is set too large. Try reducing it. More generally, you should be able to find good K values by following a tuning algorithm. There are quite a few, but the Ziegler–Nichols method is a popular choice.

One PID loop per axis should be enough, if it updates fast enough and is properly tuned.

\$\endgroup\$
0
\$\begingroup\$

I suspect that the control loop runs at an insufficient rate (the tens of hertz range), which is too slow to properly accomodate for the dynamics of the quadcopter.

Why do I think so? Because the PID_v1 library does everything with floating point numbers, which take forever (thousands of cycles per operation) to compute on your 8-bit AVR running at 16 MHz and without the aid of a floating point unit.

The MPU6050 driver code on your GitHub page is likewise completely implemented with floating point math, including trigonometric functions. I assume that you adapted said code, Mpu6050_Complementery.ino, into a library (mpu6050.h, not found on github) with few modifications.

Try to determine how many updates your control loop performs each second. For example:

int cycleCounter;
void setup()
{
    cycleCounter = 0;
    ... 
}
void loop()
{
    ... 
    ++cycleCounter;
    if(cycleCounter >= 100)
    {
        Serial.print("time after 100 cycles:");
        Serial.println(millis());
        cycleCounter = 0;
    }
}

If the cycle time is indeed the culprit, you need to optimise your code. I suspect that you could get a hundredfold (or better) improvement by getting rid of floating point math in general, and doing most of your processing with 8 or 16 bit integers. Using a lookup table for sine and cosine is also orders of magnitude faster relative to the slow but precise standard library functions.

An alternative is to switch to a board with a faster microcontroller that has hardware floating point support.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.