This part has a page of its own, with a note on using it and a circuit to try: the part page.

Servo (hobby, SG90 style)

The nine-gram hobby servo, SG90 style: three wires, and a horn that walks to the angle a pulse width tells it.

The signal on PWM is not PWM in the dimming sense; the duty cycle means nothing. It is a pulse width: about 1 ms puts the horn at one end of its travel, 2 ms the other, 1.5 ms the middle, repeated fifty times a second.

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, 1000 and 2000 microseconds by default. range: degrees of travel, 180 by default. speed: how fast the horn moves towards a new angle, 600 degrees per second.

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 outside the min_pulse–max_pulse window 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 that wants the Arduino library's default 544–2400 us window, is those three numbers changed and nothing else.

What it does not model

Current. A real SG90 pulls a quarter of an amp when it stalls and can brown out the board driving it (the single most common reason a servo project misbehaves on the bench), but Mokxi's supply rails have no impedance to sag, so a sag here would be a lie about something that cannot happen in this simulator. VCC/GND are read for one thing only: below 4 V 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, no dead band (a real SG90 ignores changes under about 5 microseconds of pulse width) and no gear backlash, so a commanded angle is always reached exactly. 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, and two things are different from the upstream library. attach(pin) with no widths uses 1000 to 2000 microseconds, this part's window, where the upstream library uses 544 to 2400; attach(pin, 544, 2400) sends exactly those, and the part ignores a pulse outside its window. And 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.

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 middle of the window, 1500 microseconds, is stopped; the ends are full speed one way and the other, rpm (110 by default, the FS90R's figure at 4.8 V); in between is in proportion. Within 10 microseconds of the middle it reads as stopped, which is the small dead band that makes write(90) stop it. A wider pulse turns it anticlockwise. The probe is then the speed in rpm, positive anticlockwise, and the horn spins on the canvas.

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 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

Driving it from a pin that also drives something power-hungry and expecting no interaction. Because current sag is not modeled, a circuit that would brown out on a real board runs cleanly 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.