New library feedback? custom-pwm

I wrote my first library “custom-pwm”

The purpose is using the 0.6.0 Particle functions for PWM to act like the Arduino servo class, it does very little. I tested with a scope and it works. Standard RC servos take 50Hz but digital servos and ESCs take 300Hz or more.

I’m asking for feedback on the format, I contributed and published it so you should see it in the Build IDE, but here’s a link:

Thanks for any feedback.

What’s the difference with our existing Servo class?

I attached a normal Servo class to D0 and this one to D1 it was the same frequency.

I then checked my header file and both pins are using Timer 4, when you use different Timers e.g. D0 and D2, you’ll get the standard 50Hz off the existing Servo class and this is 300Hz, but you could set it to any supported frequency. This is all accomplished using new Particle functions.

green trace: existing Servo PWM. yellow: this library PWM.

Adittions like that would be a nice topic for a pull request.
You can download the existing servo class implementation, add your own stuff and contribute that as a PR on

This way it might be take up into the standard framework :wink:

1 Like

Thanks, the GitHub flow it’s easy conceptually, just haven’t gotten the specific workflow down. I would want to do a lot more testing. A standard servo signal has 10 to 20% duty cycle over the whole range. The 3 digital RC things I’ve tested have a 15 to 60% duty cycle to get the same range. Optional parameters would be the way to go, right now servo.attach can take 5 parameters (I only knew of 3) but frequency and resolution could be two more.

For resolution, I have to test to see if 25% and 25.1% actually makes a difference. I’m going to try a magnet on a propeller blade and see if I can measure the RPM difference with a hall sensor, if there is one.

Here is the respective header

e.g. Servo::attach()

     * @brief Associate this instance with a servomotor whose input is
     *        connected to pin.
     * If this instance is already attached to a pin, it will be
     * detached before being attached to the new pin. This function
     * doesn't detach any interrupt attached with the pin's timer
     * channel.
     * @param pin Pin connected to the servo pulse wave input. This
     *            pin must be capable of PWM output.
     * @param minPulseWidth Minimum pulse width to write to pin, in
     *                      microseconds.  This will be associated
     *                      with a minAngle degree angle.  Defaults to
     *                      SERVO_DEFAULT_MIN_PW = 544.
     * @param maxPulseWidth Maximum pulse width to write to pin, in
     *                      microseconds.  This will be associated
     *                      with a maxAngle degree angle. Defaults to
     *                      SERVO_DEFAULT_MAX_PW = 2400.
     * @param minAngle Target angle (in degrees) associated with
     *                 minPulseWidth.  Defaults to
     *                 SERVO_DEFAULT_MIN_ANGLE = 0.
     * @param maxAngle Target angle (in degrees) associated with
     *                 maxPulseWidth.  Defaults to
     *                 SERVO_DEFAULT_MAX_ANGLE = 180.
     * @sideeffect May set pinMode(pin, PWM).
     * @return true if successful, false when pin doesn't support PWM.
    bool attach(uint16_t pin,
                uint16_t minPulseWidth=SERVO_DEFAULT_MIN_PW,
                uint16_t maxPulseWidth=SERVO_DEFAULT_MAX_PW,
                int16_t minAngle=SERVO_DEFAULT_MIN_ANGLE,
                int16_t maxAngle=SERVO_DEFAULT_MAX_ANGLE);

But as it seems to me the currently used pulse width apporoach with fixed µs values is somehow assuming a fixed PWM periode, but with variable periode it’ll get counter intuitive - to say the least.
That might be something to get @mdma on board for.

I did more testing.

At 12bits of resolution at 300Hz it changes speed from from a min 1400 to 2500, 34 to 61% PWM.
The servo class has a resolution of 180. This had a resolution of ~1100. I published the values to ThingSpeak, you can see changed about every other one, even with magnets doubling the weight of the propeller. So I’d want at least 500+ values of resolution to control a quadcopter using ESCs.

Note measuring propeller speed should be done optically, but I had a hall sensor already hooked up. I’ll find the magnet that flew off eventually.

The linked ThingSpeak channel has 500 data points now, tldr you want 500+ resolution values. In my test I did 500 of 1100, 1 second to stabilize and 3 seconds to take an RPM reading. I’ll probably update it with a full range sweep in a day or two. Then it’ll be using the Electron to send the PWM to all 4, with the asset tracker I hope to use the accelerometer to maintain level.

Optical is much better.