O'Reilly logo

BeagleBone Cookbook by Jason Kridner, Mark A. Yoder

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 4. Motors

Introduction

One of the many fun things about embedded computers is that you can move physical things with motors. But there are so many different kinds of motors (servo, stepper, DC), how do you select the right one?

The type of motor you use depends on the type of motion you want—for example:

R/C or Hobby servo motor
Can be quickly positioned at various absolute angles, but some don’t spin. In fact, many can turn only about 180°.
Stepper motor
Spins and can also rotate in precise relative angles, such as turning 45°. Stepper motors come in two types: bipolar (which has four wires) and unipolar (which has five or six wires).
DC motor
Spins either clockwise or counter-clockwise and can have the greatest speed of the three. But a DC motor can’t easily be made to turn to a given angle.

Once you know the type of motor to use, interfacing is easy. This chapter shows how to interface with each of these types of motors.

Note

Motors come in many sizes and types. This chapter presents some of the more popular types and shows they can easily interface to the Bone. If you need to turn on and off a 120V motor, consider using something like the PowerSwitch presented in Toggling a High-Voltage External Device.

Note

The Bone has built-in 3.3V and 5V supplies, which can supply enough current to drive some small motors. Many motors, however, draw enough current that an external supply is needed. Therefore, an external 5V supply is listed as optional in many of the recipes.

Controlling a Servo Motor

Problem

You want to use BeagleBone to control the absolute position of a servo motor.

Solution

We’ll use the pulse width modulation (PWM) hardware of the Bone and control a servo motor with the analogWrite() function.

To make the recipe, you will need:

The 1kΩ resistor isn’t required, but it provides some protection to the GPIO pin in case the servo should fault and have a large current.

Wire up your servo as shown in Figure 4-1.

Note

There is no standard for how servo motor wires are colored. One of my servos is like the Figure 4-1: red is 3.3V, black is ground, and yellow is the control line. I have another servo that has red as 3.3V and ground is brown, with the control line being orange. Generally, though, the 3.3V is in the middle. Check the datasheet for your servo before wiring.

Servo Motor
Figure 4-1. Driving a servo motor with the 3.3V supply

The code for controlling the servo motor is in servoMotor.js, shown in Example 4-1.

Example 4-1. Code for driving a servo motor (servoMotor.js)
#!/usr/bin/env node

// Drive a simple servo motor back and forth

var b = require('bonescript');

var motor = 'P9_21', // Pin to control servo
    freq = 50,  // Servo frequency (20 ms)
    min  = 0.8, // Smallest angle (in ms)
    max  = 2.5, // Largest angle (in ms)
    ms  = 250,  // How often to change position, in ms
    pos = 1.5,  // Current position, about middle
    step = 0.1; // Step size to next position

console.log('Hit ^C to stop');
b.pinMode(motor, b.ANALOG_OUTPUT, 6, 0, 0, doInterval);

function doInterval(x) {
    if(x.err) {
        console.log('x.err = ' + x.err);
        return;
    }
    timer = setInterval(sweep, ms);
}

move(pos);      // Start in the middle

// Sweep from min to max position and back again
function sweep() {
    pos += step;    // Take a step
    if(pos > max || pos < min) {
        step *= -1;
    }
    move(pos);
}

function move(pos) {
    var dutyCycle = pos/1000*freq;
    b.analogWrite(motor, dutyCycle, freq);
    console.log('pos = ' + pos + ' duty cycle = ' + dutyCycle);
}

process.on('SIGINT', function() {
    console.log('Got SIGINT, turning motor off');
    clearInterval(timer);             // Stop the timer
    b.analogWrite(motor, 0, freq);    // Turn motor off
});

Running the code causes the motor move back and forth, progressing to successive positions between the two extremes. You will need to press ^C (CTRL-C) to stop the script.

Discussion

Servo motors are often used in radio-controlled airplanes or cars. They generally don’t spin, but rather turn only 180°, just enough to control an elevator on a wing or steer wheels on a car.

The servo is controlled by a PWM signal, which is controlled by the analogWrite() function, which sends a pulse 50 times a second (50Hz or every 20ms). The width of the pulse determines the position of the motor. A short pulse (1ms, for example) sends the motor angle to zero degrees. A long pulse (2ms, for example) set the angle to 180 degrees.

The code in Example 4-1 defines a move() function, which moves the motor to a different angle every time it is called. The setInterval() function schedules sweep() to be called every 1/4 second (250ms) to step the servo to a new position.

At the end of the code, the process.on() function detects when the user has pressed ^C (CTRL-C), stops the timer, and turns off the motor. If you don’t turn off the motor, it will keep buzzing, even if it isn’t moving.

Not all GPIO pins support the PWM hardware; Fading an External LED discusses which pins you can use.

Driving a 5V (or more) servor motor

If your servo motor needs to run off of 5V, wire as shown in Figure 4-2. The banded wire attaches the Bone’s 5V supply (P9_7) to the supply on the servo. We are still controlling with a 3.3V signal.

Here, we move the banded power wire from the 3.3V supply to the Bone’s 5V supply on pin P9_7. If the Bone’s built-in 5V doesn’t supply enough current, or if you need a higher voltage, connect your servo’s power supply wire to an external supply.

Servo Motor
Figure 4-2. Driving a servo motor with the 5V supply

Of the motors presented in this chapter, the servo motor is the easiest to drive, because the contol line on the servo doesn’t require much current and therefore doesn’t require additional components.

Controlling the Speed of a DC Motor

Problem

You have a DC motor (or a solenoid) and want a simple way to control its speed, but not the direction.

Solution

It would be nice if you could just wire the DC motor to BeagleBone Black and have it work, but it won’t. Most motors require more current than the GPIO ports on the Bone can supply. Our solution is to use a transistor to control the current to the bone.

Here’s what you will need:

If you are using a larger motor (more current) you will need to use a larger transistor.

Wire your breadboard as shown in Figure 4-3.

DC Motor
Figure 4-3. Wiring a DC motor to spin one direction

The code in Example 4-2 (dcMotor.js) is used to run the motor.

Example 4-2. Driving a DC motor in one direction (dcMotor.js)
#!/usr/bin/env node

// This is an example of driving a DC motor

var b = require('bonescript');

var motor = 'P9_16',// Pin to drive transistor
    min = 0.05,     // Slowest speed (duty cycle)
    max = 1,        // Fastest (always on)
    ms = 100,       // How often to change speed, in ms
    speed = 0.5,    // Current speed;
    step = 0.05;    // Change in speed

b.pinMode(motor, b.ANALOG_OUTPUT, 6, 0, 0, doInterval);

function doInterval(x) {
    if(x.err) {
        console.log('x.err = ' + x.err);
        return;
    }
    var timer = setInterval(sweep, ms);
}

function sweep() {
    speed += step;
    if(speed > max || speed < min) {
        step *= -1;
    }
    b.analogWrite(motor, speed);
    console.log('speed = ' + speed);
}

process.on('SIGINT', function() {
    console.log('Got SIGINT, turning motor off');
    clearInterval(timer);       // Stop the timer
    b.analogWrite(motor, 0);    // Turn motor off
});

Discussion

This is actually the same code that used to drive the servo motor (Controlling a Servo Motor). The only difference is how the parameters are set. We are now using the PWM hardware to control the speed, rather than the position, of the motor. If the duty cycle is 1, the voltage to the motor is on all the time and it runs at its fastest. If the duty cycle is 0.5, the voltage is on half the time, so the motor runs slower. A duty cycle of 0 stops the motor.

This same setup can be used to drive a solenoid. After all, a solenoid is a DC motor that goes back and forth, rather than spinning. Generally, you would drive a solenoid with an on or off signal, rather than using a PWM signal.

At the end of the code, the process.on() function detects when the user has pressed ^C (CTRL-C), stops the timer, and turns off the motor. If you don’t turn off the motor, it will keep spinning.

See Also

How do you change the direction of the motor? See Controlling the Speed and Direction of a DC Motor.

Controlling the Speed and Direction of a DC Motor

Problem

You would like your DC motor to go forward and backward.

Solution

Use an H-bridge to switch the terminals on the motor so it will run both backward and forward. We’ll use the L293D: a common, single-chip H-bridge.

Here’s what you will need:

Lay out your breadboard as shown in Figure 4-4. Make sure the L293D is positioned correctly. There is a notch on one end that should be pointed up.

H-bridge Motor
Figure 4-4. Driving a DC motor with an H-bridge

The code in Example 4-3 (h-bridgeMotor.js) looks much like the code for driving the DC motor with a transistor (Example 4-2). The additional code specifies which direction the motor spins.

Example 4-3. Code for driving a DC motor with an H-bridge (h-bridgeMotor.js)
#!/usr/bin/env node

// This example uses an H-bridge to drive a DC motor in two directions

var b = require('bonescript');

var enable = 'P9_21';    // Pin to use for PWM speed control
    in1    = 'P9_15',
    in2    = 'P9_16',
    step = 0.05,    // Change in speed
    min  = 0.05,    // Min duty cycle
    max  = 1.0,     // Max duty cycle
    ms   = 100,     // Update time, in ms
    speed = min;    // Current speed;

b.pinMode(enable, b.ANALOG_OUTPUT, 6, 0, 0, doInterval);
b.pinMode(in1, b.OUTPUT);
b.pinMode(in2, b.OUTPUT);

function doInterval(x) {
    if(x.err) {
        console.log('x.err = ' + x.err);
        return;
    }
    timer = setInterval(sweep, ms);
}

clockwise();        // Start by going clockwise

function sweep() {
    speed += step;
    if(speed > max || speed < min) {
        step *= -1;
        step>0 ? clockwise() : counterClockwise();
    }
    b.analogWrite(enable, speed);
    console.log('speed = ' + speed);
}

function clockwise() {
    b.digitalWrite(in1, b.HIGH);
    b.digitalWrite(in2, b.LOW);
}

function counterClockwise() {
    b.digitalWrite(in1, b.LOW);
    b.digitalWrite(in2, b.HIGH);
}

process.on('SIGINT', function() {
    console.log('Got SIGINT, turning motor off');
    clearInterval(timer);         // Stop the timer
    b.analogWrite(enable, 0);     // Turn motor off
});

Discussion

The H-bridge provides a simple way to switch the leads on a motor so it will reverse directions. Figure 4-5 shows how an H-bridge works.

H-bridge Schematic
Figure 4-5. H-bridge schematic

The four switches connected to the motor (the big M in the center) are the H-bridge. In the left diagram, two switches are closed, connecting the left terminal of the motor to the plus voltage and the right terminal to the ground. This makes the motor rotate in one direction. The diagram on the right shows the other two switches closed, and the plus and grounds are connected to the opposite terminals, making the motor spin the other way.

In the code, in1 and in2 are used to control each pair of switches. (The L293D has four sets of these switches, but we are using only two pairs.) So, to turn clockwise, set in1 HIGH and in2 LOW. To go counter-clockwise, set them the opposite way:

function clockwise() {
    b.digitalWrite(in1, b.HIGH);
    b.digitalWrite(in2, b.LOW);
}

function counterClockwise() {
    b.digitalWrite(in1, b.LOW);
    b.digitalWrite(in2, b.HIGH);
}

The L293D also has an enable pin (pin 9, on the bottom right) which is used to control the speed of the motor by using a PWM signal. (See Controlling the Speed of a DC Motor for details on how this works.)

At the end of the code, the process.on() function at the end of the code detects when the user has pressed ^C (CTRL-C), stops the timer, and turns off the motor. If you don’t turn off the motor, it will keep spinning.

Driving a 5V DC motor

The previous example uses a motor that works with 3.3V. What if you have a 5V motor? The banded wire (running from P9_7 to pin 8 of the L293D) in Figure 4-6 attaches the L293D to the Bone’s 5V supply. This will work if your motor doesn’t draw too much current.

If 5V isn’t enough voltage, or if the Bone can’t supply the current needed, Figure 4-7 shows how to use an external supply.

H-bridge Schematic for 5V
Figure 4-6. Driving a 5V DC motor with an H-bridge
H-bridge Schematic for External Supply
Figure 4-7. Driving a DC motor with an H-bridge and external supply

The H-bridge provides an easy way to reverse the direction of a DC motor, while attaching the enable to a PWM signal allows you to control the speed.

Driving a Bipolar Stepper Motor

Problem

You want to drive a stepper motor that has four wires.

Solution

Use an L293D H-bridge. The bipolar stepper motor requires us to reverse the the coils, so we need to use an H-bridge.

Here’s what you will need:

Wire as shown in Figure 4-8.

Bipolar Stepper Motor
Figure 4-8. Bipolar stepper motor wiring

The code in Example 4-4 (bipolarStepperMotor.js) is used to drive the motor.

Example 4-4. Driving a bipolar stepper motor (bipolarStepperMotor.js)
#!/usr/bin/env node
var b = require('bonescript');

// Motor is attached here
var controller = ["P9_11", "P9_13", "P9_15", "P9_17"];
var states = [[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]];
var statesHiTorque = [[1,1,0,0], [0,1,1,0], [0,0,1,1], [1,0,0,1]];
var statesHalfStep = [[1,0,0,0], [1,1,0,0], [0,1,0,0], [0,1,1,0],
                      [0,0,1,0], [0,0,1,1], [0,0,0,1], [1,0,0,1]];

var curState = 0;   // Current state
var ms = 100,       // Time between steps, in ms
    max = 22,       // Number of steps to turn before turning around
    min = 0;        // Minimum step to turn back around on

var CW  =  1,       // Clockwise
    CCW = -1,
    pos = 0,        // current position and direction
    direction = CW;

// Initialize motor control pins to be OUTPUTs
var i;
for(i=0; i<controller.length; i++) {
    b.pinMode(controller[i], b.OUTPUT);
}

// Put the motor into a known state
updateState(states[0]);
rotate(direction);

var timer = setInterval(move, ms);

// Rotate back and forth once
function move() {
    pos += direction;
    console.log("pos: " + pos);
    // Switch directions if at end.
    if (pos >= max || pos <= min) {
        direction *= -1;
    }
    rotate(direction);
}

// This is the general rotate
function rotate(direction) {
        // console.log("rotate(%d)", direction);
    // Rotate the state acording to the direction of rotation
        curState +=  direction;
        if(curState >= states.length) {
            curState = 0;
        } else if(curState<0) {
                    curState = states.length-1;
        }
        updateState(states[curState]);
}

// Write the current input state to the controller
function updateState(state) {
    console.log("state: " + state);
        for (i=0; i<controller.length; i++) {
                b.digitalWrite(controller[i], state[i]);
        }
}

process.on('exit', function() {
    updateState([0,0,0,0]);    // Turn motor off
});

When you run the code, the stepper motor will rotate back and forth.

Discussion

Stepper motors are designed to rotate in discrete steps. They operate by turning on one coil (coil 1, for example) in one direction, then turning off coil 1 and turning on coil 2, then turning on 1 in the reverse direction, then 2 in reverse, and then back to 1 forward, as shown in Figure 4-9.

Bipolar Stepper Motor Diagram
Figure 4-9. Model of a bipolar stepper motor

In Example 4-4 (bipolarStepperMotor.js), the states variable is an array of the four different states listed in the previous paragraph. That is, [1,0,0,0] says to turn on coil 1 in the forward direction. After it’s been on for a while, you move to the next state, [0,1,0,0]. This turns off coil 1 and turns on coil 2. Then you go to [0,0,1,0], which turns on coil 1 in reverse, and so on. The H-bridge (see Controlling the Speed and Direction of a DC Motor) takes care of the reversing of the coil:

var states = [[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]];

Whenever you step, you just index the next element in the array. If you want to go backward, index the previous element.

There are two other state sequences given in the code, but they aren’t ever used. statesHiTorque is like the original states, except it has both magnets on at a time, giving a stronger pull on the motor. The statesHalfStep alternates between having one and two coils on at a time to give finer control in the step size:

var statesHiTorque = [[1,1,0,0], [0,1,1,0], [0,0,1,1], [1,0,0,1]];
var statesHalfStep = [[1,0,0,0], [1,1,0,0], [0,1,0,0], [0,1,1,0],
                      [0,0,1,0], [0,0,1,1], [0,0,0,1], [1,0,0,1]];

You can easily try either of these by assigning them to the states variable.

Notice the banded wire running from pin 8 (bottom left) of the L293D to P9_7 in Figure 4-8. This is connecting the 5V supply on the Bone to the L293D. The Bone outputs 3.3V on its GPIO pins, but the stepper motor I am using really needs 5V. Connecting the 5V in this way provides 5V out of the L293D to the stepper motor.

Running higher voltages

If your stepper motor requires a higher voltage (up to 12V), you can wire an external supply as shown in Figure 4-10.

Bipolar Stepper Motor Diagram with external supply
Figure 4-10. Model of a bipolar stepper motor

The stepper motor requires a more complex setup than the servo motor, but it has the advantage of being able to spin, which the servo can’t do.

Driving a Unipolar Stepper Motor

Problem

You want to drive a stepper motor that has five or six wires.

Solution

If your stepper motor has five or six wires, it’s a unipolar stepper and is wired differently than the bipolar. Here we’ll use a ULN2003 Darlington Transistor Array IC to drive the motor.

Here’s what you will need:

Wire as shown in Figure 4-11.

Note

The IC in Figure 4-11 is illustrated upside down from the way it is usually displayed. That is, the notch for pin 1 is on the bottom. This made drawing the diagram much cleaner.

Also notice the banded wire running the P9_7 (5V) to the UL2003A. The stepper motor I’m using runs better at 5V, so I’m using the Bone’s 5V supply. The signal coming from the GPIO pins is 3.3V, but the U2003A will step them up to 5V to drive the motor.

Unipolar Stepper Motor
Figure 4-11. Unipolar stepper motor wiring

The code for driving the motor is in unipolarStepperMotor.js; however, it is almost identical to the bipolar stepper code (Example 4-4), so Example 4-5 shows only the lines that need to be changed.

Example 4-5. Changes to bipolar code to drive a unipolar stepper motor (unipolarStepperMotor.diff)
var controller = ["P9_11", "P9_13", "P9_15", "P9_17"];
var states = [[1,1,0,0], [0,1,1,0], [0,0,1,1], [1,0,0,1]];
var curState = 0;   // Current state
var ms = 100,       // Time between steps, in ms
    max = 22,       // Number of steps to turn before turning around

The code in this example makes the following changes:

  • controller is attached to the even-numbered pins on the P9 header, rather than the odd that the bipolar stepper used. (Doing this allows you to run both types of stepper motors at the same time!)
  • The states are different. Here we have two pins high at a time.
  • The time between steps (ms) is shorter and the number of steps per direction (max) is bigger. The unipolar stepper I’m using has many more steps per rotation, so I need more steps to make it go around.

Discussion

Figure 4-12 shows how the unipolar stepper motor is wired a bit differently than the bipolar.

Unipolar Stepper Motor Diagram
Figure 4-12. Model of a unipolar stepper motor

Each coil is split, so you can access the two sides separately. The difference between the five- and six-wire steppers is that the five-wire steppers have the two power lines connected to each other. The different wiring means a different energizing sequence, as seen in the different states array.

Note

If your stepper requires more voltage, or more current than what the Bone can supply, you can replace the banded wire with an external supply, similar to the bipolar stepper example (Figure 4-10).

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required