Controlling the Speed of the Motor

advertisement
Tutorial 7: Arduino, Motors and Controls
An electric motor is a device that converts electric current (AC or DC) into rotary motion. The
speed of a DC motor varies with the voltage applied to the terminals – higher voltage results in
higher speeds. This suggests a simple way to control the speed of a DC motor: simply raise the
voltage if we need more speed, or lower it if we want the motor to slow down.
Controlling the Speed of the Motor
In examining the Arduino board, however, we notice that there are no analog outputs. The digital
outputs can take on two states, 0V and 5V, but nothing in between. It would seem that we are
limited to turning the motor off, or running it at full speed – not a happy situation!
Luckily, we have another alternative: pulse-width modulation, or PWM. In PWM, we send voltage
pulses to the motor. If we want the motor to spin slowly, we send narrow pulses, and if we want
high speed, we send wide pulses. Note that in all cases the frequency of the pulses remains
unchanged, we vary the duty cycle of the pulses, as shown in the figure below.
V
V
t
Low duty cycle (12.5%)
t
High duty cycle (87.5%)
The pulses are sent to the motor at a very high frequency (approx. 490Hz, except for pins 5 and 6,
which are approx. 980Hz) such that the inertia of the rotor prevents noticeable fluctuations in speed.
The speed of the motor is then governed by the average voltage, which is given by
𝑉𝑎𝑣𝑔 = duty cycle · 𝑉ℎ𝑖
where Vhi is the voltage at the high state, or 5V. The Atmega328 makes PWM very easy to
implement. Simply use the analogWrite statement to send a digital output pin a value between 0
and 255 (8 bits) and the Atmega converts this to a series of high-frequency pulses with duty cycle
between 0 and 100%.
Powering the Motor
The LED circuits that we made last week required very low current. A motor requires much more
current, especially if we are using it to drive a load. If we hooked the motor directly to the Arduino
output, we would likely send too much current through the Atmega328, causing damage. Instead,
we will use the Arduino to switch on and off a power transistor, which can handle much higher
currents.
1
The circuit below shows one way of driving a motor with a transistor. The current is switched on
and off by the (very small) current flowing into the base of the transistor. A diode is connected
between the collector and emitter to prevent reverse voltages from developing when the motor
stops suddenly. Note that one of the motor leads is connected to 9V (the voltage delivered by the
wall-wart), which is available from pin Vin on the Arduino board.
9V
(Vin)
PM
From pin 3
R1
We will use the TIP102 power transistor in this laboratory, which can handle up to 8A of current
flowing through its collector. Because it is actually two transistors in one package, it has a terrifically
high current gain (approx. 1000). Thus, we need only supply a small amount of base current to be
able to switch on high currents to the motor.
Let us aim for a base current of 1mA. According to the datasheet, the voltage drop between the
base and the emitter is 2.8V. The voltage across the resistor is then (5V - 2.8V = 2.2V). The current
flowing into the base is then
𝑖𝑏 =
2.2𝑉
𝑅1
For a base current of 1mA, we should choose a resistor of
𝑅1 =
2.2𝑉
= 2.2𝑘Ω
1𝑚𝐴
The Code
The code fragment below reads the voltage input from analog input 0 (the potentiometer) and sends
a PWM signal to digital output pin 3. The duty cycle of the PWM signal is proportional to the
voltage read by analog input 0. Since the PWM requires a value between 0 and 255 (8 bits), we must
divide the analog input (10 bits) signal by 4. The nice part about PWM in the Atmega chip is that
the PWM signal will continue to be sent to the digital output pin even when the processor is busy
doing something else (like writing to the serial port).
2
Notice also that we are defining the potentiometer pin to be number 14. Arduino numbers the
analog pins 14-19 internally (the digital pins are numbered 0-13).
// Motor drive using PWM
// This program uses a potentiometer to
// control the speed of a motor.
int potValue;
int potPin = 14;
int PWMPin = 3;
void setup() {
Serial.begin(9600); // initialize serial communication
}
void loop() {
potValue = analogRead(potPin); // read value from analog input 0
Serial.println(potValue);
// send value through serial port
delay(10);
// wait for ADC to stabilize
analogWrite(PWMPin,potValue/4);
}
Challenge 1:
Build a circuit and write an Arduino program to control the speed of the fan using the
potentiometer. Display the potentiometer reading on the Serial Monitor.
9V
(Vin)
PM
From pin 3
R1
C1
Simple Filtering
You probably noticed that the fan motor makes an awful whining noise, especially at low speeds.
This occurs not because the fan is cheap (which it is!) but because of the constant turning on and off
from the electrical pulses being sent by Arduino. In fact, if you measured the noise, you would find
that its frequencies correspond to the PWM frequency, plus several harmonics. It would be nice to
smooth out the pulses, so that the transistor receives a steady (or almost steady) voltage from
Arduino.
3
Luckily, there is a simple fix for this problem – a filter circuit. The diagram above shows that by
adding a capacitor we can create a first-order lowpass filter. Remember that the name indicates that
it passes low frequencies through, while attenuating high frequencies. In the configuration above, the
cutoff frequency is calculated as
𝑓𝑐 =
1
2𝜋𝑅1 𝐶1
If we choose 10μF for the capacitor (and keeping 2.2k for the resistor), the cutoff frequency is
7.2Hz, which is well below the 490Hz PWM frequency. The only downside to this filter is that the
fan may be a little more sluggish in responding to our commands. Try adding the capacitor and
observe the difference in noise and responsiveness.
On-Off Control
In the preceding exercise, you controlled the speed of a DC motor through Pulse-Width
Modulation. When you wanted the motor to spin faster, you rotated the potentiometer and Arduino
sent pulses of longer duration to the motor. If you wanted to, you could create a plot of
potentiometer position vs. fan speed, so that another user could make the fan spin at a desired speed
simply by rotating the potentiometer to the correct position. A schematic of this control scheme is
shown in the figure below. It is called “open loop” control, because there is no sensor to tell if the
fan is actually spinning at the desired speed.
Potentiometer
(setpoint)
Analog Input
(ADC)
Digital Output
(PWM)
Motor/Fan
System
Fan speed
(Output)
Arduino
The main problem with this type of control happens when there is a long-term disturbance in the
fan system. For example, a piece of paper might partially block the fan, which would slow it down.
In this situation we would like Arduino to send more power to the fan, but Arduino has no way of
knowing that the fan has slowed down.
To make our system more robust, we might choose to include a speed sensor, or tachometer. If we
feed the tachometer signal back into the Arduino, it will know if the fan is moving too fast or too
slow, and can be programmed to respond accordingly. The simplest type of response is called “onoff” control. In on-off control, if the fan is moving too slowly, we apply full power, and if the fan is
moving too quickly, we shut power off. A block diagram of on-off control is shown below.
4
Potentiometer
(setpoint)
+_
Error
Positive error
turn on motor
Negative error
turn off motor
Motor/Fan
System
Fan speed
(Output)
Optical
sensor
Tachometer
Arduino
There is an important new feature in the diagram above: the summation block. In this block, the
setpoint and tachometer signals are subtracted from each other – the result is the error. In on-off
control, a positive error indicates that the fan is moving too slowly, and we should apply full power.
Conversely, a negative error means the setpoint is lower than the actual speed, and we should cut
power to the fan.
Test tube
Fan
33 Resistor
(heater)
LM34
The Temperature Control Project
The diagram above shows the system we wish to control. In a sense, it is identical to the
temperature control system in your house: if the temperature is too low, the heat is turned on, and if
it is too high, a cooling system is applied (in this case, a fan). The heat is supplied by a 33Ω resistor
rated at 1/4 W.
Since the wall-wart power supply is rated at 7.5V, and there is a 2V drop across the transistor, we
can expect
5.5V
= 167mA
33Ω
to flow through the resistor. This translates into (167mA)2 (33Ω) = 0.92W of power, which is
more than the 1/4 W for which the resistor is rated. In other words, the resistor will get hot when
power is applied (don’t touch it!) Power to the resistor is controlled by another transistor, in the
same way we control power to the fan motor (see figure below).
5
7.5V
(Vin)
LM34
33 , 1/4W resistor
2k
From digital
output pin
Gnd
V+
Vout
We measure temperature using the LM34 “Precision Fahrenheit Temperature Sensor”. The LM34 is
a sensor whose voltage output is linearly proportional to temperature, with a scaling factor of
10.0mV/°F. Thus, at 72°F the LM34 outputs a voltage of 0.72V. The LM34 is wired as shown in
the diagram at right. The formula for temperature conversion in Arduino is then
𝑇 (℉) = (
𝑉𝑓𝑠 (V) 1000mV
℉
)(
)(
) · 𝑁𝑎
1023
V
10mV
where Vfs is the full-scale voltage of the analog input (5V by default, but see below) and Na is the
number returned by the ADC (between 0 and 1023).
The Analog Reference Pin
We expect that the temperature inside the incubator will vary across a limited range; say between 50°
F and 120° F. For the LM34, this corresponds to an output voltage of between 0.5V – 1.2V, which
is only a small fraction of the 0-5V range of the analog input. Recall that the range of 0-5V is
represented by the numerical range 0-1023 after conversion in the ADC. The range 0.5V – 1.2V will
be converted to numbers between 102 and 246 by the ADC, which gives only
246 − 102 = 144
possible values for temperature between 50° and 120°F.
T
t
The result of this is called quantization error. Quantization error occurs when an analog signal is
converted into a limited range of digital values, as shown in the figure above. This occurs for two
reasons, typically. First, an inexpensive ADC may only have 6 bits (64 values) or so to represent the
6
full analog range. This does not pertain to our situation, since we have a full 10-bit converter.
Second, we may only need a limited part of the full analog range; e.g. 0.5-1.2V out of a full range of
0-5V.
3.3V
R
Analog Reference voltage
32k
Arduino
The solution to this problem is to use a different analog reference for full range. Luckily, the Atmega
chip has a built-in analog reference pin, which can be used to specify a different full-scale analog voltage
than the default 5V. The way this works is shown in the diagram above. The Atmega chip has an
internal 32k resistor; the analog reference voltage is taken at the junction between it and a usersupplied external resistor. We use the voltage divider law to find the analog reference:
𝑣𝑟𝑒𝑓 =
32kΩ
· 3.3V
𝑅 + 32kΩ
For example, if we use R = 47k, then the analog reference voltage would be 1.34V. In the Arduino
code we use the statement
analogReference(EXTERNAL)
to tell Arduino that 1.34V should now be converted to 1023, instead of the default 5V. As it turns
out, this reference voltage will work well for the LM34, since it allows for a maximum temperature
of 134°F – slightly higher than what we expect for the incubator. When you connect your own
resistor, make sure to measure the actual AREF voltage so that your program is calibrated correctly.
Challenge 2: The Incubator
Build the “incubator” as shown in the diagram at the middle of page 5. Write a program that keeps
the inside of the incubator between 80°F and 82°F. Display the temperature (in °F) using the Serial
Monitor. Answer the following questions (verbally).
1. What is the overshoot and undershoot of your system?
2. How long does the air temperature keep rising after you turn off the heat?
3. Why does it do this?
Construction Hints
1. Use a “star ground” approach for building this circuit, especially for the ground pin of the
LM34. That is, connect the ground pin of the LM34 directly to a GND pin on the Arduino
7
board, instead of through a ground bus on the breadboard. Since the ground bus on the
breadboard will be handling large currents (for the fan and resistor) there will be a voltage
drop between the ground bus and the GND pin on the Arduino board – the ground bus will
not remain exactly at ground! Since the temperature reading is tied to the voltage between
the middle and ground pins on the LM34, a nonzero ground pin will give erroneous
temperature readings. The star ground approach is commonly used in hi-fi systems for the
same reason.
2. Use CAT5 wires to make the connections on the breadboard, and make everything as neat as
possible. Since this is a more complicated circuit than before, troubleshooting will probably
be necessary. Troubleshooting a “spaghetti circuit” is very difficult and time-consuming!
Parts List
Resistors
100Ω, 1/2W (1)
2.2k (2)
47k (1)
potentiometer (1)
Capacitors
10μF electrolytic (1)
Semiconductors
1N4148 small signal diode (2)
TIP102 Darlington transistor (2)
LM34 temperature sensor (1)
Hardware
5V computer fan (1)
small test tube/beaker (1)
“wall wart” power supply (1)
Arduino UNO (1)
breadboard (1)
jumpers and CAT5 wire
8
Download