init
This commit is contained in:
parent
626fa702f7
commit
7d1a7a66f7
8 changed files with 928 additions and 0 deletions
252
Adafruit_MotorHAT/Adafruit_MotorHAT.py
Executable file
252
Adafruit_MotorHAT/Adafruit_MotorHAT.py
Executable file
|
|
@ -0,0 +1,252 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
from Adafruit_PWM_Servo_Driver import PWM
|
||||
import time
|
||||
|
||||
class Adafruit_StepperMotor:
|
||||
MICROSTEPS = 8
|
||||
MICROSTEP_CURVE = [0, 50, 98, 142, 180, 212, 236, 250, 255]
|
||||
|
||||
#MICROSTEPS = 16
|
||||
# a sinusoidal curve NOT LINEAR!
|
||||
#MICROSTEP_CURVE = [0, 25, 50, 74, 98, 120, 141, 162, 180, 197, 212, 225, 236, 244, 250, 253, 255]
|
||||
|
||||
def __init__(self, controller, num, steps=200):
|
||||
self.MC = controller
|
||||
self.revsteps = steps
|
||||
self.motornum = num
|
||||
self.sec_per_step = 0.1
|
||||
self.steppingcounter = 0
|
||||
self.currentstep = 0
|
||||
|
||||
num -= 1
|
||||
|
||||
if (num == 0):
|
||||
self.PWMA = 8
|
||||
self.AIN2 = 9
|
||||
self.AIN1 = 10
|
||||
self.PWMB = 13
|
||||
self.BIN2 = 12
|
||||
self.BIN1 = 11
|
||||
elif (num == 1):
|
||||
self.PWMA = 2
|
||||
self.AIN2 = 3
|
||||
self.AIN1 = 4
|
||||
self.PWMB = 7
|
||||
self.BIN2 = 6
|
||||
self.BIN1 = 5
|
||||
else:
|
||||
raise NameError('MotorHAT Stepper must be between 1 and 2 inclusive')
|
||||
|
||||
def setSpeed(self, rpm):
|
||||
self.sec_per_step = 60.0 / (self.revsteps * rpm)
|
||||
self.steppingcounter = 0
|
||||
|
||||
def oneStep(self, dir, style):
|
||||
pwm_a = pwm_b = 255
|
||||
|
||||
# first determine what sort of stepping procedure we're up to
|
||||
if (style == Adafruit_MotorHAT.SINGLE):
|
||||
if ((self.currentstep/(self.MICROSTEPS/2)) % 2):
|
||||
# we're at an odd step, weird
|
||||
if (dir == Adafruit_MotorHAT.FORWARD):
|
||||
self.currentstep += self.MICROSTEPS/2
|
||||
else:
|
||||
self.currentstep -= self.MICROSTEPS/2
|
||||
else:
|
||||
# go to next even step
|
||||
if (dir == Adafruit_MotorHAT.FORWARD):
|
||||
self.currentstep += self.MICROSTEPS
|
||||
else:
|
||||
self.currentstep -= self.MICROSTEPS
|
||||
if (style == Adafruit_MotorHAT.DOUBLE):
|
||||
if not (self.currentstep/(self.MICROSTEPS/2) % 2):
|
||||
# we're at an even step, weird
|
||||
if (dir == Adafruit_MotorHAT.FORWARD):
|
||||
self.currentstep += self.MICROSTEPS/2
|
||||
else:
|
||||
self.currentstep -= self.MICROSTEPS/2
|
||||
else:
|
||||
# go to next odd step
|
||||
if (dir == Adafruit_MotorHAT.FORWARD):
|
||||
self.currentstep += self.MICROSTEPS
|
||||
else:
|
||||
self.currentstep -= self.MICROSTEPS
|
||||
if (style == Adafruit_MotorHAT.INTERLEAVE):
|
||||
if (dir == Adafruit_MotorHAT.FORWARD):
|
||||
self.currentstep += self.MICROSTEPS/2
|
||||
else:
|
||||
self.currentstep -= self.MICROSTEPS/2
|
||||
|
||||
if (style == Adafruit_MotorHAT.MICROSTEP):
|
||||
if (dir == Adafruit_MotorHAT.FORWARD):
|
||||
self.currentstep += 1
|
||||
else:
|
||||
self.currentstep -= 1
|
||||
|
||||
# go to next 'step' and wrap around
|
||||
self.currentstep += self.MICROSTEPS * 4
|
||||
self.currentstep %= self.MICROSTEPS * 4
|
||||
|
||||
pwm_a = pwm_b = 0
|
||||
if (self.currentstep >= 0) and (self.currentstep < self.MICROSTEPS):
|
||||
pwm_a = self.MICROSTEP_CURVE[self.MICROSTEPS - self.currentstep]
|
||||
pwm_b = self.MICROSTEP_CURVE[self.currentstep]
|
||||
elif (self.currentstep >= self.MICROSTEPS) and (self.currentstep < self.MICROSTEPS*2):
|
||||
pwm_a = self.MICROSTEP_CURVE[self.currentstep - self.MICROSTEPS]
|
||||
pwm_b = self.MICROSTEP_CURVE[self.MICROSTEPS*2 - self.currentstep]
|
||||
elif (self.currentstep >= self.MICROSTEPS*2) and (self.currentstep < self.MICROSTEPS*3):
|
||||
pwm_a = self.MICROSTEP_CURVE[self.MICROSTEPS*3 - self.currentstep]
|
||||
pwm_b = self.MICROSTEP_CURVE[self.currentstep - self.MICROSTEPS*2]
|
||||
elif (self.currentstep >= self.MICROSTEPS*3) and (self.currentstep < self.MICROSTEPS*4):
|
||||
pwm_a = self.MICROSTEP_CURVE[self.currentstep - self.MICROSTEPS*3]
|
||||
pwm_b = self.MICROSTEP_CURVE[self.MICROSTEPS*4 - self.currentstep]
|
||||
|
||||
|
||||
# go to next 'step' and wrap around
|
||||
self.currentstep += self.MICROSTEPS * 4
|
||||
self.currentstep %= self.MICROSTEPS * 4
|
||||
|
||||
# only really used for microstepping, otherwise always on!
|
||||
self.MC._pwm.setPWM(self.PWMA, 0, pwm_a*16)
|
||||
self.MC._pwm.setPWM(self.PWMB, 0, pwm_b*16)
|
||||
|
||||
# set up coil energizing!
|
||||
coils = [0, 0, 0, 0]
|
||||
|
||||
if (style == Adafruit_MotorHAT.MICROSTEP):
|
||||
if (self.currentstep >= 0) and (self.currentstep < self.MICROSTEPS):
|
||||
coils = [1, 1, 0, 0]
|
||||
elif (self.currentstep >= self.MICROSTEPS) and (self.currentstep < self.MICROSTEPS*2):
|
||||
coils = [0, 1, 1, 0]
|
||||
elif (self.currentstep >= self.MICROSTEPS*2) and (self.currentstep < self.MICROSTEPS*3):
|
||||
coils = [0, 0, 1, 1]
|
||||
elif (self.currentstep >= self.MICROSTEPS*3) and (self.currentstep < self.MICROSTEPS*4):
|
||||
coils = [1, 0, 0, 1]
|
||||
else:
|
||||
step2coils = [ [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] ]
|
||||
coils = step2coils[self.currentstep/(self.MICROSTEPS/2)]
|
||||
|
||||
#print "coils state = " + str(coils)
|
||||
self.MC.setPin(self.AIN2, coils[0])
|
||||
self.MC.setPin(self.BIN1, coils[1])
|
||||
self.MC.setPin(self.AIN1, coils[2])
|
||||
self.MC.setPin(self.BIN2, coils[3])
|
||||
|
||||
return self.currentstep
|
||||
|
||||
def step(self, steps, direction, stepstyle):
|
||||
s_per_s = self.sec_per_step
|
||||
lateststep = 0
|
||||
|
||||
if (stepstyle == Adafruit_MotorHAT.INTERLEAVE):
|
||||
s_per_s = s_per_s / 2.0
|
||||
if (stepstyle == Adafruit_MotorHAT.MICROSTEP):
|
||||
s_per_s /= self.MICROSTEPS
|
||||
steps *= self.MICROSTEPS
|
||||
|
||||
print s_per_s, " sec per step"
|
||||
|
||||
for s in range(steps):
|
||||
lateststep = self.oneStep(direction, stepstyle)
|
||||
time.sleep(s_per_s)
|
||||
|
||||
if (stepstyle == Adafruit_MotorHAT.MICROSTEP):
|
||||
# this is an edge case, if we are in between full steps, lets just keep going
|
||||
# so we end on a full step
|
||||
while (lateststep != 0) and (lateststep != self.MICROSTEPS):
|
||||
lateststep = self.oneStep(dir, stepstyle)
|
||||
time.sleep(s_per_s)
|
||||
|
||||
class Adafruit_DCMotor:
|
||||
def __init__(self, controller, num):
|
||||
self.MC = controller
|
||||
self.motornum = num
|
||||
pwm = in1 = in2 = 0
|
||||
|
||||
if (num == 0):
|
||||
pwm = 8
|
||||
in2 = 9
|
||||
in1 = 10
|
||||
elif (num == 1):
|
||||
pwm = 13
|
||||
in2 = 12
|
||||
in1 = 11
|
||||
elif (num == 2):
|
||||
pwm = 2
|
||||
in2 = 3
|
||||
in1 = 4
|
||||
elif (num == 3):
|
||||
pwm = 7
|
||||
in2 = 6
|
||||
in1 = 5
|
||||
else:
|
||||
raise NameError('MotorHAT Motor must be between 1 and 4 inclusive')
|
||||
self.PWMpin = pwm
|
||||
self.IN1pin = in1
|
||||
self.IN2pin = in2
|
||||
|
||||
def run(self, command):
|
||||
if not self.MC:
|
||||
return
|
||||
if (command == Adafruit_MotorHAT.FORWARD):
|
||||
self.MC.setPin(self.IN2pin, 0)
|
||||
self.MC.setPin(self.IN1pin, 1)
|
||||
if (command == Adafruit_MotorHAT.BACKWARD):
|
||||
self.MC.setPin(self.IN1pin, 0)
|
||||
self.MC.setPin(self.IN2pin, 1)
|
||||
if (command == Adafruit_MotorHAT.RELEASE):
|
||||
self.MC.setPin(self.IN1pin, 0)
|
||||
self.MC.setPin(self.IN2pin, 0)
|
||||
def setSpeed(self, speed):
|
||||
if (speed < 0):
|
||||
speed = 0
|
||||
if (speed > 255):
|
||||
speed = 255
|
||||
self.MC._pwm.setPWM(self.PWMpin, 0, speed*16)
|
||||
|
||||
class Adafruit_MotorHAT:
|
||||
FORWARD = 1
|
||||
BACKWARD = 2
|
||||
BRAKE = 3
|
||||
RELEASE = 4
|
||||
|
||||
SINGLE = 1
|
||||
DOUBLE = 2
|
||||
INTERLEAVE = 3
|
||||
MICROSTEP = 4
|
||||
|
||||
def __init__(self, addr = 0x60, freq = 1600):
|
||||
self._i2caddr = addr # default addr on HAT
|
||||
self._frequency = freq # default @1600Hz PWM freq
|
||||
self.motors = [ Adafruit_DCMotor(self, m) for m in range(4) ]
|
||||
self.steppers = [ Adafruit_StepperMotor(self, 1), Adafruit_StepperMotor(self, 2) ]
|
||||
self._pwm = PWM(addr, debug=False)
|
||||
self._pwm.setPWMFreq(self._frequency)
|
||||
|
||||
def setPin(self, pin, value):
|
||||
if (pin < 0) or (pin > 15):
|
||||
raise NameError('PWM pin must be between 0 and 15 inclusive')
|
||||
if (value != 0) and (value != 1):
|
||||
raise NameError('Pin value must be 0 or 1!')
|
||||
if (value == 0):
|
||||
self._pwm.setPWM(pin, 0, 4096)
|
||||
if (value == 1):
|
||||
self._pwm.setPWM(pin, 4096, 0)
|
||||
|
||||
def getStepper(self, steps, num):
|
||||
if (num < 1) or (num > 2):
|
||||
raise NameError('MotorHAT Stepper must be between 1 and 2 inclusive')
|
||||
return self.steppers[num-1]
|
||||
|
||||
def getMotor(self, num):
|
||||
if (num < 1) or (num > 4):
|
||||
raise NameError('MotorHAT Motor must be between 1 and 4 inclusive')
|
||||
return self.motors[num-1]
|
||||
92
Adafruit_MotorHAT/Adafruit_PWM_Servo_Driver.py
Normal file
92
Adafruit_MotorHAT/Adafruit_PWM_Servo_Driver.py
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
import time
|
||||
import math
|
||||
from Adafruit_I2C import Adafruit_I2C
|
||||
|
||||
# ============================================================================
|
||||
# Adafruit PCA9685 16-Channel PWM Servo Driver
|
||||
# ============================================================================
|
||||
|
||||
class PWM :
|
||||
# Registers/etc.
|
||||
__MODE1 = 0x00
|
||||
__MODE2 = 0x01
|
||||
__SUBADR1 = 0x02
|
||||
__SUBADR2 = 0x03
|
||||
__SUBADR3 = 0x04
|
||||
__PRESCALE = 0xFE
|
||||
__LED0_ON_L = 0x06
|
||||
__LED0_ON_H = 0x07
|
||||
__LED0_OFF_L = 0x08
|
||||
__LED0_OFF_H = 0x09
|
||||
__ALL_LED_ON_L = 0xFA
|
||||
__ALL_LED_ON_H = 0xFB
|
||||
__ALL_LED_OFF_L = 0xFC
|
||||
__ALL_LED_OFF_H = 0xFD
|
||||
|
||||
# Bits
|
||||
__RESTART = 0x80
|
||||
__SLEEP = 0x10
|
||||
__ALLCALL = 0x01
|
||||
__INVRT = 0x10
|
||||
__OUTDRV = 0x04
|
||||
|
||||
general_call_i2c = Adafruit_I2C(0x00)
|
||||
|
||||
@classmethod
|
||||
def softwareReset(cls):
|
||||
"Sends a software reset (SWRST) command to all the servo drivers on the bus"
|
||||
cls.general_call_i2c.writeRaw8(0x06) # SWRST
|
||||
|
||||
def __init__(self, address=0x40, debug=False):
|
||||
self.i2c = Adafruit_I2C(address)
|
||||
self.i2c.debug = debug
|
||||
self.address = address
|
||||
self.debug = debug
|
||||
if (self.debug):
|
||||
print "Reseting PCA9685 MODE1 (without SLEEP) and MODE2"
|
||||
self.setAllPWM(0, 0)
|
||||
self.i2c.write8(self.__MODE2, self.__OUTDRV)
|
||||
self.i2c.write8(self.__MODE1, self.__ALLCALL)
|
||||
time.sleep(0.005) # wait for oscillator
|
||||
|
||||
mode1 = self.i2c.readU8(self.__MODE1)
|
||||
mode1 = mode1 & ~self.__SLEEP # wake up (reset sleep)
|
||||
self.i2c.write8(self.__MODE1, mode1)
|
||||
time.sleep(0.005) # wait for oscillator
|
||||
|
||||
def setPWMFreq(self, freq):
|
||||
"Sets the PWM frequency"
|
||||
prescaleval = 25000000.0 # 25MHz
|
||||
prescaleval /= 4096.0 # 12-bit
|
||||
prescaleval /= float(freq)
|
||||
prescaleval -= 1.0
|
||||
if (self.debug):
|
||||
print "Setting PWM frequency to %d Hz" % freq
|
||||
print "Estimated pre-scale: %d" % prescaleval
|
||||
prescale = math.floor(prescaleval + 0.5)
|
||||
if (self.debug):
|
||||
print "Final pre-scale: %d" % prescale
|
||||
|
||||
oldmode = self.i2c.readU8(self.__MODE1);
|
||||
newmode = (oldmode & 0x7F) | 0x10 # sleep
|
||||
self.i2c.write8(self.__MODE1, newmode) # go to sleep
|
||||
self.i2c.write8(self.__PRESCALE, int(math.floor(prescale)))
|
||||
self.i2c.write8(self.__MODE1, oldmode)
|
||||
time.sleep(0.005)
|
||||
self.i2c.write8(self.__MODE1, oldmode | 0x80)
|
||||
|
||||
def setPWM(self, channel, on, off):
|
||||
"Sets a single PWM channel"
|
||||
self.i2c.write8(self.__LED0_ON_L+4*channel, on & 0xFF)
|
||||
self.i2c.write8(self.__LED0_ON_H+4*channel, on >> 8)
|
||||
self.i2c.write8(self.__LED0_OFF_L+4*channel, off & 0xFF)
|
||||
self.i2c.write8(self.__LED0_OFF_H+4*channel, off >> 8)
|
||||
|
||||
def setAllPWM(self, on, off):
|
||||
"Sets a all PWM channels"
|
||||
self.i2c.write8(self.__ALL_LED_ON_L, on & 0xFF)
|
||||
self.i2c.write8(self.__ALL_LED_ON_H, on >> 8)
|
||||
self.i2c.write8(self.__ALL_LED_OFF_L, off & 0xFF)
|
||||
self.i2c.write8(self.__ALL_LED_OFF_H, off >> 8)
|
||||
62
examples/DCTest.py
Normal file
62
examples/DCTest.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/python
|
||||
#import Adafruit_MotorHAT, Adafruit_DCMotor, Adafruit_Stepper
|
||||
from Adafruit_MotorHAT import Adafruit_MotorHAT, Adafruit_DCMotor, Adafruit_StepperMotor
|
||||
|
||||
import time
|
||||
import atexit
|
||||
|
||||
# create a default object, no changes to I2C address or frequency
|
||||
mh = Adafruit_MotorHAT(addr=0x61)
|
||||
|
||||
# recommended for auto-disabling motors on shutdown!
|
||||
def turnOffMotors():
|
||||
mh.getMotor(1).run(Adafruit_MotorHAT.RELEASE)
|
||||
mh.getMotor(2).run(Adafruit_MotorHAT.RELEASE)
|
||||
mh.getMotor(3).run(Adafruit_MotorHAT.RELEASE)
|
||||
mh.getMotor(4).run(Adafruit_MotorHAT.RELEASE)
|
||||
|
||||
atexit.register(turnOffMotors)
|
||||
|
||||
################################# DC motor test!
|
||||
myMotor = mh.getMotor(3)
|
||||
|
||||
# set the speed to start, from 0 (off) to 255 (max speed)
|
||||
myMotor.setSpeed(150)
|
||||
myMotor.run(Adafruit_MotorHAT.FORWARD);
|
||||
# turn on motor
|
||||
myMotor.run(Adafruit_MotorHAT.RELEASE);
|
||||
|
||||
|
||||
while (True):
|
||||
print "Forward! "
|
||||
myMotor.run(Adafruit_MotorHAT.FORWARD)
|
||||
|
||||
print "\tSpeed up..."
|
||||
for i in range(255):
|
||||
myMotor.setSpeed(i)
|
||||
time.sleep(0.01)
|
||||
|
||||
print "\tSlow down..."
|
||||
for i in reversed(range(255)):
|
||||
myMotor.setSpeed(i)
|
||||
time.sleep(0.01)
|
||||
|
||||
print "Backward! "
|
||||
myMotor.run(Adafruit_MotorHAT.BACKWARD)
|
||||
|
||||
print "\tSpeed up..."
|
||||
for i in range(255):
|
||||
myMotor.setSpeed(i)
|
||||
time.sleep(0.01)
|
||||
|
||||
print "\tSlow down..."
|
||||
for i in reversed(range(255)):
|
||||
myMotor.setSpeed(i)
|
||||
time.sleep(0.01)
|
||||
|
||||
print "Release"
|
||||
myMotor.run(Adafruit_MotorHAT.RELEASE)
|
||||
time.sleep(1.0)
|
||||
|
||||
|
||||
|
||||
67
examples/DualStepperTest.py
Normal file
67
examples/DualStepperTest.py
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/python
|
||||
from Adafruit_MotorHAT import Adafruit_MotorHAT, Adafruit_DCMotor, Adafruit_StepperMotor
|
||||
import time
|
||||
import atexit
|
||||
import threading
|
||||
import random
|
||||
|
||||
# create a default object, no changes to I2C address or frequency
|
||||
mh = Adafruit_MotorHAT()
|
||||
|
||||
# create empty threads (these will hold the stepper 1 and 2 threads)
|
||||
st1 = threading.Thread()
|
||||
st2 = threading.Thread()
|
||||
|
||||
|
||||
# recommended for auto-disabling motors on shutdown!
|
||||
def turnOffMotors():
|
||||
mh.getMotor(1).run(Adafruit_MotorHAT.RELEASE)
|
||||
mh.getMotor(2).run(Adafruit_MotorHAT.RELEASE)
|
||||
mh.getMotor(3).run(Adafruit_MotorHAT.RELEASE)
|
||||
mh.getMotor(4).run(Adafruit_MotorHAT.RELEASE)
|
||||
|
||||
atexit.register(turnOffMotors)
|
||||
|
||||
myStepper1 = mh.getStepper(200, 1) # 200 steps/rev, motor port #1
|
||||
myStepper2 = mh.getStepper(200, 2) # 200 steps/rev, motor port #1
|
||||
myStepper1.setSpeed(60) # 30 RPM
|
||||
myStepper2.setSpeed(60) # 30 RPM
|
||||
|
||||
|
||||
stepstyles = [Adafruit_MotorHAT.SINGLE, Adafruit_MotorHAT.DOUBLE, Adafruit_MotorHAT.INTERLEAVE, Adafruit_MotorHAT.MICROSTEP]
|
||||
|
||||
def stepper_worker(stepper, numsteps, direction, style):
|
||||
#print("Steppin!")
|
||||
stepper.step(numsteps, direction, style)
|
||||
#print("Done")
|
||||
|
||||
while (True):
|
||||
if not st1.isAlive():
|
||||
randomdir = random.randint(0, 1)
|
||||
print("Stepper 1"),
|
||||
if (randomdir == 0):
|
||||
dir = Adafruit_MotorHAT.FORWARD
|
||||
print("forward"),
|
||||
else:
|
||||
dir = Adafruit_MotorHAT.BACKWARD
|
||||
print("backward"),
|
||||
randomsteps = random.randint(10,50)
|
||||
print("%d steps" % randomsteps)
|
||||
st1 = threading.Thread(target=stepper_worker, args=(myStepper1, randomsteps, dir, stepstyles[random.randint(0,3)],))
|
||||
st1.start()
|
||||
|
||||
if not st2.isAlive():
|
||||
print("Stepper 2"),
|
||||
randomdir = random.randint(0, 1)
|
||||
if (randomdir == 0):
|
||||
dir = Adafruit_MotorHAT.FORWARD
|
||||
print("forward"),
|
||||
else:
|
||||
dir = Adafruit_MotorHAT.BACKWARD
|
||||
print("backward"),
|
||||
|
||||
randomsteps = random.randint(10,50)
|
||||
print("%d steps" % randomsteps)
|
||||
|
||||
st2 = threading.Thread(target=stepper_worker, args=(myStepper2, randomsteps, dir, stepstyles[random.randint(0,3)],))
|
||||
st2.start()
|
||||
71
examples/StackingTest.py
Normal file
71
examples/StackingTest.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/python
|
||||
from Adafruit_MotorHAT import Adafruit_MotorHAT, Adafruit_DCMotor, Adafruit_StepperMotor
|
||||
import time
|
||||
import atexit
|
||||
import threading
|
||||
import random
|
||||
|
||||
# bottom hat is default address 0x60
|
||||
bottomhat = Adafruit_MotorHAT(addr=0x60)
|
||||
# top hat has A0 jumper closed, so its address 0x61
|
||||
tophat = Adafruit_MotorHAT(addr=0x61)
|
||||
|
||||
# create empty threads (these will hold the stepper 1, 2 & 3 threads)
|
||||
stepperThreads = [threading.Thread(), threading.Thread(), threading.Thread()]
|
||||
|
||||
# recommended for auto-disabling motors on shutdown!
|
||||
def turnOffMotors():
|
||||
tophat.getMotor(1).run(Adafruit_MotorHAT.RELEASE)
|
||||
tophat.getMotor(2).run(Adafruit_MotorHAT.RELEASE)
|
||||
tophat.getMotor(3).run(Adafruit_MotorHAT.RELEASE)
|
||||
tophat.getMotor(4).run(Adafruit_MotorHAT.RELEASE)
|
||||
bottomhat.getMotor(1).run(Adafruit_MotorHAT.RELEASE)
|
||||
bottomhat.getMotor(2).run(Adafruit_MotorHAT.RELEASE)
|
||||
bottomhat.getMotor(3).run(Adafruit_MotorHAT.RELEASE)
|
||||
bottomhat.getMotor(4).run(Adafruit_MotorHAT.RELEASE)
|
||||
|
||||
atexit.register(turnOffMotors)
|
||||
|
||||
myStepper1 = bottomhat.getStepper(200, 1) # 200 steps/rev, motor port #1
|
||||
myStepper2 = bottomhat.getStepper(200, 2) # 200 steps/rev, motor port #2
|
||||
myStepper3 = tophat.getStepper(200, 1) # 200 steps/rev, motor port #1
|
||||
|
||||
myStepper1.setSpeed(60) # 60 RPM
|
||||
myStepper2.setSpeed(30) # 30 RPM
|
||||
myStepper3.setSpeed(15) # 15 RPM
|
||||
|
||||
# get a DC motor!
|
||||
myMotor = tophat.getMotor(3)
|
||||
# set the speed to start, from 0 (off) to 255 (max speed)
|
||||
myMotor.setSpeed(150)
|
||||
# turn on motor
|
||||
myMotor.run(Adafruit_MotorHAT.FORWARD);
|
||||
|
||||
|
||||
stepstyles = [Adafruit_MotorHAT.SINGLE, Adafruit_MotorHAT.DOUBLE, Adafruit_MotorHAT.INTERLEAVE]
|
||||
steppers = [myStepper1, myStepper2, myStepper3]
|
||||
|
||||
def stepper_worker(stepper, numsteps, direction, style):
|
||||
#print("Steppin!")
|
||||
stepper.step(numsteps, direction, style)
|
||||
#print("Done")
|
||||
|
||||
while (True):
|
||||
for i in range(3):
|
||||
if not stepperThreads[i].isAlive():
|
||||
randomdir = random.randint(0, 1)
|
||||
print("Stepper %d" % i),
|
||||
if (randomdir == 0):
|
||||
dir = Adafruit_MotorHAT.FORWARD
|
||||
print("forward"),
|
||||
else:
|
||||
dir = Adafruit_MotorHAT.BACKWARD
|
||||
print("backward"),
|
||||
randomsteps = random.randint(10,50)
|
||||
print("%d steps" % randomsteps)
|
||||
stepperThreads[i] = threading.Thread(target=stepper_worker, args=(steppers[i], randomsteps, dir, stepstyles[random.randint(0,len(stepstyles)-1)],))
|
||||
stepperThreads[i].start()
|
||||
|
||||
# also, lets switch around the DC motor!
|
||||
myMotor.setSpeed(random.randint(0,255)) # random speed
|
||||
#myMotor.run(random.randint(0,1)) # random forward/back
|
||||
38
examples/StepperTest.py
Normal file
38
examples/StepperTest.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/python
|
||||
#import Adafruit_MotorHAT, Adafruit_DCMotor, Adafruit_Stepper
|
||||
from Adafruit_MotorHAT import Adafruit_MotorHAT, Adafruit_DCMotor, Adafruit_StepperMotor
|
||||
|
||||
import time
|
||||
import atexit
|
||||
|
||||
# create a default object, no changes to I2C address or frequency
|
||||
mh = Adafruit_MotorHAT()
|
||||
|
||||
# recommended for auto-disabling motors on shutdown!
|
||||
def turnOffMotors():
|
||||
mh.getMotor(1).run(Adafruit_MotorHAT.RELEASE)
|
||||
mh.getMotor(2).run(Adafruit_MotorHAT.RELEASE)
|
||||
mh.getMotor(3).run(Adafruit_MotorHAT.RELEASE)
|
||||
mh.getMotor(4).run(Adafruit_MotorHAT.RELEASE)
|
||||
|
||||
atexit.register(turnOffMotors)
|
||||
|
||||
myStepper = mh.getStepper(200, 2) # 200 steps/rev, motor port #1
|
||||
myStepper.setSpeed(30) # 30 RPM
|
||||
|
||||
while (True):
|
||||
print("Single coil steps")
|
||||
myStepper.step(100, Adafruit_MotorHAT.FORWARD, Adafruit_MotorHAT.SINGLE)
|
||||
myStepper.step(100, Adafruit_MotorHAT.BACKWARD, Adafruit_MotorHAT.SINGLE)
|
||||
|
||||
print("Double coil steps")
|
||||
myStepper.step(100, Adafruit_MotorHAT.FORWARD, Adafruit_MotorHAT.DOUBLE)
|
||||
myStepper.step(100, Adafruit_MotorHAT.BACKWARD, Adafruit_MotorHAT.DOUBLE)
|
||||
|
||||
print("Interleaved coil steps")
|
||||
myStepper.step(100, Adafruit_MotorHAT.FORWARD, Adafruit_MotorHAT.INTERLEAVE)
|
||||
myStepper.step(100, Adafruit_MotorHAT.BACKWARD, Adafruit_MotorHAT.INTERLEAVE)
|
||||
|
||||
print("Microsteps")
|
||||
myStepper.step(100, Adafruit_MotorHAT.FORWARD, Adafruit_MotorHAT.MICROSTEP)
|
||||
myStepper.step(100, Adafruit_MotorHAT.BACKWARD, Adafruit_MotorHAT.MICROSTEP)
|
||||
332
ez_setup.py
Normal file
332
ez_setup.py
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
#!/usr/bin/env python
|
||||
"""Bootstrap setuptools installation
|
||||
|
||||
To use setuptools in your package's setup.py, include this
|
||||
file in the same directory and add this to the top of your setup.py::
|
||||
|
||||
from ez_setup import use_setuptools
|
||||
use_setuptools()
|
||||
|
||||
To require a specific version of setuptools, set a download
|
||||
mirror, or use an alternate download directory, simply supply
|
||||
the appropriate options to ``use_setuptools()``.
|
||||
|
||||
This file can also be run as a script to install or upgrade setuptools.
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import zipfile
|
||||
import optparse
|
||||
import subprocess
|
||||
import platform
|
||||
import textwrap
|
||||
import contextlib
|
||||
|
||||
from distutils import log
|
||||
|
||||
try:
|
||||
from site import USER_SITE
|
||||
except ImportError:
|
||||
USER_SITE = None
|
||||
|
||||
DEFAULT_VERSION = "3.5.1"
|
||||
DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
|
||||
|
||||
def _python_cmd(*args):
|
||||
"""
|
||||
Return True if the command succeeded.
|
||||
"""
|
||||
args = (sys.executable,) + args
|
||||
return subprocess.call(args) == 0
|
||||
|
||||
|
||||
def _install(archive_filename, install_args=()):
|
||||
with archive_context(archive_filename):
|
||||
# installing
|
||||
log.warn('Installing Setuptools')
|
||||
if not _python_cmd('setup.py', 'install', *install_args):
|
||||
log.warn('Something went wrong during the installation.')
|
||||
log.warn('See the error message above.')
|
||||
# exitcode will be 2
|
||||
return 2
|
||||
|
||||
|
||||
def _build_egg(egg, archive_filename, to_dir):
|
||||
with archive_context(archive_filename):
|
||||
# building an egg
|
||||
log.warn('Building a Setuptools egg in %s', to_dir)
|
||||
_python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
|
||||
# returning the result
|
||||
log.warn(egg)
|
||||
if not os.path.exists(egg):
|
||||
raise IOError('Could not build the egg.')
|
||||
|
||||
|
||||
def get_zip_class():
|
||||
"""
|
||||
Supplement ZipFile class to support context manager for Python 2.6
|
||||
"""
|
||||
class ContextualZipFile(zipfile.ZipFile):
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.close
|
||||
return zipfile.ZipFile if hasattr(zipfile.ZipFile, '__exit__') else \
|
||||
ContextualZipFile
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def archive_context(filename):
|
||||
# extracting the archive
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
log.warn('Extracting in %s', tmpdir)
|
||||
old_wd = os.getcwd()
|
||||
try:
|
||||
os.chdir(tmpdir)
|
||||
with get_zip_class()(filename) as archive:
|
||||
archive.extractall()
|
||||
|
||||
# going in the directory
|
||||
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
|
||||
os.chdir(subdir)
|
||||
log.warn('Now working in %s', subdir)
|
||||
yield
|
||||
|
||||
finally:
|
||||
os.chdir(old_wd)
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
|
||||
def _do_download(version, download_base, to_dir, download_delay):
|
||||
egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg'
|
||||
% (version, sys.version_info[0], sys.version_info[1]))
|
||||
if not os.path.exists(egg):
|
||||
archive = download_setuptools(version, download_base,
|
||||
to_dir, download_delay)
|
||||
_build_egg(egg, archive, to_dir)
|
||||
sys.path.insert(0, egg)
|
||||
|
||||
# Remove previously-imported pkg_resources if present (see
|
||||
# https://bitbucket.org/pypa/setuptools/pull-request/7/ for details).
|
||||
if 'pkg_resources' in sys.modules:
|
||||
del sys.modules['pkg_resources']
|
||||
|
||||
import setuptools
|
||||
setuptools.bootstrap_install_from = egg
|
||||
|
||||
|
||||
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
|
||||
to_dir=os.curdir, download_delay=15):
|
||||
to_dir = os.path.abspath(to_dir)
|
||||
rep_modules = 'pkg_resources', 'setuptools'
|
||||
imported = set(sys.modules).intersection(rep_modules)
|
||||
try:
|
||||
import pkg_resources
|
||||
except ImportError:
|
||||
return _do_download(version, download_base, to_dir, download_delay)
|
||||
try:
|
||||
pkg_resources.require("setuptools>=" + version)
|
||||
return
|
||||
except pkg_resources.DistributionNotFound:
|
||||
return _do_download(version, download_base, to_dir, download_delay)
|
||||
except pkg_resources.VersionConflict as VC_err:
|
||||
if imported:
|
||||
msg = textwrap.dedent("""
|
||||
The required version of setuptools (>={version}) is not available,
|
||||
and can't be installed while this script is running. Please
|
||||
install a more recent version first, using
|
||||
'easy_install -U setuptools'.
|
||||
|
||||
(Currently using {VC_err.args[0]!r})
|
||||
""").format(VC_err=VC_err, version=version)
|
||||
sys.stderr.write(msg)
|
||||
sys.exit(2)
|
||||
|
||||
# otherwise, reload ok
|
||||
del pkg_resources, sys.modules['pkg_resources']
|
||||
return _do_download(version, download_base, to_dir, download_delay)
|
||||
|
||||
def _clean_check(cmd, target):
|
||||
"""
|
||||
Run the command to download target. If the command fails, clean up before
|
||||
re-raising the error.
|
||||
"""
|
||||
try:
|
||||
subprocess.check_call(cmd)
|
||||
except subprocess.CalledProcessError:
|
||||
if os.access(target, os.F_OK):
|
||||
os.unlink(target)
|
||||
raise
|
||||
|
||||
def download_file_powershell(url, target):
|
||||
"""
|
||||
Download the file at url to target using Powershell (which will validate
|
||||
trust). Raise an exception if the command cannot complete.
|
||||
"""
|
||||
target = os.path.abspath(target)
|
||||
cmd = [
|
||||
'powershell',
|
||||
'-Command',
|
||||
"(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" % vars(),
|
||||
]
|
||||
_clean_check(cmd, target)
|
||||
|
||||
def has_powershell():
|
||||
if platform.system() != 'Windows':
|
||||
return False
|
||||
cmd = ['powershell', '-Command', 'echo test']
|
||||
devnull = open(os.path.devnull, 'wb')
|
||||
try:
|
||||
try:
|
||||
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
||||
except Exception:
|
||||
return False
|
||||
finally:
|
||||
devnull.close()
|
||||
return True
|
||||
|
||||
download_file_powershell.viable = has_powershell
|
||||
|
||||
def download_file_curl(url, target):
|
||||
cmd = ['curl', url, '--silent', '--output', target]
|
||||
_clean_check(cmd, target)
|
||||
|
||||
def has_curl():
|
||||
cmd = ['curl', '--version']
|
||||
devnull = open(os.path.devnull, 'wb')
|
||||
try:
|
||||
try:
|
||||
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
||||
except Exception:
|
||||
return False
|
||||
finally:
|
||||
devnull.close()
|
||||
return True
|
||||
|
||||
download_file_curl.viable = has_curl
|
||||
|
||||
def download_file_wget(url, target):
|
||||
cmd = ['wget', url, '--quiet', '--output-document', target]
|
||||
_clean_check(cmd, target)
|
||||
|
||||
def has_wget():
|
||||
cmd = ['wget', '--version']
|
||||
devnull = open(os.path.devnull, 'wb')
|
||||
try:
|
||||
try:
|
||||
subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
|
||||
except Exception:
|
||||
return False
|
||||
finally:
|
||||
devnull.close()
|
||||
return True
|
||||
|
||||
download_file_wget.viable = has_wget
|
||||
|
||||
def download_file_insecure(url, target):
|
||||
"""
|
||||
Use Python to download the file, even though it cannot authenticate the
|
||||
connection.
|
||||
"""
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib2 import urlopen
|
||||
src = dst = None
|
||||
try:
|
||||
src = urlopen(url)
|
||||
# Read/write all in one block, so we don't create a corrupt file
|
||||
# if the download is interrupted.
|
||||
data = src.read()
|
||||
dst = open(target, "wb")
|
||||
dst.write(data)
|
||||
finally:
|
||||
if src:
|
||||
src.close()
|
||||
if dst:
|
||||
dst.close()
|
||||
|
||||
download_file_insecure.viable = lambda: True
|
||||
|
||||
def get_best_downloader():
|
||||
downloaders = [
|
||||
download_file_powershell,
|
||||
download_file_curl,
|
||||
download_file_wget,
|
||||
download_file_insecure,
|
||||
]
|
||||
|
||||
for dl in downloaders:
|
||||
if dl.viable():
|
||||
return dl
|
||||
|
||||
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
|
||||
to_dir=os.curdir, delay=15, downloader_factory=get_best_downloader):
|
||||
"""
|
||||
Download setuptools from a specified location and return its filename
|
||||
|
||||
`version` should be a valid setuptools version number that is available
|
||||
as an egg for download under the `download_base` URL (which should end
|
||||
with a '/'). `to_dir` is the directory where the egg will be downloaded.
|
||||
`delay` is the number of seconds to pause before an actual download
|
||||
attempt.
|
||||
|
||||
``downloader_factory`` should be a function taking no arguments and
|
||||
returning a function for downloading a URL to a target.
|
||||
"""
|
||||
# making sure we use the absolute path
|
||||
to_dir = os.path.abspath(to_dir)
|
||||
zip_name = "setuptools-%s.zip" % version
|
||||
url = download_base + zip_name
|
||||
saveto = os.path.join(to_dir, zip_name)
|
||||
if not os.path.exists(saveto): # Avoid repeated downloads
|
||||
log.warn("Downloading %s", url)
|
||||
downloader = downloader_factory()
|
||||
downloader(url, saveto)
|
||||
return os.path.realpath(saveto)
|
||||
|
||||
def _build_install_args(options):
|
||||
"""
|
||||
Build the arguments to 'python setup.py install' on the setuptools package
|
||||
"""
|
||||
return ['--user'] if options.user_install else []
|
||||
|
||||
def _parse_args():
|
||||
"""
|
||||
Parse the command line for options
|
||||
"""
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option(
|
||||
'--user', dest='user_install', action='store_true', default=False,
|
||||
help='install in user site package (requires Python 2.6 or later)')
|
||||
parser.add_option(
|
||||
'--download-base', dest='download_base', metavar="URL",
|
||||
default=DEFAULT_URL,
|
||||
help='alternative URL from where to download the setuptools package')
|
||||
parser.add_option(
|
||||
'--insecure', dest='downloader_factory', action='store_const',
|
||||
const=lambda: download_file_insecure, default=get_best_downloader,
|
||||
help='Use internal, non-validating downloader'
|
||||
)
|
||||
parser.add_option(
|
||||
'--version', help="Specify which version to download",
|
||||
default=DEFAULT_VERSION,
|
||||
)
|
||||
options, args = parser.parse_args()
|
||||
# positional arguments are ignored
|
||||
return options
|
||||
|
||||
def main():
|
||||
"""Install or upgrade setuptools and EasyInstall"""
|
||||
options = _parse_args()
|
||||
archive = download_setuptools(
|
||||
version=options.version,
|
||||
download_base=options.download_base,
|
||||
downloader_factory=options.downloader_factory,
|
||||
)
|
||||
return _install(archive, _build_install_args(options))
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
14
setup.py
Normal file
14
setup.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
from ez_setup import use_setuptools
|
||||
use_setuptools()
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(name = 'Adafruit_MotorHAT',
|
||||
version = '1.0.0',
|
||||
author = 'Limor Fried',
|
||||
author_email = 'support@adafruit.com',
|
||||
description = 'Library for Adafruit Motor HAT',
|
||||
license = 'MIT',
|
||||
url = 'https://github.com/adafruit/Adafruit_Python_MotorHAT/',
|
||||
dependency_links = ['https://github.com/adafruit/Adafruit_Python_GPIO/tarball/master#egg=Adafruit-GPIO-0.7'],
|
||||
install_requires = ['Adafruit-GPIO>=0.7'],
|
||||
packages = find_packages())
|
||||
Loading…
Reference in a new issue