Pulse Width Modulation (PWM) is the technique used from a digital source to simulate an analog output.
For example, imagine that you want to dim an
led
from a digital device, to make it look like it is glowing.
The digital device only has pins that can take 2 values: 0
or 3V3
.
0
means that the led will be off, 3V3
means it will be on, at 100% of its brightness.
In short, it is on or off, and there is nothing in between.
But here is an idea to work around that issue:
To show it at
50%
of its brightness, the idea is to turn it off 50% of the time, and on 50% of the time.
To show it at
25%
of its brightness, it will be on 25% of the time, and off 75% of the time.
If the on-off cycles are short and fast enough, a human eye will no be able to see them, it will only have the illusion of the resulting brightness.
A human eye cannot make the distinction between images separated by less than one 10th of a second. That is why the movies are shot at 24 images per second, so you cannot tell the difference between the frames.
This technique is call Persistence of Vision (POV).
The #1 parameter of PoV is the human retina. To have an idea of how much it is important, just put your cat in front of a TV, and see how much he/she reacts. To a cat, it might just be a fuzzy screen...
- The early movies - like Charlie Chaplin's silent ones - were shot at 16 images per second, fast enough to induce POV. They were later projected by faster projectors - 24 frames per second. That is why the characters seem to move faster. They were originally moving normally.
Here are examples of PWM applied to POV:
The Raspberry PI does not have analog pins, we need to use Pulse Width Modulation to simulate analog values, a servo is an analog device.
We use for that the method
setPWM(channel, 0, pulse)
, that will eventually write to the registers
of the device.
An instruction like
setPWM(channel, 0, pulse)
means:
- On channel
channel
(0
to15
on thePCA9685
) - in each cycle, turn the power
on
between0
andpulse
.
pulse
has a value between 0
and 4095
, that is 4096
distinct values, 4096
is 212, the PCA9685
is a 12 bit device.
The frequency
The frequency is provided in Hertz (Hz). A frequency of 60 means 60 cycles per second.At 60 Hz, a cycle will be
1 / 60
second, which is 0.01666666
second, or 16.66666
milli-second (ms).
The pulse
For each of the cycles set above by setting the frequency, we need to determine theint
value,
between 0
and 4095
, corresponding to the pulse in milliseconds we want to simulate with PWM.
In the class
i2c.servo.pwm.PCA9685.java
, this is done in this method:
public static int getServoValueFromPulse(int freq, float targetPulse) { double pulseLength = 1_000_000; // 1s = 1,000,000 us per pulse. "us" is to be read "micro (mu) sec". pulseLength /= freq; // 40..1000 Hz pulseLength /= 4_096; // 12 bits of resolution. 4096 = 2^12 int pulse = (int) Math.round((targetPulse * 1_000) / pulseLength); // in millisec if (verbose) { System.out.println(String.format("%.04f \u00b5s per bit, pulse: %d", pulseLength, pulse)); } return pulse; }The cycle length (in ms) obviously depends on the frequency.
The pulse required for the servo to work is emitted once per cycle.
Example
As an example, let us calculate for a60 Hz
frequency the pulse
value to send to setPWM(channel, 0, pulse)
for a 1.5
millisecond PWM:
- 1 cycle has a duration of
1 / 60
second, or16.66666
milliseconds. - each cycle is divided in
4096
slots, we can say that4096
bits =16.6666
ms. - the solution is provided by a rule of three:
value
=4096
* (pulse
/16.66666
), which is368.64
, rounded to369
.
A comment about servos' compliance and reliability
Theoretically, servos follow those rules:Pulse | Standard | Continuous |
---|---|---|
1.5 ms | 0 ° | Stop |
2.0 ms | 90 ° | FullSpeed forward |
1.0 ms | -90 ° | FullSpeed backward |
0.5 ms
and 2.5 ms
.
Before using them, servos should be calibrated. You can use the class
i2c.samples.IntercativeServo.java
can be used for that,
you set the pulse values interactively, and you see what the servo is doing.
$> ./inter.servo Connected to bus. OK. Connected to device. OK. freq (40-1000) ? > 60 Setting PWM frequency to 60 Hz Estimated pre-scale: 100.72526 Final pre-scale: 101.0 Servo Channel (0-15) : 1 Entry method: T for Ticks (0..4095), P for Pulse (in ms) > p Enter 'quit' to exit. Pulse in ms > 1.5 setServoPulse(1, 1.5) 4.0690 μs per bit, pulse:369 ------------------- Pulse in ms > 0.5 setServoPulse(1, 0.5) 4.0690 μs per bit, pulse:122 ------------------- Pulse in ms > 0.6 setServoPulse(1, 0.6) 4.0690 μs per bit, pulse:147 ------------------- Pulse in ms > 2.4 setServoPulse(1, 2.4) 4.0690 μs per bit, pulse:589 ------------------- Pulse in ms > 2.5 setServoPulse(1, 2.5) 4.0690 μs per bit, pulse:614 ------------------- ... etc.Once you have determined the appropriate min and max values, you also have the
int
values
to feed the setPWM
with.
Some links:
- https://github.com/OlivierLD/raspberry-pi4j-samples/blob/master/I2C.SPI/PWM.md
- http://raspberrypi.lediouris.net/servo/readme.html
- POV at work
No comments:
Post a Comment