Good day,

I am a student currently working on an autonomous quadcopter project, specifically the stabilization part as of now. I am using a tuned propeller system and I also already considered the balancing of the quadcopter during component placements. I had been tuning the PID's of my quadcopter for the past 3 1/2 weeks now and the best I've achieved is a constant angle oscillation of the quadcopter by +-10 degrees with 0 degrees as the setpoint/desired angle. I also tried a conservative 7 degrees setpoint with the same results on the pitch axis.

As of now my PID code takes in the difference of the angle measurement from the complementary filter ( FilteredAngle=(0.98)*(FilteredAngle + GyroAngleVel*dt) + (0.02)*(AccelAngle) ) and the desired angle.

enter image description here

I have read somewhere that it is IMPOSSIBLE to stabilize the quadcopter utilizing only angle measurements, adding that the angular rate must be also taken into consideration. But I have read a lot of works using only a single pid loop with angle differences (Pitch Yaw and Roll) as the input.

In contrast to what was stated above, I have read a comment from this article (https://www.quora.com/What-is-rate-and-stabilize-PID-in-quadcopter-control) by Edouard Leurent that a Single PID control loop only angle errors and a Cascaded PID loop (Angle and Rate) that utilizes both angle errors and angular velocity errors are equivalent Mathematically.

If I were to continue using only the Single PID loop (Angle) method, I would only have to tune 3 parameters (Kp, Ki & Kd).

But if I were to change my code to utilize the Cascaded Loop (Angle and Angular Velocity),

  1. Would I have to tune two sets of the 3 parameters (Kp, Ki & Kd for angle and Kp, Ki & Kd for the angular velocity)?
  2. Would the cascaded PID control loop give better performance than the single PID control loop?
  3. In the Cascaded Loop, is the set point for the angular velocity for stabilized flight also 0 in deg/sec? What if the quadcopter is not yet at its desired angle?

Thank you :)

  • $\begingroup$ I am also using a 100Hz sampling rate for my control loop $\endgroup$ Jan 15, 2016 at 7:16
  • 2
    $\begingroup$ Regarding your cascading PID controllers, I would ask you to consider a thought experiment. What if you commanded angular position to be a constant value, but also commanded angular velocity to be a constant, non-zero value? Would the system obey the angular position and set velocity to zero, or would it obey angular velocity and allow angular position to move to infinity? You can't control both, you can only control one and the other will do what the controlled signal requires. PID controllers use position because velocity can be limited (not controlled) by PID gains - damping, settling, etc. $\endgroup$
    – Chuck
    Jan 15, 2016 at 15:43
  • 1
    $\begingroup$ just keep trying that's the way I fix things. $\endgroup$
    – hunt
    Jan 15, 2016 at 17:32
  • $\begingroup$ This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient reputation you will be able to comment on any post. - From Review $\endgroup$ Jan 15, 2016 at 18:33
  • 1
    $\begingroup$ That would wind up with the controllers "fighting". The only way to get to zero position error is... to get there. That is, there has to be some speed approaching zero in order to ever arrive at zero. If you just switch controllers the moment you hit zero, then you'll be acting to stay at zero speed despite the fact that inertia will pull you past zero angular error. $\endgroup$
    – Chuck
    Mar 19, 2016 at 15:20

2 Answers 2


It is possible to stabilize a quadcopter using only angle measurements in a single loop pid. However it is easier to stabilize a quadcopter using a cascaded PID controller. Yes you are tuning more parameters. Firstly you tune first the inner loop rate PID controller using the gyroscope's (the fast sensor, but drifts) angular rate readings then tune the outer loop stabilize PID using an angle setpoint and angle measurements from the sensor fusion of the angle readings from both the accelerometer and the angles integrated from the angular velocity readings from the gyroscope. I found that it was the easiest way to achieve stable flight coupled with my now current control loop rate of 530Hz.

Other related helpful questions with answers:

  1. PID output does not reach setpoint precisely enough

  2. Need help for a quadcopter PID


  1. https://www.quora.com/What-is-rate-and-stabilize-PID-in-quadcopter-control

How are you managing to get any angle from the code you posted, filter = (0.98*gyro*dt + 0.02*accel)? Gyro output is in $\mbox{deg}/s$, where acceleration is $\mbox{deg}/s^2$. When you multiply gyro times time, you get an angle unit, $\mbox{deg}$, (not an angle, see below) but then you're adding that to an acceleration, which doesn't have the correct units.

Also, for the gyro portion, you're just getting to the correct units. Angular position is the integral of angular velocity, meaning that you have to sum those gyro*dt segments to accumulate an angle. Otherwise all gyro*dt gives you is the angle that you moved in the last time interval dt.

Can you check if your code matches what you wrote in the question and then update the question?


My question wasn't about how you're calculating the accel values, but instead about how you're implementing the filter. In your update, the filter calculation is still incorrect.

Now, instead of getting your gyro output to angular position units, you've gone the other way and gotten to angular acceleration units. Worse, you're also now accumulating that acceleration, which doesn't make sense.

What you should have somewhere in the initialization portion of your code is:

gyro<AXIS>Position = 0;
accelerometer<AXIS>Position = 0;
accelerometer<AXIS>Velocity = 0;

Then, in your loop, update the accelerometer-based angular velocity by numerical integration:

accelerometer<AXIS>Velocity = accelerometer<AXIS>Velocity + accel<AXIS>*dt;

Next, numerically integrate the gyro angular velocity and the accelerometer-based angular velocity:

accelerometer<AXIS>Position = accelerometer<AXIS>Position + accelerometer<AXIS>Velocity*dt;
gyro<AXIS>Position = gyro<AXIS>Position + gyro<AXIS>*dt;

Finally, you can fuse those two readings with your complementary filter:

blend = 0.98;
filter = blend*gyro<AXIS>Position + (1-blend)*accelerometer<AXIS>Position;
  • $\begingroup$ I am sorry, I have corrected the code for the Complemetary Filter used and also updated what is currently written on the question. $\endgroup$ Jan 15, 2016 at 15:10
  • $\begingroup$ The accelerometer angles were computed from the accelerations obtained from the accelerometers using the following formulas: For the Roll: float accelRoll = atan2f(-accelRealX, accelRealZ)*180.0F/PI; $\endgroup$ Jan 15, 2016 at 15:12
  • $\begingroup$ For the Pitch: float accelPitch = atanf((accelRealY)/sqrt(pow(accelRealX, 2) + pow(accelRealZ, 2)))*180.0F/PI; $\endgroup$ Jan 15, 2016 at 15:12
  • $\begingroup$ For the Yaw: float numeratorYaw = magRealZcos(accelRollPI/180.0F) - magRealYsin(accelRollPI/180.0F); float denominatorYaw = magRealXcos(accelPitchPI/180.0F) + magRealYsin(accelPitchPI/180.0F)*sin(accelRollPI/180.0F) + magRealZsin(accelPitchPI/180.0F)*cos(accelRollPI/180.0F); float accelYaw = atan2f((numeratorYaw)/(denominatorYaw)) *180.0F/PI; $\endgroup$ Jan 15, 2016 at 15:13
  • 1
    $\begingroup$ @user123456098 - You can delineate code on this SE site by either putting it on its own line with four spaces before it, or delineate it in-line using the grave accent (`) on either side of the text. $\endgroup$
    – Chuck
    Jan 15, 2016 at 15:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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