Bad output from servo library

I've created a simple code to drive a RC electronic speed control (ESC). If I use the code below, I get an output that varies from 0.5ms to 2.5ms. If I comment out the servo.write() and uncomment the servo.writeMicroseconds(), I get the correct span of 1ms to 2ms. Is there something wrong with my code or is there a bug in servo.write()?
Running on Photon 2 with O/S v5.9.0.

Servo myservo;  // create servo object to control a R/C servo
                // a maximum of eight servo objects can be created

const int PWM_OUTP  = D1;	// 1ms << out_pulse << 2ms
const int SPD_POT = A0;

STARTUP(WiFi.selectAntenna(ANT_INTERNAL));

// Let Device OS manage the connection to the Particle Cloud
SYSTEM_MODE(AUTOMATIC);

// Show system, cloud connectivity, and application logs over USB
// View logs with CLI using 'particle serial monitor --follow'
SerialLogHandler logHandler(LOG_LEVEL_INFO);

void setup()
{
    (void)logHandler; // Does nothing, just to eliminate the unused variable warning

    // Configure I/O pins
    pinMode(RUN, INPUT_PULLUP);     // sets pin as input
    pinMode(USER_OUTP, OUTPUT);
    
    myservo.attach(PWM_OUTP);       // attaches the servo on the D0 pin to the servo object
                                    // Only supported on pins that have PWM
    // Gen 4 devices including the M-SoM, P2, and Photon 2
    analogWrite(PWM_OUTP, 255, 50);

    Log.info("Starting RC Servo... ");
}


void loop()
{
    static int old_pwm  = -1;       // servo position from previous reading
    static int loop_cnt = 0;
    
    if ( digitalRead(RUN) == LOW )
    {
            int pot = analogRead(SPD_POT);      // read user input; rtns 0-4095
            int pwm = map(pot, 0, 4095, 0, 180);// convert to 0-180 degree
    
            if (pwm != old_pwm) 
            {
                Log.info("Pot is %d/4095, pwm=%d ", pot, pwm);
                old_pwm = pwm;
            }

            myservo.write(pwm);
            //myservo.writeMicroseconds(map(pot, 0, 4095, 1000, 2000));
        delay(100);
    }
    else
    {
        myservo.write(0);
        //myservo.writeMicroseconds(1000);
        delay(1000);
    }

    
    loop_cnt += 1;

    digitalWriteFast(USER_OUTP, !pinReadFast(USER_OUTP));   // toggle LED
}

The values in the docs for writeMicroseconds don't match the Device OS code.

#define SERVO_DEFAULT_MIN_PW            544
#define SERVO_DEFAULT_MAX_PW            2400
#define SERVO_DEFAULT_MIN_ANGLE         0
#define SERVO_DEFAULT_MAX_ANGLE         180

The minimum is 544 and the maximum is 2400. Internally, write() calls writeMicroseconds, but it uses those values to map the range.

1 Like

Thanks @rickkas7, that explains what I'm seeing. But that doesn't match the R/C "standard" afaik, and my ESC throws a "bad input signal" error. Is there some logic to the #defines, or is 544-2400 a newer standard?

The range of 544 - 2400 matches Arduino and it's been that way since the Spark Core, 12 years ago, Device OS 0.4.2. It would seem to be out of spec, but there's a comment not to change it in the code.

Anyway, the advantage of using writeMicroseconds is that you can easily change the mapping to fit your hardware.

1 Like

Thanks again for taking time to explain it! I agree that writeMicroseconds keeps it explicit and simple.