init
This commit is contained in:
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())
|
||||||
Reference in New Issue
Block a user