Controlling a stepper motor with the Raspberry Pi

I live in an extremely remote part of Northern British Columbia, Canada. It is a minimum of an hour to get to the nearest town. We are exceptionally sparsely populated with a vast amount of land right on the second-largest lake in the province.

To that end, we have a wild abundance of wildlife everywhere. Bears, moose, wolves, coyotes, deer etc etc. I set out to set up a series (eight) wildlife cameras using Raspberry Pis (four on my house, the other four each on a separate cabin), all streaming to a central server that I can display on a television set, with all eight camera streams within a single window.

After I accomplished the bulk of that work, I wanted a way to pan and tilt my cameras individually. The tilt part I use a standard servo with the the servo() functionality of the RPi::WiringPi distribution.

For pan, I decided on a 28BYJ-48 gear reduction stepper motor, driven by a ULN2003A motor driver. I then read the datasheet, put some code together, and now we can drive said unit with Perl.

The setup is extremely basic, simply connect 5v+ and Ground to the driver board, along with four GPIO pins (image on my Github).

The new distribution is RPi::StepperMotor, and is very easy to get going with.

To the code. This is pretty well the most basic example we can have. It sets up the object, readies the pins, then swivels 180 degrees clockwise, then back counter-clockwise 180 degrees, essentially on a permanent sweep:

use warnings;
use strict;

use RPi::StepperMotor;

my $sm = RPi::StepperMotor->new(
    pins => [12, 16, 20, 21]
);

while (1){
    $sm->cw(180);
    $sm->ccw(180);
}

NOTE: It is up to the user to unset the pins after they are done. Shortly, this distribution will appear within the RPi::WiringPi framework, so pin cleanup will be done automatically upon crash or program exit if you use that distribution and instantiate a stepper motor object through there. It's already in the repo, doing the full test suite so I should have that up tomorrow.

I've included also a stepper binary for quick command line movement of the motor:

Usage:   stepper <cw|ccw> degrees [speed]

Example: stepper cw 180 [full]

The stepper motor can be driven in "half" speed (ie. we execute all steps per movement) or "full" speed, which skips every second step. Full is half as accurate, but twice as fast. You can set the speed ('half' by default) in the instantiation call:

my $sm = RPi::StepperMotor->new(pins => $pins, speed => 'full');

...or at runtime with the speed() method:

$sm->speed('full');

The only other option is the delay we introduce in between each step. This, too can be set in the instantiation call, or at runtime with the delay() method. The default delay is 0.01 seconds.

my $sm = RPi::StepperMotor->new(pins => $pins, delay => 0.2);

...or

$sm->delay(0.2);

Have fun!

3 Comments

Mmm Moose and pi on the same page

happy π day.

Hello, it is a great blog for me.
Please, let me know in case you use
a hat-motor Rpi, how I can see which pin
to connect, do you know? I will try to
find how to manage this and return here.
Regards

OK, there are driver written in python for adafruit motor-hat that use i2c protocols.
https://www.adafruit.com/product/2348
and I have this motor-hat in my lab.
But, they did not use perl, our favorite language...what I can do?

Leave a comment

About Steve Bertrand

user-pic Just Another Perl Hacker