This part has a page of its own, with a note on using it and a circuit to try: the part page.
The signal on PWM is not PWM in the dimming sense; the duty cycle means nothing.
It is a pulse width, repeated fifty times a second. By default the part reads it
the way the Arduino Servo library writes it: 544 microseconds puts the horn at
0 degrees, 2400 microseconds at 180, and 1472 microseconds, which is what
write(90) sends, in the middle.
Pins
| Pin | What it does |
|---|---|
GND |
Ground, brown wire. |
VCC |
Supply, red wire. |
PWM |
Signal, orange wire: a pulse width, not a duty cycle. |
Properties
min_pulse / max_pulse: the pulse widths for the two ends of travel, 544 and
2400 microseconds by default, the Arduino Servo library's MIN_PULSE_WIDTH and
MAX_PULSE_WIDTH. range: degrees of travel, 180 by default. speed: how fast
the horn moves towards a new angle, 600 degrees per second.
| Sketch | Pulse | Horn, with the defaults |
|---|---|---|
write(0) |
544 us | 0 degrees |
write(90) |
1472 us | 90 degrees |
write(180) |
2400 us | 180 degrees |
A servo that wants another window, 1000 to 2000 microseconds say, is
attach(pin, 1000, 2000) in the sketch and the same two numbers in
min_pulse and max_pulse, so the two agree on where each angle is.
idle_ma / moving_ma: the supply current, 10 and 150 mA at 5 V.
mode: positional or continuous (below). rpm, neutral and dead_band
are for the continuous kind only.
Models
model picks a servo by name, or custom (the default) for the settings below it.
A named model sets the speed, the mode, the rpm and the dead band from its maker's
page; the pulse range and range stay yours, because they are what attach() says.
| Model | What it sets |
|---|---|
SG90, SG92R |
0.1 s per 60 degrees at 4.8 V, a 10 µs dead band |
MG90S |
0.10 s at 4.8 V and 0.08 s at 6 V, following the supply between, a 10 µs dead band |
FS90R, SG90-360 |
continuous rotation, 110 rpm (the 4.8 V figure), 1500 µs stop |
The MG996R is its own part. The MG995, the DS3218 and the MG996R's 360 degree version are not here: no maker's figures for them could be read.
What the model gets right
The part is a stopwatch on one pin and a horn that walks towards the angle the
stopwatch names: a rising edge starts the clock, a falling edge stops it, a width
past either end of the min_pulse to max_pulse window is that end (the horn
stops against its end stop), a pulse longer than 3 ms is treated as noise and
ignored, and with no pulses at all the horn stays exactly where it is, the way a
real servo does when its signal wire falls off. speed matches the datasheet's
0.1 seconds per sixty degrees. A servo that only sweeps 120 degrees, or one set up
for 1000 to 2000 us, is those three numbers changed and nothing else.
Supply current
Between VCC and GND the servo is a load, so a bench supply with a multimeter
in its lead (dca) reads what the servo draws: about 10 mA with the horn still
and about 150 mA while it moves, both quoted at 5 V and following the supply
from there. idle_ma and moving_ma set the two figures (SG90 sheets give 5 to
10 mA idle and 100 to 250 mA running). The load changes only when the horn starts
or stops moving. It applies when a bench supply (psu, a battery) feeds the
servo; on a board's own 5V pin the servo behaves as before.
What it does not model
The stall current (about 650 mA for an SG90 with the horn held against a stop):
nothing here can hold the horn, so a servo pinned at the end of its window just
arrives and goes idle. Nor the start-up surge, nor a brown-out of the board that
powers it: Mokxi's rails have no impedance to sag. Below 4 V across VCC/GND
the servo does not move at all.
No torque, no load and no overshoot. The horn walks to its target at a constant
600 degrees a second and stops dead. There is no acceleration, no settling, no
hunting around the target and no gear backlash. A real SG90 ignores changes
under about 10 microseconds of pulse width, the datasheet's dead band width. On
custom there is no positional dead band, so a commanded angle is always reached. The
named models ignore a change of 10 microseconds or less, about a degree on the default
window, so a very small step can leave the horn where it was. The 0.1 seconds per sixty degrees is the datasheet's unloaded figure
and applies here whatever is on the horn, because there is nothing on the horn.
The stopwatch is also more forgiving than a real servo's: the horn is updated every 20 ms whatever the pulse rate is, a pulse longer than 3 ms is discarded rather than treated as a fault, and a gap in the pulse train is simply held rather than released.
Code
The Arduino library's own calls work as they are on every board that compiles in the browser:
#include <Servo.h>
Servo myservo;
void setup() {
myservo.attach(9);
}
void loop() {
for (int pos = 0; pos <= 180; pos++) {
myservo.write(pos);
delay(15);
}
}
Servo.h is Mokxi's own, on the same driver as mokxi_servo.h, with the
upstream library's widths. attach(pin) uses 544 to 2400 microseconds and
attach(pin, min, max) sets another window; write(angle) spreads 0 to 180
across the window, so write(0), write(90) and write(180) send 544, 1472
and 2400 microseconds; writeMicroseconds() passes a width straight through,
held to the attached window; and read() gives the angle back. One driver
serves every board, so the numbers are the same on the AVR boards, the Pico,
the STM32 boards, the SAMD21 XIAO and the Uno R4 alike.
One thing differs from the upstream library: each write() sends one pulse
rather than starting a timer that pulses for ever. The part holds the last width
it was sent, as a real servo does with nothing pushing on the horn. On the
bench, under load, call myservo.refresh() from loop() to keep the frame
coming.
ESP32Servo.h is the same class, for ESP32 tutorials, with ESP32Servo's numbers:
attach(pin) uses its DEFAULT_uS_LOW and DEFAULT_uS_HIGH, 544 and 2400
microseconds, and attach(pin, min, max) holds the window to 500 to 2500.
Projects saved before the window changed to 544 to 2400 open with it: a servo
or robot arm that still had the old 1000 and 2000 microsecond defaults is moved
onto the new ones, so write() lands where it says. A sketch that times its
own pulses for a 1000 to 2000 microsecond servo now turns the horn a shorter
way; set the servo's min_pulse and max_pulse back to 1000 and 2000 for it,
and that choice is kept.
Continuous rotation
Set mode to continuous and the part is the other servo in the parts bin, the
FS90R kind: the same case and wires, with the end stops removed and the position
sensor replaced by a fixed middle. A pulse now names a speed. The servo's
neutral, 1500 microseconds by default, is stopped; 500 microseconds either side
of it (1000 and 2000) is full speed one way and the other, rpm (110 by default,
the FS90R's figure at 4.8 V); in between is in proportion, and further out, as far
as 544 and 2400, stays at full speed. A wider pulse turns it counterclockwise. The
probe is then the speed in rpm, positive counterclockwise, and the horn spins on the
canvas.
Why write(90) stops it. With the Arduino library's widths, write(90) sends
1472 microseconds, not 1500. A real continuous servo stops anyway, because it has
a stop zone around its neutral, set by the factory trim (the small trimmer some
have is for moving it). The part models that as dead_band: any pulse within 35
microseconds of neutral, 1465 to 1535 by default, reads as stopped. 1472 is 28
microseconds short of neutral, inside the band with room for the Uno's 4
microsecond timing step. write(85) (1420 microseconds) creeps one way and
write(95) (1523) stays stopped; set dead_band to 0 to see how a servo with no
stop zone at all creeps at write(90), or set neutral to match a servo trimmed
another way.
A real one stops within a frame or two when the pulses stop. This one keeps the
last speed it was sent, because Mokxi's Servo library sends one pulse per
write(), and write(180); delay(2000); means two seconds of turning. The
neutral, the dead band and the full-speed pulse width vary from servo to servo on
the bench, which is why some have a trimmer; here they are exact.
Common mistakes
Powering several servos from a board's 5V pin and expecting it to sag. The supply current shows on a bench supply with a meter, but a board rail does not brown out here, which is worth knowing before trusting the simulation for a power budget.
See it in action
Servo fader drives the horn from a slide potentiometer. Open it at /templates.
The RC plane elevon and V-tail mixer sets two servos
to the RC window, 1000 to 2000 microseconds, with min_pulse and max_pulse.
Related
- The servo part page, with its pinout
- PCA9685 16-channel servo driver
- Robot arm (4 servos)