Skip to main content

Pulse Width Modulation with a Servo

This example will guide you through the process of connecting a servo to your imp, and controlling its position with Pulse Width Modulation (PWM). Pulse Width Modulation just means we’ll be sending a series of pulses to the output pin. By varying the length of the pulses with pin.write() we can affect how much power the servo gets, which will set the servo’s position. Take a look at the PWM Wikipedia page to learn more about PWM, and what it can be used for.

This example assumes you have a basic familiarity with Electric Imp’s impCentral™. We suggest working through our Getting Started Guide before trying this example.

What you will need

Note The following instructions were written with the imp001 in mind, but they can be readily adapted to any other imp and breakout board.

For this example you are going to need the following:

  • 1 x April board
  • 1 x imp001 card
  • 1 x breadboard
  • 1 x servo (we choose this one)

Circuit

Simple Servo Circuit

Hook Up Instructions

  1. Connect the servo’s yellow (control) wire to pin7
  2. Connect the servo’s red (power) wire to VIN
  3. Connect the servo’s black (ground) wire to GND

Servos typically require more than 3.3V to function properly. Because of this, you generally want to connect the servo’s power to VIN as opposed to 3v3. As always, you should consult the part’s datasheet for more information.

Code

In impCentral, create a new Product called “Examples” (if you have not tried another of these basic hardware examples) and a new Development Device Group called “servo”. Assign your device to the new Device Group, then copy and paste the following code into the code editor’s ‘Device Code’ pane and hit ‘Build and Force Restart’.

What’s going on

This example should sweep your servo between its minimum and maximum position. Here’s how it works.

The first thing we do is assign the minimum and maximum values we want to write to the PWM control pin. We’ll use these values to make sure we aren’t overdriving — and potentially damaging — our servo in either direction.

const SERVO_MIN = 0.03;
const SERVO_MAX = 0.1;

Next, we assign the imp’s hardware.pin7 object to a global variable called servo and configure it as a PWM_OUT. We set the period to 0.02, which is a fairly standard value for servos, and set the initial phase to the servo’s minimum:

servo <- hardware.pin1;
servo.configure(PWM_OUT, 0.02, SERVO_MIN);

The next thing we do is set up a function to set the position of the servo. We take a value between 0.0 and 1.0, and do some basic math to translate it to an equal value between our SERVO_MIN and SERVO_MAX, then write it to the servo pin:

function setServo(value) {
    local scaledValue = value * (SERVO_MAX - SERVO_MIN) + SERVO_MIN;
    servo.write(scaledValue);
}

If we wanted to specify an absolute position (in degrees), since we know the servo has a range of about 160°, we could change our function to the following:

function setServoDegrees(value) {
    local scaledValue = (value + 81) / 181.0 * (SERVO_MAX - SERVO_MIN) + SERVO_MIN;
    servo.write(scaledValue);
}

Finally, we create our sweep() function that flips the position of the servo between its minimum value (at 0.0) and its maximum value (at 1.0). This function works identically to the blink() function used in the Digital Output example:

function sweep() {
    setServo(position);
    position = 1.0 - position;
    imp.wakeup(1.0, sweep);
}

Finally, we call sweep() to start the loop:

sweep();