#!/usr/bin/env python # This code is written by Stephen C Phillips. # It is in the public domain, so you can do what you like with it # but a link to http://scphillips.com would be nice. # It works on the Raspberry Pi computer with the standard Debian Wheezy OS and # the 28BJY-48 stepper motor with ULN2003 control board. from time import sleep import RPi.GPIO as GPIO class Motor(object): def __init__(self, pins, mode=3): """Initialise the motor object. pins -- a list of 4 integers referring to the GPIO pins that the IN1, IN2 IN3 and IN4 pins of the ULN2003 board are wired to mode -- the stepping mode to use: 1: wave drive (not yet implemented) 2: full step drive 3: half step drive (default) """ self.P1 = pins[0] self.P2 = pins[1] self.P3 = pins[2] self.P4 = pins[3] self.mode = mode self.deg_per_step = 5.625 / 64 # for half-step drive (mode 3) self.steps_per_rev = int(360 / self.deg_per_step) # 4096 self.step_angle = 0 # Assume the way it is pointing is zero degrees for p in pins: GPIO.setup(p, GPIO.OUT) GPIO.output(p, 0) def _set_rpm(self, rpm): """Set the turn speed in RPM.""" self._rpm = rpm # T is the amount of time to stop between signals self._T = (60.0 / rpm) / self.steps_per_rev # This means you can set "rpm" as if it is an attribute and # behind the scenes it sets the _T attribute rpm = property(lambda self: self._rpm, _set_rpm) def move_to(self, angle): """Take the shortest route to a particular angle (degrees).""" # Make sure there is a 1:1 mapping between angle and stepper angle target_step_angle = 8 * (int(angle / self.deg_per_step) / 8) steps = target_step_angle - self.step_angle steps = (steps % self.steps_per_rev) if steps > self.steps_per_rev / 2: steps -= self.steps_per_rev print "moving " + `steps` + " steps" if self.mode == 2: self._move_acw_2(-steps / 8) else: self._move_acw_3(-steps / 8) else: print "moving " + `steps` + " steps" if self.mode == 2: self._move_cw_2(steps / 8) else: self._move_cw_3(steps / 8) self.step_angle = target_step_angle def __clear(self): GPIO.output(self.P1, 0) GPIO.output(self.P2, 0) GPIO.output(self.P3, 0) GPIO.output(self.P4, 0) def _move_acw_2(self, big_steps): self.__clear() for i in range(big_steps): GPIO.output(self.P3, 0) GPIO.output(self.P1, 1) sleep(self._T * 2) GPIO.output(self.P2, 0) GPIO.output(self.P4, 1) sleep(self._T * 2) GPIO.output(self.P1, 0) GPIO.output(self.P3, 1) sleep(self._T * 2) GPIO.output(self.P4, 0) GPIO.output(self.P2, 1) sleep(self._T * 2) def _move_cw_2(self, big_steps): self.__clear() for i in range(big_steps): GPIO.output(self.P4, 0) GPIO.output(self.P2, 1) sleep(self._T * 2) GPIO.output(self.P1, 0) GPIO.output(self.P3, 1) sleep(self._T * 2) GPIO.output(self.P2, 0) GPIO.output(self.P4, 1) sleep(self._T * 2) GPIO.output(self.P3, 0) GPIO.output(self.P1, 1) sleep(self._T * 2) def _move_acw_3(self, big_steps): self.__clear() for i in range(big_steps): GPIO.output(self.P1, 0) sleep(self._T) GPIO.output(self.P3, 1) sleep(self._T) GPIO.output(self.P4, 0) sleep(self._T) GPIO.output(self.P2, 1) sleep(self._T) GPIO.output(self.P3, 0) sleep(self._T) GPIO.output(self.P1, 1) sleep(self._T) GPIO.output(self.P2, 0) sleep(self._T) GPIO.output(self.P4, 1) sleep(self._T) def _move_cw_3(self, big_steps): self.__clear() for i in range(big_steps): GPIO.output(self.P3, 0) sleep(self._T) GPIO.output(self.P1, 1) sleep(self._T) GPIO.output(self.P4, 0) sleep(self._T) GPIO.output(self.P2, 1) sleep(self._T) GPIO.output(self.P1, 0) sleep(self._T) GPIO.output(self.P3, 1) sleep(self._T) GPIO.output(self.P2, 0) sleep(self._T) GPIO.output(self.P4, 1) sleep(self._T) if __name__ == "__main__": GPIO.setmode(GPIO.BOARD) m = Motor([18,22,24,26]) m.rpm = 5 print "Pause in seconds: " + `m._T` m.move_to(90) sleep(1) m.move_to(0) sleep(1) m.mode = 2 m.move_to(90) sleep(1) m.move_to(0) GPIO.cleanup()