When I joined Udacity’s Flying Car Nanodegree program team, one of my first assignments was to update the controls module of the program. Given the program’s focus on helping you develop the skills to build an autonomous aircraft system, I was excited to work on this module, as controls is the area where you make a drone physically move. Given a path, it provides the vehicle with all the necessary information on how to activate rotors to get the desired effect in a physical, continuous space.
In this post, we’re going to discover how a PID controller works on a drone by focusing more on the concepts as opposed to the math behind it.
In a drone, the PID controller is part of the flight controller software that reads data coming from sensors and calculates how fast the motors should spin in order to maintain the speed and position of the drone. The goal of the PID controller is to correct any errors. The PID controller is a control loop feedback mechanism, and it continuously calculates an error value as the difference between a desired setpoint and a measured process variable; when it identifies an error, it applies a correction based on proportional, integral, and derivative terms (hence the name PID); this gives the controller its name.
Let’s start to see how the PID controller works for a quadrotor. We will approach every single parameter independently, so we can see how each affects the drone behavior.
In this example, we want to build a controller that allows us to control the altitude of the drone (this is a one-dimensional world). The simplified diagram for this system is as follows:
The input to our system is the thrust we can command to the propellers (generated by the propellers’ speed), and the output is the altitude from the ground. Conversely, the input of the controller is the measured error, and the output is the thrust that the controller signals to the drone.
The error in our example is the difference between the actual (present) altitude and the target altitude.
Our starting state sees the drone on the ground, and our goal is to lift the drone up to reach the desired (target) altitude.
To compensate for the error, we will input a thrust (derived from the propellers’ speed), which will allow the drone to lift off and therefore reduce the error.
On the other hand, let’s see what happens when the drone reaches the target altitude:
In this case, since the error is zero, the command to the drone will demand zero thrust, and therefore will stop the propellers’ speed and cause the drone to fall.
As soon as it starts falling, the error increases and the controller will send a signal to increase the thrust, to compensate for that error between the current and the target altitude.
Let’s take a step further and add the goal of hovering the drone to the target location.
Hovering implies a lift thrust equal to the weight of the drone.
Let’s see how the proportional controller influences the behavior of the drone. Let’s assume that the equilibrium (hovering state) is reached when the thrust is equal to 100N.
If we pick a proportional gain (Kp) equal to 1, then the commanded thrust would be equivalent to 100 (error = 100; Kp=1 => thrust = 100*1 = 100N) and the drone would continue to hover at ground level.
If we increase Kp to 5, then the drone will hover at an altitude of 80m, since the drone will reach the commanded thrust when the error is equal to 20m.
We can see that the more we increase Kp, the smaller the error will be.
Unfortunately, this error won’t ever go away. No matter how big Kp is, we won’t be able to get the error to zero. This is obviously not ideal.
So far, the proportional gain hasn’t helped our drone reach the target altitude. It certainly got us closer to it, but it still carries a constant error (called “steady state error”).
The proportional controller uses only present information. We were comparing actual altitude with target altitude. But to help us get rid of this constant error introduced by the proportional gain, we can use an integrator path into our controller.
The integrator path (identified by the integral-gain Ki) looks, instead, at information coming from the past. Thus, the integral part keeps in memory what has happened before.
This is how our system diagram looks like with these two controllers running in parallel:
The integrator controller sums up the input signal (the error in our case) over time, and it adjusts the system to counter the accumulation of the error.
A situation of “steady-state” error causes a residual error between current and actual position. This bias keeps the drone from flying at exactly the target altitude, but always a bit off from it.
The integral component looks at the past error, and tries to reduce the accumulated error by signaling an increase of thrust. The more time we spend below our goal, the more thrust will be applied.
While the proportional term adjusts the output based on the present error, the integral term adjusts the output based on past errors.
Therefore, if the drone is flying below the target altitude, then the integral component will provide a thrust higher than 100N (the equilibrium thrust). To remove the excess of thrust, we will need to have a negative error so that the accumulated sum of error lowers, and the integral component sends a signal to slow down the thrust. But, to get a negative error, the drone has to overshoot the target, then undershoot a bit until it finally reaches the target altitude.
Although a controller with proportional and integral components can help us eventually reach the target altitude, this overshooting is not ideal, and should be minimized as much as possible.
It would be great if we had something that could predict the future and tell us how fast we will be approaching the goal in order to regulate it! That’s what the derivative term of our controller does!
The derivative term measures the error’s rate of change. Therefore, it sees how fast the error is increasing/decreasing.
If the error is decreasing quickly, then the rate of change is negative (think about the derivative as the slope of the curve), and the output from our derivative term of the controller is a negative output. This means that it lowers the thrust (essentially the propellers’ speed).
In this case, looking at the rate of change of the error helps the controller determine how the drone is approaching the goal. The controller then slows the drone down appropriately to prevent overshooting.
Now that we have seen how each component works, we can redesign the final system diagram as follows:
As we can see, the proportional, integral and derivative components affect the output of the controller and their contribution can be adjusted by the gain terms (Kp, Kd, Ki).
Therefore the next step would be to fine-tune these three parameters in order to allow the drone to restore from current speed to the desired speed in an optimal way, without delay or overshoot.
If you want to learn more about controls for drones, enroll in our Flying Car Nanodegree program. The program covers topics like estimation, control, planning, quadrotors, fixed-wing aircraft, and more. The focus is on developing the skills to build an autonomous aircraft system. This means a unique emphasis on planning and autonomy for three-dimensional mobility, involving hands-on projects in simulation, with the opportunity to port your code to real drones!
Explore other programs in Udacity’s School of Autonomous Systems:
- Robotics Software Engineer Nanodegree Program
- Self-Driving Car Engineer Nanodegree Program
- Intro to Self-Driving Cars Nanodegree Program (an introductory program to the Robotics field in general)
See you in the classroom, and in the skies!