Skip to content

Commit 8b93279

Browse files
authored
Merge pull request #123 from Open-STEM/proportional-control
Intro to Proportional control
2 parents 4c224c7 + d69be2b commit 8b93279

7 files changed

Lines changed: 128 additions & 48 deletions

File tree

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,85 @@
11
Introduction to Proportional Control
22
====================================
33

4-
Introduction:
5-
-------------
4+
What is Proportional Control?
5+
-----------------------------
66

7-
While the on-off controller works, there are issues that can be solved using another type of controller.
7+
Imagine you're driving a car and you want to keep at a steady speed. If you're going too slow,
8+
you press the accelerator a bit, and if you're going too fast, you ease off. But instead of
9+
just fully pressing or fully releasing the accelerator (like an on-off switch), you adjust
10+
how hard you press based on how far off you are from your desired speed. That's the basic idea
11+
behind proportional control. The further you are from your target, the harder you try to correct it.
12+
If you're a little off, you make a small adjustment. If you're way off, you make a big one.
813

9-
The on-off controller is a **discrete** controller. This means that the controller has discrete states. It can be "on" or "off". It cannot be "half on" or "half off".
14+
Let's take this analogy further - you decide that the perfect cruising speed for your car ride is 70 mph.
15+
This speed represents your desired value or where you ideally want to be. In control theory, this is
16+
called the **setpoint**.
1017

11-
A **continuous** controller is one that can have any value. For example, the speed of a car is a continuous controller. It is not limited to "on" or "off".
18+
You get on the highway, and as you settle into your drive, you glance at your speedometer. It reads 65 mph,
19+
which is your current value. In control theory, this is called the **process variable**.
1220

13-
Continuous controllers are more effective and offer the user more control over their system, but are also easier to implement.
21+
Naturally, you recognize there's a difference between where you want to be (70 mph) and where you currently are
22+
(65 mph). This difference is the called the **error**, and in this case, it's 5 mph. It's easily calculated by
23+
the formula:
1424

15-
Basic Definitions + Steps of a Proportional Controller
16-
------------------------------------------------------
25+
.. code-block:: python
1726
18-
A proportional controller is the simplest type of continuous controller. It is also known as a P controller.
27+
error = setpoint - process_variable
1928
20-
Before implementing one, we need to define some terms and steps.
29+
Knowing the error isn't enough. How should you, the driver, react to it? This is where the concept of Proportional
30+
control comes into play.
2131

22-
**Target Value** - The value that you want to go to. In this example, let's set our target value to 5 cm
32+
Think of P control as your driving instinct. Instead of abruptly flooring the accelerator or immediately slamming the
33+
brakes, you adjust your speed based on your error: how far you are from your desired speed.
2334

24-
**Error** - The difference between the target value and the actual value. For example, if you want to go to 5 cm but you are currently at 3 cm, then the error is 2 cm.
35+
A measure called **control output** tells you much to adjust. It's calculated as:
2536

26-
**Control Effort** - The value that the controller outputs.
37+
.. code-block:: python
2738
28-
**kp** - The constant that you scale the error by to get the control effort. For example, if you want to go to 5 cm but you are currently at 3 cm, then the error is 2 cm. If **kp** is 0.5, then the control effort is 1 (0.5 * 2 cm).
39+
control_output = Kp * error
2940
30-
Now that we have defined some terms, let's go over the steps to implement a continuous controller.
41+
where Kp is a constant called the **proportional gain** and acts as a scaling factor for the error.
3142

32-
1. Define your target value
33-
2. Find the error
34-
3. Multiply the error by a constant **kp** to get the control effort
35-
4. Feed the control effort into your system
43+
If Kp is high, it's like you have a heavy foot and you'll accelerate hard even for a small error. You'll get there faster, but
44+
less precisely and you're more likely to overshoot.
45+
46+
On the other hand, if Kp is low, you're more of a cautious driver, gently pressing the accelerator for the same error. You'll
47+
get there more slowly, but at a much smoother pace.
48+
49+
Having the constant Kp allows you to tune your control system to your liking.
50+
51+
Note that this analogy breaks down somewhat. Imagine your current speed is *greater* than your desired speed. In this case,
52+
the error is negative. If you plug this into the control output formula, you'll get a negative control output. This means that
53+
a proportional controller will actually slow you down if you're going too fast, proportional to how far you are from your desired
54+
speed. So, you can imagine that a proportional controller is like a driver who's always trying to get to the speed limit, utilizing
55+
both the accelerator and the brakes.
56+
57+
Tuning Kp
58+
---------
59+
60+
The following graph shows proportional control in action.
61+
62+
.. image:: media/proportional.jpeg
63+
:width: 400
64+
65+
The blue line is the reference, and indicates the desired value. Red, green, and purple lines represent the current value over time
66+
when controlled by a proportional controller with different values of Kp.
67+
68+
With a low Kp, the red line is slow to react to the error, and the controller is sluggish. It takes a long time to reach the desired
69+
value, and it never quite gets there. This is called **underdamped** behavior.
70+
71+
With a high Kp, the purple line is quick to react to the error, and the controller is aggressive. It reaches the desired value quickly,
72+
but overshoots, causing the error to become negative. It then corrects itself, but overshoots again, and so on. This is called **overdamped**
73+
behavior, and results in oscillations around the desired value.
74+
75+
The green line is just right. It reaches the desired value quickly, and doesn't overshoot much. It's an important task to tune Kp so that
76+
the controller approaches the desired value as quickly and smoothly as possible.
77+
78+
Note: You'll find that, even with excellent tuning, a proportional controller often will either oscillate a little bit, or never quite reach
79+
the desired value. More advanced control systems like PID aim to minimize these issues, but they are out of the scope of this course.
3680

37-
Tips on finding "kp"
38-
--------------------
3981

40-
Finding the right value for **kp** is a bit tricky. If **kp** is too small, then the system will not respond fast enough. If **kp** is too large, then the system will overshoot the target value and oscillate around it.
4182

42-
When first finding a **kp** value, you want to "scale" an expected range of errors into an acceptable control signal.
4383

44-
For example, if your expected error ranges from 0-40 but your control signal ranges from 0-1, a "good" starting kp value would be 0.025 (1/40).\
4584

46-
From there, you can adjust the kp value to get the desired response after testing.
4785

17.7 KB
Loading
224 KB
Loading
34.6 KB
Loading
23.7 KB
Loading
14.4 KB
Loading
Lines changed: 65 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,87 @@
11
Implementing a Proportional Controller
22
======================================
33

4-
Now that you've learned about proportional controllers, let's implement one on the distance tracking activity
4+
Now that you've learned about how proportional controllers, let's implement one for our distance tracking activity,
5+
where we want to keep the robot some distance from the object in front of it using the rangefinder!
56

6-
Steps
7-
-----
7+
Defining Terminology
8+
--------------------
89

9-
The first step when creating a proportional controller is to define your target and error terms.
10+
Let's identify the terms we'll need to use in our code:
1011

11-
For our target, let's set it to 20 cm.
12+
**Set Point** or desired value: In this example, this is some set distance from the rangefinder we want the robot to be at.
13+
For this example, let's say 20cm.
1214

13-
In this case, the error is the difference between the target and the current distance from the object in front of the XRP.
15+
**Process Variable** or current value: We obtain our measured value from reading the rangerfinder value. This is
16+
:code:`rangefinder.distance()`.
1417

15-
Now, we need to define our proportional gain.
18+
Our goal is for our process variable (the rangefinder distance) to approach the set point (20 cm).
1619

17-
The first step of this is understanding the range of values that the error can take.
20+
Thus, our **error** is calculated as :code:`error = rangefinder.distance() - 20`. Note that :code:`error = 20 - rangefinder.distance()`
21+
is also "correct". The distinction in sign is simply whichever makes more sense for your application. Here, if we had an error of 30cm,
22+
we would want to drive forward 10cm, so we would want a positive error to make our motors spin forward.
1823

19-
The error can be any value between -20 and 20, meaning we're really close or really far.
24+
**Control Output**: In this case, this is our motor effort. This is because we want to drive with a speed proportional
25+
to the distance error. As a reminder for P control, this will be calculated as :code:`motor_effort = Kp * error`.
2026

21-
Then, the error would need to be scaled for an appropriate control signal (something from -1 to 1)
27+
**Kp**: This is our proportional gain. Though we will need to tune this value, we can guess a somewhat reasonable value
28+
by considering the range of values our error can take, and the domain of our control output. In this case, if we're 30cm away
29+
from the object, our error will be 10. We can guess that at this sufficient distance we will want to drive forward at a maximum
30+
effort of 1, as effort is restricted to the domain :math:`[-1, 1]`. Thus, we can guess that :code:`Kp = 1/10 = 0.1`. Of course,
31+
this isn't likely the final value that works best for your robot, but it's a good starting point.
2232

23-
Therefore, a good starting kp value would be 0.05.
33+
Implementing the Controller
34+
---------------------------
2435

36+
Now that we've defined our terms, let's write the code!
2537

26-
Finally, we need to set the speed of the XRP to our error times kp.
38+
Let's start by defining our proportional gain and our set point:
2739

28-
This is an example program that implements a proportional controller.
40+
.. tab-set::
2941

30-
.. error::
42+
.. tab-item:: Python
3143

32-
TODO add code to complete this
33-
34-
.. admonition:: Try it out
35-
36-
Now that you've designed a successful proportional controller, let's try some other values for kp.
44+
.. code-block:: python
45+
46+
Kp = 0.1
47+
desired_distance = 20
48+
49+
.. tab-item:: Blockly
50+
51+
.. image:: media/variables.png
52+
:width: 300
53+
54+
Next, we want to enter some sort of loop to continuously read our rangefinder value and update our motor effort from our controller output.
55+
56+
.. tab-set::
3757

38-
First, let's try making kp too small (0.01). What happens?
58+
.. tab-item:: Python
3959

40-
When kp is too small, the XRP doesn't react fast enough to the error, and it takes a long time to get to the target.
60+
.. code-block:: python
4161
42-
Next, let's try making kp too big (1). What happens?
62+
Kp = 0.1
63+
desired_distance = 20
64+
while True:
65+
error = rangefinder.distance() - desired_distance
66+
motor_effort = Kp * error
67+
drivetrain.set_effort(motor_effort, motor_effort)
68+
time.sleep(0.05)
4369
44-
The behavior you're seeing is called oscillation and happens when kp is too high.
70+
.. tab-item:: Blockly
71+
72+
.. image:: media/pcode.png
73+
:width: 500
74+
75+
Each iteration of the loop consists of the following steps:
76+
#. Read the rangefinder value to get the current distance
77+
#. Calculate the error
78+
#. Calculate the control output through Kp * error
79+
#. Set the drivetrain motor efforts to the control output
80+
#. Wait for a short period of time
81+
82+
This code should give us a working solution to maintain a set distance from the object in front of the robot!
83+
84+
.. admonition:: Try it out
4585

86+
Try moving the object in front of the robot and watch the robot attempt to maintain the set distance! What
87+
happens when you increase Kp? Decrease it? What value of Kp works best for your robot?

0 commit comments

Comments
 (0)