From fbc0c001927bbf49f0dc0851893e6eba87099808 Mon Sep 17 00:00:00 2001 From: shrkey Date: Sat, 13 Aug 2016 20:48:37 +0100 Subject: [PATCH] Big update Needs testing --- C++/README.md | 2 - Python/README.md | 2 - Python/dwescape/dwescapeHAT.py | 144 - README.md | 11 +- .../Adafruit_I2C.py | 0 .../Adafruit_PWM_Servo_Driver.py | 0 darkwater_escape/GPIO.py | 426 ++ darkwater_escape/I2C.py | 200 + darkwater_escape/PCA9685.py | 167 + darkwater_escape/Platform.py | 106 + darkwater_escape/SPI.py | 336 ++ .../dwescape => darkwater_escape}/__init__.py | 0 darkwater_escape/darkwater_escape.py | 249 + {Python/examples => examples}/escapetest.py | 0 hardware/Mk2/ESCapemk2.brd | 3267 ----------- hardware/Mk2/ESCapemk2.sch | 4786 ----------------- hardware/Mk2/ESCapemk2.zip | Bin 92938 -> 0 bytes hardware/readme.md | 1 - license.txt | 425 -- 19 files changed, 1486 insertions(+), 8636 deletions(-) delete mode 100644 C++/README.md delete mode 100644 Python/README.md delete mode 100644 Python/dwescape/dwescapeHAT.py rename {Python/dwescape => darkwater_escape}/Adafruit_I2C.py (100%) rename {Python/dwescape => darkwater_escape}/Adafruit_PWM_Servo_Driver.py (100%) create mode 100644 darkwater_escape/GPIO.py create mode 100644 darkwater_escape/I2C.py create mode 100644 darkwater_escape/PCA9685.py create mode 100644 darkwater_escape/Platform.py create mode 100644 darkwater_escape/SPI.py rename {Python/dwescape => darkwater_escape}/__init__.py (100%) create mode 100644 darkwater_escape/darkwater_escape.py rename {Python/examples => examples}/escapetest.py (100%) delete mode 100644 hardware/Mk2/ESCapemk2.brd delete mode 100644 hardware/Mk2/ESCapemk2.sch delete mode 100644 hardware/Mk2/ESCapemk2.zip delete mode 100644 hardware/readme.md delete mode 100644 license.txt diff --git a/C++/README.md b/C++/README.md deleted file mode 100644 index 1b794bf..0000000 --- a/C++/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# escape -Library for the escape board diff --git a/Python/README.md b/Python/README.md deleted file mode 100644 index 1b794bf..0000000 --- a/Python/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# escape -Library for the escape board diff --git a/Python/dwescape/dwescapeHAT.py b/Python/dwescape/dwescapeHAT.py deleted file mode 100644 index e3b02a1..0000000 --- a/Python/dwescape/dwescapeHAT.py +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/python - -import RPi.GPIO as GPIO -from Adafruit_PWM_Servo_Driver import PWM -import time -import math - -class dw_PWM: - def __init__(self, controller, num, freq): - - _SERVO_MIN_MS = 1.250 #ms - _SERVO_MAX_MS = 1.750 #ms - - self.speed = 0 - self.MC = controller - self.cnum = num - self.pin = 0 - - self.freq = freq - - self.servo_min = math.trunc( ( _SERVO_MIN_MS * 4096 ) / (1000.0 / self.freq ) - 1 ) - self.servo_max = math.trunc( ( _SERVO_MAX_MS * 4096 ) / (1000.0 / self.freq ) - 1 ) - - self.servo_zero = math.trunc( ( self.servo_min + self.servo_max ) / 2 ) # halfway = 0 degrees - - - if (num == 0): - self.pin = 9 - elif (num == 1): - self.pin = 8 - elif (num == 2): - self.pin = 10 - elif (num == 3): - self.pin = 11 - elif (num == 4): - self.pin = 12 - elif (num == 5): - self.pin = 13 - elif (num == 6): - self.pin = 0 - elif (num == 7): - self.pin = 1 - elif (num == 8): - self.pin = 2 - elif (num == 9): - self.pin = 3 - elif (num == 10): - self.pin = 5 - elif (num == 11): - self.pin = 4 - else: - raise NameError('Port must be between 1 and 12 inclusive') - - # switch off - self.off() - - def off(self): - self.MC.setPin(self.pin, 0) - - def setAngle(self, angle): - pulse = self.servo_zero + ( (self.servo_zero - self.servo_min ) * angle / 80 ) - print "angle=%s pulse=%s" % (angle, pulse) - #self.setPWMmS( pulse ) - - def setPWM(self, value): - if(value > 0): - self.MC._pwm.setPWM(self.pin, 0, int(value) ) - if(value == 0): - self.off() - - def setPWMmS(self, length_ms): - self.setPWM( round( length_ms * 4096 ) / ( 1000 / self.freq ) ) - - def setPWMuS(self, length_us): - self.setPWM( round( length_us * 4096 ) / ( 1000000 / self.freq ) ) - - def run(self, command, speed = 0): - if not self.MC: - return - - -class dw_PWMCONTROL: - - def __init__(self, addr = 0x61, freq = 100, correctionFactor = 1.0): - self._i2caddr = addr # default addr on HAT - self._frequency = freq # default @60Hz PWM freq - # self.steppers = [ Adafruit_StepperMotor(self, 1), Adafruit_StepperMotor(self, 2) ] - self._pwm = PWM(addr, debug=False) - self._pwm.setPWMFreq(self._frequency, correctionFactor) - # Just gonna default to high for now - - self.servo = [ dw_PWM(self, m, freq) for m in range(6) ] - self.esc = [ dw_PWM(self, m, freq) for m in range(6, 12) ] - - 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 setAllPin(self, 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.setAllPWM(0, 4096) - if (value == 1): - self._pwm.setAllPWM(4096, 0) - - def getESC(self, num): - if (num < 1) or (num > 6): - raise NameError('ESC must be between 1 and 6 inclusive') - return self.esc[num-1] - - def getSERVO(self, num): - if (num < 1) or (num > 6): - raise NameError('Servo must be between 1 and 6 inclusive') - return self.servo[num-1] - - def setAllPWM(self, value): - if(value > 0): - self._pwm.setAllPWM(0, value) - if(value == 0): - self.allOff() - - def setAllPWMmS(self, value): - if(value > 0): - self._pwm.setAllPWM(0, value) - if(value == 0): - self.allOff() - - def setAllPWMuS(self, value): - if(value > 0): - self._pwm.setAllPWM(0, value) - if(value == 0): - self.allOff() - - def allOff(self): - this.setAllPin( 0 ); diff --git a/README.md b/README.md index ca7aaf1..1b794bf 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,2 @@ -# ESCAPE ESC powered motor driver -Files for the escape board - -#License - -Designed by Dark Water. Distributed under a Creative Commons Attribution, Share-Alike license. -Development kits based on this product should be distributed under a similar license. -Commercial products using the Escape boards as a reference design need not comply with this license; further questions can be sent to team@darkwater.io. -Check license.txt for more information. +# escape +Library for the escape board diff --git a/Python/dwescape/Adafruit_I2C.py b/darkwater_escape/Adafruit_I2C.py similarity index 100% rename from Python/dwescape/Adafruit_I2C.py rename to darkwater_escape/Adafruit_I2C.py diff --git a/Python/dwescape/Adafruit_PWM_Servo_Driver.py b/darkwater_escape/Adafruit_PWM_Servo_Driver.py similarity index 100% rename from Python/dwescape/Adafruit_PWM_Servo_Driver.py rename to darkwater_escape/Adafruit_PWM_Servo_Driver.py diff --git a/darkwater_escape/GPIO.py b/darkwater_escape/GPIO.py new file mode 100644 index 0000000..f32ffcc --- /dev/null +++ b/darkwater_escape/GPIO.py @@ -0,0 +1,426 @@ +# Copyright (c) 2014 Adafruit Industries +# Author: Tony DiCola +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import Platform as Platform + + +OUT = 0 +IN = 1 +HIGH = True +LOW = False + +RISING = 1 +FALLING = 2 +BOTH = 3 + +PUD_OFF = 0 +PUD_DOWN = 1 +PUD_UP = 2 + +class BaseGPIO(object): + """Base class for implementing simple digital IO for a platform. + Implementors are expected to subclass from this and provide an implementation + of the setup, output, and input functions.""" + + def setup(self, pin, mode, pull_up_down=PUD_OFF): + """Set the input or output mode for a specified pin. Mode should be + either OUT or IN.""" + raise NotImplementedError + + def output(self, pin, value): + """Set the specified pin the provided high/low value. Value should be + either HIGH/LOW or a boolean (true = high).""" + raise NotImplementedError + + def input(self, pin): + """Read the specified pin and return HIGH/true if the pin is pulled high, + or LOW/false if pulled low.""" + raise NotImplementedError + + def set_high(self, pin): + """Set the specified pin HIGH.""" + self.output(pin, HIGH) + + def set_low(self, pin): + """Set the specified pin LOW.""" + self.output(pin, LOW) + + def is_high(self, pin): + """Return true if the specified pin is pulled high.""" + return self.input(pin) == HIGH + + def is_low(self, pin): + """Return true if the specified pin is pulled low.""" + return self.input(pin) == LOW + + +# Basic implementation of multiple pin methods just loops through pins and +# processes each one individually. This is not optimal, but derived classes can +# provide a more optimal implementation that deals with groups of pins +# simultaneously. +# See MCP230xx or PCF8574 classes for examples of optimized implementations. + + def output_pins(self, pins): + """Set multiple pins high or low at once. Pins should be a dict of pin + name to pin value (HIGH/True for 1, LOW/False for 0). All provided pins + will be set to the given values. + """ + # General implementation just loops through pins and writes them out + # manually. This is not optimized, but subclasses can choose to implement + # a more optimal batch output implementation. See the MCP230xx class for + # example of optimized implementation. + for pin, value in iter(pins.items()): + self.output(pin, value) + + def setup_pins(self, pins): + """Setup multiple pins as inputs or outputs at once. Pins should be a + dict of pin name to pin type (IN or OUT). + """ + # General implementation that can be optimized by derived classes. + for pin, value in iter(pins.items()): + self.setup(pin, value) + + def input_pins(self, pins): + """Read multiple pins specified in the given list and return list of pin values + GPIO.HIGH/True if the pin is pulled high, or GPIO.LOW/False if pulled low. + """ + # General implementation that can be optimized by derived classes. + return [self.input(pin) for pin in pins] + + + def add_event_detect(self, pin, edge): + """Enable edge detection events for a particular GPIO channel. Pin + should be type IN. Edge must be RISING, FALLING or BOTH. + """ + raise NotImplementedError + + def remove_event_detect(self, pin): + """Remove edge detection for a particular GPIO channel. Pin should be + type IN. + """ + raise NotImplementedError + + def add_event_callback(self, pin, callback): + """Add a callback for an event already defined using add_event_detect(). + Pin should be type IN. + """ + raise NotImplementedError + + def event_detected(self, pin): + """Returns True if an edge has occured on a given GPIO. You need to + enable edge detection using add_event_detect() first. Pin should be + type IN. + """ + raise NotImplementedError + + def wait_for_edge(self, pin, edge): + """Wait for an edge. Pin should be type IN. Edge must be RISING, + FALLING or BOTH.""" + raise NotImplementedError + + def cleanup(self, pin=None): + """Clean up GPIO event detection for specific pin, or all pins if none + is specified. + """ + raise NotImplementedError + + +# helper functions useful to derived classes + + def _validate_pin(self, pin): + # Raise an exception if pin is outside the range of allowed values. + if pin < 0 or pin >= self.NUM_GPIO: + raise ValueError('Invalid GPIO value, must be between 0 and {0}.'.format(self.NUM_GPIO)) + + def _bit2(self, src, bit, val): + bit = 1 << bit + return (src | bit) if val else (src & ~bit) + + +class RPiGPIOAdapter(BaseGPIO): + """GPIO implementation for the Raspberry Pi using the RPi.GPIO library.""" + + def __init__(self, rpi_gpio, mode=None): + self.rpi_gpio = rpi_gpio + # Suppress warnings about GPIO in use. + rpi_gpio.setwarnings(False) + # Setup board pin mode. + if mode == rpi_gpio.BOARD or mode == rpi_gpio.BCM: + rpi_gpio.setmode(mode) + elif mode is not None: + raise ValueError('Unexpected value for mode. Must be BOARD or BCM.') + else: + # Default to BCM numbering if not told otherwise. + rpi_gpio.setmode(rpi_gpio.BCM) + # Define mapping of Adafruit GPIO library constants to RPi.GPIO constants. + self._dir_mapping = { OUT: rpi_gpio.OUT, + IN: rpi_gpio.IN } + self._pud_mapping = { PUD_OFF: rpi_gpio.PUD_OFF, + PUD_DOWN: rpi_gpio.PUD_DOWN, + PUD_UP: rpi_gpio.PUD_UP } + self._edge_mapping = { RISING: rpi_gpio.RISING, + FALLING: rpi_gpio.FALLING, + BOTH: rpi_gpio.BOTH } + + def setup(self, pin, mode, pull_up_down=PUD_OFF): + """Set the input or output mode for a specified pin. Mode should be + either OUTPUT or INPUT. + """ + self.rpi_gpio.setup(pin, self._dir_mapping[mode], + pull_up_down=self._pud_mapping[pull_up_down]) + + def output(self, pin, value): + """Set the specified pin the provided high/low value. Value should be + either HIGH/LOW or a boolean (true = high). + """ + self.rpi_gpio.output(pin, value) + + def input(self, pin): + """Read the specified pin and return HIGH/true if the pin is pulled high, + or LOW/false if pulled low. + """ + return self.rpi_gpio.input(pin) + + def input_pins(self, pins): + """Read multiple pins specified in the given list and return list of pin values + GPIO.HIGH/True if the pin is pulled high, or GPIO.LOW/False if pulled low. + """ + # maybe rpi has a mass read... it would be more efficient to use it if it exists + return [self.rpi_gpio.input(pin) for pin in pins] + + def add_event_detect(self, pin, edge, callback=None, bouncetime=-1): + """Enable edge detection events for a particular GPIO channel. Pin + should be type IN. Edge must be RISING, FALLING or BOTH. Callback is a + function for the event. Bouncetime is switch bounce timeout in ms for + callback + """ + kwargs = {} + if callback: + kwargs['callback']=callback + if bouncetime > 0: + kwargs['bouncetime']=bouncetime + self.rpi_gpio.add_event_detect(pin, self._edge_mapping[edge], **kwargs) + + def remove_event_detect(self, pin): + """Remove edge detection for a particular GPIO channel. Pin should be + type IN. + """ + self.rpi_gpio.remove_event_detect(pin) + + def add_event_callback(self, pin, callback): + """Add a callback for an event already defined using add_event_detect(). + Pin should be type IN. + """ + self.rpi_gpio.add_event_callback(pin, callback) + + def event_detected(self, pin): + """Returns True if an edge has occured on a given GPIO. You need to + enable edge detection using add_event_detect() first. Pin should be + type IN. + """ + return self.rpi_gpio.event_detected(pin) + + def wait_for_edge(self, pin, edge): + """Wait for an edge. Pin should be type IN. Edge must be RISING, + FALLING or BOTH. + """ + self.rpi_gpio.wait_for_edge(pin, self._edge_mapping[edge]) + + def cleanup(self, pin=None): + """Clean up GPIO event detection for specific pin, or all pins if none + is specified. + """ + if pin is None: + self.rpi_gpio.cleanup() + else: + self.rpi_gpio.cleanup(pin) + +class AdafruitBBIOAdapter(BaseGPIO): + """GPIO implementation for the Beaglebone Black using the Adafruit_BBIO + library. + """ + + def __init__(self, bbio_gpio): + self.bbio_gpio = bbio_gpio + # Define mapping of Adafruit GPIO library constants to RPi.GPIO constants. + self._dir_mapping = { OUT: bbio_gpio.OUT, + IN: bbio_gpio.IN } + self._pud_mapping = { PUD_OFF: bbio_gpio.PUD_OFF, + PUD_DOWN: bbio_gpio.PUD_DOWN, + PUD_UP: bbio_gpio.PUD_UP } + self._edge_mapping = { RISING: bbio_gpio.RISING, + FALLING: bbio_gpio.FALLING, + BOTH: bbio_gpio.BOTH } + + def setup(self, pin, mode, pull_up_down=PUD_OFF): + """Set the input or output mode for a specified pin. Mode should be + either OUTPUT or INPUT. + """ + self.bbio_gpio.setup(pin, self._dir_mapping[mode], + pull_up_down=self._pud_mapping[pull_up_down]) + + def output(self, pin, value): + """Set the specified pin the provided high/low value. Value should be + either HIGH/LOW or a boolean (true = high). + """ + self.bbio_gpio.output(pin, value) + + def input(self, pin): + """Read the specified pin and return HIGH/true if the pin is pulled high, + or LOW/false if pulled low. + """ + return self.bbio_gpio.input(pin) + + def input_pins(self, pins): + """Read multiple pins specified in the given list and return list of pin values + GPIO.HIGH/True if the pin is pulled high, or GPIO.LOW/False if pulled low. + """ + # maybe bbb has a mass read... it would be more efficient to use it if it exists + return [self.bbio_gpio.input(pin) for pin in pins] + + def add_event_detect(self, pin, edge, callback=None, bouncetime=-1): + """Enable edge detection events for a particular GPIO channel. Pin + should be type IN. Edge must be RISING, FALLING or BOTH. Callback is a + function for the event. Bouncetime is switch bounce timeout in ms for + callback + """ + kwargs = {} + if callback: + kwargs['callback']=callback + if bouncetime > 0: + kwargs['bouncetime']=bouncetime + self.bbio_gpio.add_event_detect(pin, self._edge_mapping[edge], **kwargs) + + def remove_event_detect(self, pin): + """Remove edge detection for a particular GPIO channel. Pin should be + type IN. + """ + self.bbio_gpio.remove_event_detect(pin) + + def add_event_callback(self, pin, callback, bouncetime=-1): + """Add a callback for an event already defined using add_event_detect(). + Pin should be type IN. Bouncetime is switch bounce timeout in ms for + callback + """ + kwargs = {} + if bouncetime > 0: + kwargs['bouncetime']=bouncetime + self.bbio_gpio.add_event_callback(pin, callback, **kwargs) + + def event_detected(self, pin): + """Returns True if an edge has occured on a given GPIO. You need to + enable edge detection using add_event_detect() first. Pin should be + type IN. + """ + return self.bbio_gpio.event_detected(pin) + + def wait_for_edge(self, pin, edge): + """Wait for an edge. Pin should be type IN. Edge must be RISING, + FALLING or BOTH. + """ + self.bbio_gpio.wait_for_edge(pin, self._edge_mapping[edge]) + + def cleanup(self, pin=None): + """Clean up GPIO event detection for specific pin, or all pins if none + is specified. + """ + if pin is None: + self.bbio_gpio.cleanup() + else: + self.bbio_gpio.cleanup(pin) + +class AdafruitMinnowAdapter(BaseGPIO): + """GPIO implementation for the Minnowboard + MAX using the mraa library""" + + def __init__(self,mraa_gpio): + self.mraa_gpio = mraa_gpio + # Define mapping of Adafruit GPIO library constants to mraa constants + self._dir_mapping = { OUT: self.mraa_gpio.DIR_OUT, + IN: self.mraa_gpio.DIR_IN } + self._pud_mapping = { PUD_OFF: self.mraa_gpio.MODE_STRONG, + PUD_UP: self.mraa_gpio.MODE_HIZ, + PUD_DOWN: self.mraa_gpio.MODE_PULLDOWN } + self._edge_mapping = { RISING: self.mraa_gpio.EDGE_RISING, + FALLING: self.mraa_gpio.EDGE_FALLING, + BOTH: self.mraa_gpio.EDGE_BOTH } + + def setup(self,pin,mode): + """Set the input or output mode for a specified pin. Mode should be + either DIR_IN or DIR_OUT. + """ + self.mraa_gpio.Gpio.dir(self.mraa_gpio.Gpio(pin),self._dir_mapping[mode]) + + def output(self,pin,value): + """Set the specified pin the provided high/low value. Value should be + either 1 (ON or HIGH), or 0 (OFF or LOW) or a boolean. + """ + self.mraa_gpio.Gpio.write(self.mraa_gpio.Gpio(pin), value) + + def input(self,pin): + """Read the specified pin and return HIGH/true if the pin is pulled high, + or LOW/false if pulled low. + """ + return self.mraa_gpio.Gpio.read(self.mraa_gpio.Gpio(pin)) + + def add_event_detect(self, pin, edge, callback=None, bouncetime=-1): + """Enable edge detection events for a particular GPIO channel. Pin + should be type IN. Edge must be RISING, FALLING or BOTH. Callback is a + function for the event. Bouncetime is switch bounce timeout in ms for + callback + """ + kwargs = {} + if callback: + kwargs['callback']=callback + if bouncetime > 0: + kwargs['bouncetime']=bouncetime + self.mraa_gpio.Gpio.isr(self.mraa_gpio.Gpio(pin), self._edge_mapping[edge], **kwargs) + + def remove_event_detect(self, pin): + """Remove edge detection for a particular GPIO channel. Pin should be + type IN. + """ + self.mraa_gpio.Gpio.isrExit(self.mraa_gpio.Gpio(pin)) + + def wait_for_edge(self, pin, edge): + """Wait for an edge. Pin should be type IN. Edge must be RISING, + FALLING or BOTH. + """ + self.bbio_gpio.wait_for_edge(self.mraa_gpio.Gpio(pin), self._edge_mapping[edge]) + +def get_platform_gpio(**keywords): + """Attempt to return a GPIO instance for the platform which the code is being + executed on. Currently supports only the Raspberry Pi using the RPi.GPIO + library and Beaglebone Black using the Adafruit_BBIO library. Will throw an + exception if a GPIO instance can't be created for the current platform. The + returned GPIO object is an instance of BaseGPIO. + """ + plat = Platform.platform_detect() + if plat == Platform.RASPBERRY_PI: + import RPi.GPIO + return RPiGPIOAdapter(RPi.GPIO, **keywords) + elif plat == Platform.BEAGLEBONE_BLACK: + import Adafruit_BBIO.GPIO + return AdafruitBBIOAdapter(Adafruit_BBIO.GPIO, **keywords) + elif plat == Platform.MINNOWBOARD: + import mraa + return AdafruitMinnowAdapter(mraa, **keywords) + elif plat == Platform.UNKNOWN: + raise RuntimeError('Could not determine platform.') diff --git a/darkwater_escape/I2C.py b/darkwater_escape/I2C.py new file mode 100644 index 0000000..6097ed5 --- /dev/null +++ b/darkwater_escape/I2C.py @@ -0,0 +1,200 @@ +# Copyright (c) 2014 Adafruit Industries +# Author: Tony DiCola +# Based on Adafruit_I2C.py created by Kevin Townsend. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +import logging +import subprocess + +import Platform as Platform + + +def reverseByteOrder(data): + """Reverses the byte order of an int (16-bit) or long (32-bit) value.""" + # Courtesy Vishal Sapre + byteCount = len(hex(data)[2:].replace('L','')[::2]) + val = 0 + for i in range(byteCount): + val = (val << 8) | (data & 0xff) + data >>= 8 + return val + +def get_default_bus(): + """Return the default bus number based on the device platform. For a + Raspberry Pi either bus 0 or 1 (based on the Pi revision) will be returned. + For a Beaglebone Black the first user accessible bus, 1, will be returned. + """ + plat = Platform.platform_detect() + if plat == Platform.RASPBERRY_PI: + if Platform.pi_revision() == 1: + # Revision 1 Pi uses I2C bus 0. + return 0 + else: + # Revision 2 Pi uses I2C bus 1. + return 1 + elif plat == Platform.BEAGLEBONE_BLACK: + # Beaglebone Black has multiple I2C buses, default to 1 (P9_19 and P9_20). + return 1 + else: + raise RuntimeError('Could not determine default I2C bus for platform.') + +def get_i2c_device(address, busnum=None, i2c_interface=None, **kwargs): + """Return an I2C device for the specified address and on the specified bus. + If busnum isn't specified, the default I2C bus for the platform will attempt + to be detected. + """ + if busnum is None: + busnum = get_default_bus() + return Device(address, busnum, i2c_interface, **kwargs) + +def require_repeated_start(): + """Enable repeated start conditions for I2C register reads. This is the + normal behavior for I2C, however on some platforms like the Raspberry Pi + there are bugs which disable repeated starts unless explicitly enabled with + this function. See this thread for more details: + http://www.raspberrypi.org/forums/viewtopic.php?f=44&t=15840 + """ + plat = Platform.platform_detect() + if plat == Platform.RASPBERRY_PI: + # On the Raspberry Pi there is a bug where register reads don't send a + # repeated start condition like the kernel smbus I2C driver functions + # define. As a workaround this bit in the BCM2708 driver sysfs tree can + # be changed to enable I2C repeated starts. + subprocess.check_call('chmod 666 /sys/module/i2c_bcm2708/parameters/combined', shell=True) + subprocess.check_call('echo -n 1 > /sys/module/i2c_bcm2708/parameters/combined', shell=True) + # Other platforms are a no-op because they (presumably) have the correct + # behavior and send repeated starts. + + +class Device(object): + """Class for communicating with an I2C device using the adafruit-pureio pure + python smbus library, or other smbus compatible I2C interface. Allows reading + and writing 8-bit, 16-bit, and byte array values to registers + on the device.""" + def __init__(self, address, busnum, i2c_interface=None): + """Create an instance of the I2C device at the specified address on the + specified I2C bus number.""" + self._address = address + if i2c_interface is None: + # Use pure python I2C interface if none is specified. + import Adafruit_PureIO.smbus + self._bus = Adafruit_PureIO.smbus.SMBus(busnum) + else: + # Otherwise use the provided class to create an smbus interface. + self._bus = i2c_interface(busnum) + self._logger = logging.getLogger('Adafruit_I2C.Device.Bus.{0}.Address.{1:#0X}' \ + .format(busnum, address)) + + def writeRaw8(self, value): + """Write an 8-bit value on the bus (without register).""" + value = value & 0xFF + self._bus.write_byte(self._address, value) + self._logger.debug("Wrote 0x%02X", + value) + + def write8(self, register, value): + """Write an 8-bit value to the specified register.""" + value = value & 0xFF + self._bus.write_byte_data(self._address, register, value) + self._logger.debug("Wrote 0x%02X to register 0x%02X", + value, register) + + def write16(self, register, value): + """Write a 16-bit value to the specified register.""" + value = value & 0xFFFF + self._bus.write_word_data(self._address, register, value) + self._logger.debug("Wrote 0x%04X to register pair 0x%02X, 0x%02X", + value, register, register+1) + + def writeList(self, register, data): + """Write bytes to the specified register.""" + self._bus.write_i2c_block_data(self._address, register, data) + self._logger.debug("Wrote to register 0x%02X: %s", + register, data) + + def readList(self, register, length): + """Read a length number of bytes from the specified register. Results + will be returned as a bytearray.""" + results = self._bus.read_i2c_block_data(self._address, register, length) + self._logger.debug("Read the following from register 0x%02X: %s", + register, results) + return results + + def readRaw8(self): + """Read an 8-bit value on the bus (without register).""" + result = self._bus.read_byte(self._address) & 0xFF + self._logger.debug("Read 0x%02X", + result) + return result + + def readU8(self, register): + """Read an unsigned byte from the specified register.""" + result = self._bus.read_byte_data(self._address, register) & 0xFF + self._logger.debug("Read 0x%02X from register 0x%02X", + result, register) + return result + + def readS8(self, register): + """Read a signed byte from the specified register.""" + result = self.readU8(register) + if result > 127: + result -= 256 + return result + + def readU16(self, register, little_endian=True): + """Read an unsigned 16-bit value from the specified register, with the + specified endianness (default little endian, or least significant byte + first).""" + result = self._bus.read_word_data(self._address,register) & 0xFFFF + self._logger.debug("Read 0x%04X from register pair 0x%02X, 0x%02X", + result, register, register+1) + # Swap bytes if using big endian because read_word_data assumes little + # endian on ARM (little endian) systems. + if not little_endian: + result = ((result << 8) & 0xFF00) + (result >> 8) + return result + + def readS16(self, register, little_endian=True): + """Read a signed 16-bit value from the specified register, with the + specified endianness (default little endian, or least significant byte + first).""" + result = self.readU16(register, little_endian) + if result > 32767: + result -= 65536 + return result + + def readU16LE(self, register): + """Read an unsigned 16-bit value from the specified register, in little + endian byte order.""" + return self.readU16(register, little_endian=True) + + def readU16BE(self, register): + """Read an unsigned 16-bit value from the specified register, in big + endian byte order.""" + return self.readU16(register, little_endian=False) + + def readS16LE(self, register): + """Read a signed 16-bit value from the specified register, in little + endian byte order.""" + return self.readS16(register, little_endian=True) + + def readS16BE(self, register): + """Read a signed 16-bit value from the specified register, in big + endian byte order.""" + return self.readS16(register, little_endian=False) diff --git a/darkwater_escape/PCA9685.py b/darkwater_escape/PCA9685.py new file mode 100644 index 0000000..09ba060 --- /dev/null +++ b/darkwater_escape/PCA9685.py @@ -0,0 +1,167 @@ +# Copyright (c) 2016 Adafruit Industries +# Author: Tony DiCola +# +# Updated by: Dark Water +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +from __future__ import division +import logging +import time +import math + + +# Registers/etc: +PCA9685_ADDRESS = 0x60 +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 + + +logger = logging.getLogger(__name__) + + +def software_reset(i2c=None, **kwargs): + """Sends a software reset (SWRST) command to all servo drivers on the bus.""" + # Setup I2C interface for device 0x00 to talk to all of them. + if i2c is None: + import I2C as I2C + i2c = I2C + self._device = i2c.get_i2c_device(0x00, **kwargs) + self._device.writeRaw8(0x06) # SWRST + + +class PCA9685(object): + """PCA9685 PWM LED/servo controller.""" + + def __init__(self, address=PCA9685_ADDRESS, i2c=None, **kwargs): + """Initialize the PCA9685.""" + # Setup I2C interface for the device. + if i2c is None: + import I2C as I2C + i2c = I2C + self._device = i2c.get_i2c_device(address, **kwargs) + self.set_all_pwm(0, 0) + self._device.write8(MODE2, OUTDRV) + self._device.write8(MODE1, ALLCALL) + time.sleep(0.005) # wait for oscillator + mode1 = self._device.readU8(MODE1) + mode1 = mode1 & ~SLEEP # wake up (reset sleep) + self._device.write8(MODE1, mode1) + time.sleep(0.005) # wait for oscillator + + def set_pwm_freq(self, freq_hz): + """Set the PWM frequency to the provided value in hertz.""" + prescaleval = 25000000.0 # 25MHz + prescaleval /= 4096.0 # 12-bit + prescaleval /= float(freq_hz) + prescaleval -= 1.0 + logger.debug('Setting PWM frequency to {0} Hz'.format(freq_hz)) + logger.debug('Estimated pre-scale: {0}'.format(prescaleval)) + prescale = int(math.floor(prescaleval + 0.5)) + logger.debug('Final pre-scale: {0}'.format(prescale)) + oldmode = self._device.readU8(MODE1); + newmode = (oldmode & 0x7F) | 0x10 # sleep + self._device.write8(MODE1, newmode) # go to sleep + self._device.write8(PRESCALE, prescale) + self._device.write8(MODE1, oldmode) + time.sleep(0.005) + self._device.write8(MODE1, oldmode | 0x80) + + def set_pwm_freq_min(self, freq_hz, correctionFactor=1.0): + "Sets the PWM frequency" + prescaleval = 25000000.0 # 25MHz + prescaleval /= 4096.0 # 12-bit + prescaleval /= float(freq_hz) + prescaleval -= 1.0 + if (self.debug): + print "Setting PWM frequency to %d Hz" % freq_hz + print "Estimated pre-scale: %d" % prescaleval + prescale = math.floor(prescaleval * correctionFactor + 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 set_pwm_freq_max(self, freq_hz, correctionFactor=1.0): + "Sets the PWM frequency" + prescaleval = 25000000.0 # 25MHz + prescaleval /= 4096.0 # 12-bit + prescaleval /= float(freq_hz) + prescaleval -= 1.0 + if (self.debug): + print "Setting PWM frequency to %d Hz" % freq_hz + print "Estimated pre-scale: %d" % prescaleval + prescale = math.ceil(prescaleval * correctionFactor + 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 get_pwm_freq(self): + prescale = self.i2c.readU8(self.__PRESCALE) + calcfreq = 25000000.0 / 4096.0 / ( float(prescale) + 1 ) + if (self.debug): + print "Got pre-scale: %d" % prescale + print "Calculated Frequency: %d" % calcfreq + + return calcfreq + + def set_pwm(self, channel, on, off): + """Sets a single PWM channel.""" + self._device.write8(LED0_ON_L+4*channel, on & 0xFF) + self._device.write8(LED0_ON_H+4*channel, on >> 8) + self._device.write8(LED0_OFF_L+4*channel, off & 0xFF) + self._device.write8(LED0_OFF_H+4*channel, off >> 8) + + def set_all_pwm(self, on, off): + """Sets all PWM channels.""" + self._device.write8(ALL_LED_ON_L, on & 0xFF) + self._device.write8(ALL_LED_ON_H, on >> 8) + self._device.write8(ALL_LED_OFF_L, off & 0xFF) + self._device.write8(ALL_LED_OFF_H, off >> 8) diff --git a/darkwater_escape/Platform.py b/darkwater_escape/Platform.py new file mode 100644 index 0000000..8ba4ca9 --- /dev/null +++ b/darkwater_escape/Platform.py @@ -0,0 +1,106 @@ +# Copyright (c) 2014 Adafruit Industries +# Author: Tony DiCola + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +import platform +import re + +# Platform identification constants. +UNKNOWN = 0 +RASPBERRY_PI = 1 +BEAGLEBONE_BLACK = 2 +MINNOWBOARD = 3 + +def platform_detect(): + """Detect if running on the Raspberry Pi or Beaglebone Black and return the + platform type. Will return RASPBERRY_PI, BEAGLEBONE_BLACK, or UNKNOWN.""" + # Handle Raspberry Pi + pi = pi_version() + if pi is not None: + return RASPBERRY_PI + + # Handle Beaglebone Black + # TODO: Check the Beaglebone Black /proc/cpuinfo value instead of reading + # the platform. + plat = platform.platform() + if plat.lower().find('armv7l-with-debian') > -1: + return BEAGLEBONE_BLACK + elif plat.lower().find('armv7l-with-ubuntu') > -1: + return BEAGLEBONE_BLACK + elif plat.lower().find('armv7l-with-glibc2.4') > -1: + return BEAGLEBONE_BLACK + + # Handle Minnowboard + # Assumption is that mraa is installed + try: + import mraa + if mraa.getPlatformName()=='MinnowBoard MAX': + return MINNOWBOARD + except ImportError: + pass + + # Couldn't figure out the platform, just return unknown. + return UNKNOWN + + +def pi_revision(): + """Detect the revision number of a Raspberry Pi, useful for changing + functionality like default I2C bus based on revision.""" + # Revision list available at: http://elinux.org/RPi_HardwareHistory#Board_Revision_History + with open('/proc/cpuinfo', 'r') as infile: + for line in infile: + # Match a line of the form "Revision : 0002" while ignoring extra + # info in front of the revsion (like 1000 when the Pi was over-volted). + match = re.match('Revision\s+:\s+.*(\w{4})$', line, flags=re.IGNORECASE) + if match and match.group(1) in ['0000', '0002', '0003']: + # Return revision 1 if revision ends with 0000, 0002 or 0003. + return 1 + elif match: + # Assume revision 2 if revision ends with any other 4 chars. + return 2 + # Couldn't find the revision, throw an exception. + raise RuntimeError('Could not determine Raspberry Pi revision.') + + +def pi_version(): + """Detect the version of the Raspberry Pi. Returns either 1, 2 or + None depending on if it's a Raspberry Pi 1 (model A, B, A+, B+), + Raspberry Pi 2 (model B+), or not a Raspberry Pi. + """ + # Check /proc/cpuinfo for the Hardware field value. + # 2708 is pi 1 + # 2709 is pi 2 + # Anything else is not a pi. + with open('/proc/cpuinfo', 'r') as infile: + cpuinfo = infile.read() + # Match a line like 'Hardware : BCM2709' + match = re.search('^Hardware\s+:\s+(\w+)$', cpuinfo, + flags=re.MULTILINE | re.IGNORECASE) + if not match: + # Couldn't find the hardware, assume it isn't a pi. + return None + if match.group(1) == 'BCM2708': + # Pi 1 + return 1 + elif match.group(1) == 'BCM2709': + # Pi 2 + return 2 + else: + # Something else, not a pi. + return None diff --git a/darkwater_escape/SPI.py b/darkwater_escape/SPI.py new file mode 100644 index 0000000..cfad79b --- /dev/null +++ b/darkwater_escape/SPI.py @@ -0,0 +1,336 @@ +# Copyright (c) 2014 Adafruit Industries +# Author: Tony DiCola +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import operator +import time + +import Adafruit_GPIO as GPIO + + +MSBFIRST = 0 +LSBFIRST = 1 + + +class SpiDev(object): + """Hardware-based SPI implementation using the spidev interface.""" + + def __init__(self, port, device, max_speed_hz=500000): + """Initialize an SPI device using the SPIdev interface. Port and device + identify the device, for example the device /dev/spidev1.0 would be port + 1 and device 0. + """ + import spidev + self._device = spidev.SpiDev() + self._device.open(port, device) + self._device.max_speed_hz=max_speed_hz + # Default to mode 0. + self._device.mode = 0 + + def set_clock_hz(self, hz): + """Set the speed of the SPI clock in hertz. Note that not all speeds + are supported and a lower speed might be chosen by the hardware. + """ + self._device.max_speed_hz=hz + + def set_mode(self, mode): + """Set SPI mode which controls clock polarity and phase. Should be a + numeric value 0, 1, 2, or 3. See wikipedia page for details on meaning: + http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus + """ + if mode < 0 or mode > 3: + raise ValueError('Mode must be a value 0, 1, 2, or 3.') + self._device.mode = mode + + def set_bit_order(self, order): + """Set order of bits to be read/written over serial lines. Should be + either MSBFIRST for most-significant first, or LSBFIRST for + least-signifcant first. + """ + if order == MSBFIRST: + self._device.lsbfirst = False + elif order == LSBFIRST: + self._device.lsbfirst = True + else: + raise ValueError('Order must be MSBFIRST or LSBFIRST.') + + def close(self): + """Close communication with the SPI device.""" + self._device.close() + + def write(self, data): + """Half-duplex SPI write. The specified array of bytes will be clocked + out the MOSI line. + """ + self._device.writebytes(data) + + def read(self, length): + """Half-duplex SPI read. The specified length of bytes will be clocked + in the MISO line and returned as a bytearray object. + """ + return bytearray(self._device.readbytes(length)) + + def transfer(self, data): + """Full-duplex SPI read and write. The specified array of bytes will be + clocked out the MOSI line, while simultaneously bytes will be read from + the MISO line. Read bytes will be returned as a bytearray object. + """ + return bytearray(self._device.xfer2(data)) + +class SpiDevMraa(object): + """Hardware SPI implementation with the mraa library on Minnowboard""" + def __init__(self, port, device, max_speed_hz=500000): + import mraa + self._device = mraa.Spi(0) + self._device.mode(0) + + def set_clock_hz(self, hz): + """Set the speed of the SPI clock in hertz. Note that not all speeds + are supported and a lower speed might be chosen by the hardware. + """ + self._device.frequency(hz) + + def set_mode(self,mode): + """Set SPI mode which controls clock polarity and phase. Should be a + numeric value 0, 1, 2, or 3. See wikipedia page for details on meaning: + http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus + """ + if mode < 0 or mode > 3: + raise ValueError('Mode must be a value 0, 1, 2, or 3.') + self._device.mode(mode) + + def set_mode(self,mode): + """Set SPI mode which controls clock polarity and phase. Should be a + numeric value 0, 1, 2, or 3. See wikipedia page for details on meaning: + http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus + """ + if mode < 0 or mode > 3: + raise ValueError('Mode must be a value 0, 1, 2, or 3.') + self._device.mode(mode) + + def set_bit_order(self, order): + """Set order of bits to be read/written over serial lines. Should be + either MSBFIRST for most-significant first, or LSBFIRST for + least-signifcant first. + """ + if order == MSBFIRST: + self._device.lsbmode(False) + elif order == LSBFIRST: + self._device.lsbmode(True) + else: + raise ValueError('Order must be MSBFIRST or LSBFIRST.') + + def close(self): + """Close communication with the SPI device.""" + self._device.Spi() + + def write(self, data): + """Half-duplex SPI write. The specified array of bytes will be clocked + out the MOSI line. + """ + self._device.write(bytearray(data)) + +class BitBang(object): + """Software-based implementation of the SPI protocol over GPIO pins.""" + + def __init__(self, gpio, sclk, mosi=None, miso=None, ss=None): + """Initialize bit bang (or software) based SPI. Must provide a BaseGPIO + class, the SPI clock, and optionally MOSI, MISO, and SS (slave select) + pin numbers. If MOSI is set to None then writes will be disabled and fail + with an error, likewise for MISO reads will be disabled. If SS is set to + None then SS will not be asserted high/low by the library when + transfering data. + """ + self._gpio = gpio + self._sclk = sclk + self._mosi = mosi + self._miso = miso + self._ss = ss + # Set pins as outputs/inputs. + gpio.setup(sclk, GPIO.OUT) + if mosi is not None: + gpio.setup(mosi, GPIO.OUT) + if miso is not None: + gpio.setup(miso, GPIO.IN) + if ss is not None: + gpio.setup(ss, GPIO.OUT) + # Assert SS high to start with device communication off. + gpio.set_high(ss) + # Assume mode 0. + self.set_mode(0) + # Assume most significant bit first order. + self.set_bit_order(MSBFIRST) + + def set_clock_hz(self, hz): + """Set the speed of the SPI clock. This is unsupported with the bit + bang SPI class and will be ignored. + """ + pass + + def set_mode(self, mode): + """Set SPI mode which controls clock polarity and phase. Should be a + numeric value 0, 1, 2, or 3. See wikipedia page for details on meaning: + http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus + """ + if mode < 0 or mode > 3: + raise ValueError('Mode must be a value 0, 1, 2, or 3.') + if mode & 0x02: + # Clock is normally high in mode 2 and 3. + self._clock_base = GPIO.HIGH + else: + # Clock is normally low in mode 0 and 1. + self._clock_base = GPIO.LOW + if mode & 0x01: + # Read on trailing edge in mode 1 and 3. + self._read_leading = False + else: + # Read on leading edge in mode 0 and 2. + self._read_leading = True + # Put clock into its base state. + self._gpio.output(self._sclk, self._clock_base) + + def set_bit_order(self, order): + """Set order of bits to be read/written over serial lines. Should be + either MSBFIRST for most-significant first, or LSBFIRST for + least-signifcant first. + """ + # Set self._mask to the bitmask which points at the appropriate bit to + # read or write, and appropriate left/right shift operator function for + # reading/writing. + if order == MSBFIRST: + self._mask = 0x80 + self._write_shift = operator.lshift + self._read_shift = operator.rshift + elif order == LSBFIRST: + self._mask = 0x01 + self._write_shift = operator.rshift + self._read_shift = operator.lshift + else: + raise ValueError('Order must be MSBFIRST or LSBFIRST.') + + def close(self): + """Close the SPI connection. Unused in the bit bang implementation.""" + pass + + def write(self, data, assert_ss=True, deassert_ss=True): + """Half-duplex SPI write. If assert_ss is True, the SS line will be + asserted low, the specified bytes will be clocked out the MOSI line, and + if deassert_ss is True the SS line be put back high. + """ + # Fail MOSI is not specified. + if self._mosi is None: + raise RuntimeError('Write attempted with no MOSI pin specified.') + if assert_ss and self._ss is not None: + self._gpio.set_low(self._ss) + for byte in data: + for i in range(8): + # Write bit to MOSI. + if self._write_shift(byte, i) & self._mask: + self._gpio.set_high(self._mosi) + else: + self._gpio.set_low(self._mosi) + # Flip clock off base. + self._gpio.output(self._sclk, not self._clock_base) + # Return clock to base. + self._gpio.output(self._sclk, self._clock_base) + if deassert_ss and self._ss is not None: + self._gpio.set_high(self._ss) + + def read(self, length, assert_ss=True, deassert_ss=True): + """Half-duplex SPI read. If assert_ss is true, the SS line will be + asserted low, the specified length of bytes will be clocked in the MISO + line, and if deassert_ss is true the SS line will be put back high. + Bytes which are read will be returned as a bytearray object. + """ + if self._miso is None: + raise RuntimeError('Read attempted with no MISO pin specified.') + if assert_ss and self._ss is not None: + self._gpio.set_low(self._ss) + result = bytearray(length) + for i in range(length): + for j in range(8): + # Flip clock off base. + self._gpio.output(self._sclk, not self._clock_base) + # Handle read on leading edge of clock. + if self._read_leading: + if self._gpio.is_high(self._miso): + # Set bit to 1 at appropriate location. + result[i] |= self._read_shift(self._mask, j) + else: + # Set bit to 0 at appropriate location. + result[i] &= ~self._read_shift(self._mask, j) + # Return clock to base. + self._gpio.output(self._sclk, self._clock_base) + # Handle read on trailing edge of clock. + if not self._read_leading: + if self._gpio.is_high(self._miso): + # Set bit to 1 at appropriate location. + result[i] |= self._read_shift(self._mask, j) + else: + # Set bit to 0 at appropriate location. + result[i] &= ~self._read_shift(self._mask, j) + if deassert_ss and self._ss is not None: + self._gpio.set_high(self._ss) + return result + + def transfer(self, data, assert_ss=True, deassert_ss=True): + """Full-duplex SPI read and write. If assert_ss is true, the SS line + will be asserted low, the specified bytes will be clocked out the MOSI + line while bytes will also be read from the MISO line, and if + deassert_ss is true the SS line will be put back high. Bytes which are + read will be returned as a bytearray object. + """ + if self._mosi is None: + raise RuntimeError('Write attempted with no MOSI pin specified.') + if self._mosi is None: + raise RuntimeError('Read attempted with no MISO pin specified.') + if assert_ss and self._ss is not None: + self._gpio.set_low(self._ss) + result = bytearray(len(data)) + for i in range(len(data)): + for j in range(8): + # Write bit to MOSI. + if self._write_shift(data[i], j) & self._mask: + self._gpio.set_high(self._mosi) + else: + self._gpio.set_low(self._mosi) + # Flip clock off base. + self._gpio.output(self._sclk, not self._clock_base) + # Handle read on leading edge of clock. + if self._read_leading: + if self._gpio.is_high(self._miso): + # Set bit to 1 at appropriate location. + result[i] |= self._read_shift(self._mask, j) + else: + # Set bit to 0 at appropriate location. + result[i] &= ~self._read_shift(self._mask, j) + # Return clock to base. + self._gpio.output(self._sclk, self._clock_base) + # Handle read on trailing edge of clock. + if not self._read_leading: + if self._gpio.is_high(self._miso): + # Set bit to 1 at appropriate location. + result[i] |= self._read_shift(self._mask, j) + else: + # Set bit to 0 at appropriate location. + result[i] &= ~self._read_shift(self._mask, j) + if deassert_ss and self._ss is not None: + self._gpio.set_high(self._ss) + return result diff --git a/Python/dwescape/__init__.py b/darkwater_escape/__init__.py similarity index 100% rename from Python/dwescape/__init__.py rename to darkwater_escape/__init__.py diff --git a/darkwater_escape/darkwater_escape.py b/darkwater_escape/darkwater_escape.py new file mode 100644 index 0000000..d4d6010 --- /dev/null +++ b/darkwater_escape/darkwater_escape.py @@ -0,0 +1,249 @@ +#!/usr/bin/python + +import RPi.GPIO as GPIO +from PCA9685 import PCA9685 +import time +import math + +class dw_Motor: + def __init__(self, controller, num, freq): + + _SERVO_MIN_MS = 1.250 #ms + _SERVO_MAX_MS = 1.750 #ms + + self.speed = 0 + self.MC = controller + self.cnum = num + self.pin = 0 + + self.freq = freq + + self.servo_min = math.trunc( ( _SERVO_MIN_MS * 4096 ) / (1000.0 / self.freq ) - 1 ) + self.servo_max = math.trunc( ( _SERVO_MAX_MS * 4096 ) / (1000.0 / self.freq ) - 1 ) + + self.servo_zero = math.trunc( ( self.servo_min + self.servo_max ) / 2 ) # halfway = 0 degrees + + + if (num == 0): + self.pin = 9 + elif (num == 1): + self.pin = 8 + elif (num == 2): + self.pin = 10 + elif (num == 3): + self.pin = 11 + elif (num == 4): + self.pin = 12 + elif (num == 5): + self.pin = 13 + elif (num == 6): + self.pin = 0 + elif (num == 7): + self.pin = 1 + elif (num == 8): + self.pin = 2 + elif (num == 9): + self.pin = 3 + elif (num == 10): + self.pin = 5 + elif (num == 11): + self.pin = 4 + else: + raise NameError('Motors must be between 1 and 12 inclusive') + + # switch off + self.off() + + def off(self): + self.MC.setPin(self.pin, 0) + + def setAngle(self, angle): + pulse = self.servo_zero + ( (self.servo_zero - self.servo_min ) * angle / 80 ) + print "angle=%s pulse=%s" % (angle, pulse) + #self.setPWMmS( pulse ) + + def setPWM(self, value): + if(value > 0): + self.MC._pwm.setPWM(self.pin, 0, int(value) ) + if(value == 0): + self.off() + + def setPWMmS(self, length_ms): + self.setPWM( round( length_ms * 4096 ) / ( 1000 / self.freq ) ) + + def setPWMuS(self, length_us): + self.setPWM( round( length_us * 4096 ) / ( 1000000 / self.freq ) ) + + def setMotorSpeed(self, value): + # Check for PWM values + if(value > 1000) and (value < 2000): + self.setPWMmS(value) + # Translate for motor values + if(value > 0) and (value <= 255): + self.setPWMmS( round(translate(value, 0, 255, 1500, 2000))) + if(value == 0): + self.setPWMmS(1500) + if(value < 0) and (value >= -255): + self.setPWMmS(round(translate(abs(value), 0, 255, 1500, 1000))) + + def run(self, command, speed = 0): + if not self.MC: + return + if (command == dw_Controller.FORWARD): + self.MC.setPin(self.PHpin, 0) + self.MC._pwm.set_pwm(self.ENpin, 0, speed*16) + if (command == dw_Controller.BACKWARD): + self.MC.setPin(self.PHpin, 1) + self.MC._pwm.set_pwm(self.ENpin, 0, speed*16) + if (command == dw_Controller.RELEASE): + self.MC.setPin(self.PHpin, 0) + self.MC.setPin(self.ENpin, 0) + +class dw_Servo: + def __init__(self, controller, num, freq): + + _SERVO_MIN_MS = 1.250 #ms + _SERVO_MAX_MS = 1.750 #ms + + self.speed = 0 + self.MC = controller + self.cnum = num + self.pin = 0 + + self.freq = freq + + self.servo_min = math.trunc( ( _SERVO_MIN_MS * 4096 ) / (1000.0 / self.freq ) - 1 ) + self.servo_max = math.trunc( ( _SERVO_MAX_MS * 4096 ) / (1000.0 / self.freq ) - 1 ) + + self.servo_zero = math.trunc( ( self.servo_min + self.servo_max ) / 2 ) # halfway = 0 degrees + + + if (num == 0): + self.pin = 9 + elif (num == 1): + self.pin = 8 + elif (num == 2): + self.pin = 10 + elif (num == 3): + self.pin = 11 + elif (num == 4): + self.pin = 12 + elif (num == 5): + self.pin = 13 + elif (num == 6): + self.pin = 0 + elif (num == 7): + self.pin = 1 + elif (num == 8): + self.pin = 2 + elif (num == 9): + self.pin = 3 + elif (num == 10): + self.pin = 5 + elif (num == 11): + self.pin = 4 + else: + raise NameError('Port must be between 1 and 12 inclusive') + + # switch off + self.off() + + def off(self): + self.MC.setPin(self.pin, 0) + + def setAngle(self, angle): + pulse = self.servo_zero + ( (self.servo_zero - self.servo_min ) * angle / 80 ) + print "angle=%s pulse=%s" % (angle, pulse) + #self.setPWMmS( pulse ) + + def setPWM(self, value): + if(value > 0): + self.MC._pwm.setPWM(self.pin, 0, int(value) ) + if(value == 0): + self.off() + + def setPWMmS(self, length_ms): + self.setPWM( round( length_ms * 4096 ) / ( 1000 / self.freq ) ) + + def setPWMuS(self, length_us): + self.setPWM( round( length_us * 4096 ) / ( 1000000 / self.freq ) ) + + def run(self, command, speed = 0): + if not self.MC: + return + + +class dw_Controller: + + def __init__(self, addr = 0x61, freq = 100, correctionFactor = 1.0): + self._i2caddr = addr # default addr on HAT + self._frequency = freq # default @60Hz PWM freq + # self.steppers = [ Adafruit_StepperMotor(self, 1), Adafruit_StepperMotor(self, 2) ] + self._pwm = PCA9685(addr) + self._pwm.set_pwm_freq(self._frequency, correctionFactor) + # Just gonna default to high for now + + self.servo = [ dw_PWM(self, m, freq) for m in range(6) ] + self.esc = [ dw_PWM(self, m, freq) for m in range(6, 12) ] + + 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.set_pwm(pin, 0, 4096) + if (value == 1): + self._pwm.set_pwm(pin, 4096, 0) + + def setAllPin(self, 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.set_all_pwm(0, 4096) + if (value == 1): + self._pwm.set_all_pwm(4096, 0) + + def getMotor(self, num): + if (num < 1) or (num > 6): + raise NameError('Motors must be between 1 and 6 inclusive') + return self.esc[num-1] + + def getServo(self, num): + if (num < 1) or (num > 6): + raise NameError('Servos must be between 1 and 6 inclusive') + return self.servo[num-1] + + def setAllPWM(self, value): + if(value > 0): + self._pwm.set_all_pwm(0, value) + if(value == 0): + self.allOff() + + def setAllPWMmS(self, value): + if(value > 0): + self._pwm.set_all_pwm(0, value) + if(value == 0): + self.allOff() + + def setAllPWMuS(self, value): + if(value > 0): + self._pwm.set_all_pwm(0, value) + if(value == 0): + self.allOff() + + def allOff(self): + this.setAllPin( 0 ); + +def translate(value, leftMin, leftMax, rightMin, rightMax): + # Figure out how 'wide' each range is + leftSpan = leftMax - leftMin + rightSpan = rightMax - rightMin + + # Convert the left range into a 0-1 range (float) + valueScaled = float(value - leftMin) / float(leftSpan) + + # Convert the 0-1 range into a value in the right range. + return rightMin + (valueScaled * rightSpan) \ No newline at end of file diff --git a/Python/examples/escapetest.py b/examples/escapetest.py similarity index 100% rename from Python/examples/escapetest.py rename to examples/escapetest.py diff --git a/hardware/Mk2/ESCapemk2.brd b/hardware/Mk2/ESCapemk2.brd deleted file mode 100644 index 455e727..0000000 --- a/hardware/Mk2/ESCapemk2.brd +++ /dev/null @@ -1,3267 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -10uF -Born in Liverpool -FD -A0 -A1 -A2 -A3 -A4 -5V -+ -Escape Mk2 -J1 -J2 -POWER -http://darkwater.io -ESC -SERVO -CPPM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -1 ->VALUE ->NAME - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find connectors and sockets- basically anything that can be plugged into or onto.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - ->NAME ->VALUE - - - - - - ->Value ->Name - - -Small solder jumper with no paste layer so it will open after reflow. - - - - - - - - ->NAME ->VALUE - - -Solder jumper, small, shorted with trace. No paste layer. Trace is cuttable. - - - - - - - - - ->NAME ->VALUE - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find all manner of retired footprints for resistors, capacitors, board names, ICs, etc., that are no longer used in our catalog.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b>Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find discrete semiconductors- transistors, diodes, TRIACs, optoisolators, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - - - - ->NAME ->VALUE - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - -<b>Chip Resistor Array</b> size 4 × 0603<p> -convex termination - Phycomp Components<br> -Source: RS Components - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>EAGLE Design Rules</b> -<p> -The default Design Rules have been set to cover -a wide range of applications. Your particular design -may have different requirements, so please make the -necessary adjustments and save your customized -design rules under a new name. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hardware/Mk2/ESCapemk2.sch b/hardware/Mk2/ESCapemk2.sch deleted file mode 100644 index 083c18d..0000000 --- a/hardware/Mk2/ESCapemk2.sch +++ /dev/null @@ -1,4786 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -1 ->VALUE ->NAME - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PCA9685 -16 Channel 12-Bit PWM -VDD: 2.3-5.5V -IO: 5V Safe -Output: 25mA Each/400mA Total -GND EXTCLK when not in use! ->NAME ->VALUE -I2C Address: 1[A5..A0][R/W] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>PCA9685</b> - 16 Channel 12-Bit I2C PWM Controller -<p>5.0V tolerant 16 channel, 12-bit I2C PWM controller with 25mA per output (max. 400mA total)</p> -<p>Digikey: 568-5931-1-ND</p> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -For use by pick and place machines to calibrate the vision/machine, 1mm -<p>By microbuilder.eu</p> - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find connectors and sockets- basically anything that can be plugged into or onto.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -2mm SMD side-entry connector. tDocu layer indicates the actual physical plastic housing. +/- indicate SparkFun standard batteries and wiring. - - - - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - -This footprint was designed to help hold the alignment of a through-hole component (i.e. 6-pin header) while soldering it into place. -You may notice that each hole has been shifted either up or down by 0.005 of an inch from it's more standard position (which is a perfectly straight line). -This slight alteration caused the pins (the squares in the middle) to touch the edges of the holes. Because they are alternating, it causes a "brace" -to hold the component in place. 0.005 has proven to be the perfect amount of "off-center" position when using our standard breakaway headers. -Although looks a little odd when you look at the bare footprint, once you have a header in there, the alteration is very hard to notice. Also, -if you push a header all the way into place, it is covered up entirely on the bottom side. This idea of altering the position of holes to aid alignment -will be further integrated into the Sparkfun Library for other footprints. It can help hold any component with 3 or more connection pins. - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - ->NAME ->VALUE - - - - - - ->Name ->Value -+ -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - ->Name ->Value -+ -- - - -<H3>JST-2-PTH-KIT</h3> -2-Pin JST, through-hole connector<br> -<br> -<b>Warning:</b> This is the KIT version of this package. This package has a smaller diameter top stop mask, which doesn't cover the diameter of the pad. This means only the bottom side of the pads' copper will be exposed. You'll only be able to solder to the bottom side. - - - - - - - - - ->Name ->Value -+ -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->Name ->Value -+ -- - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - -This footprint was designed to help hold the alignment of a through-hole component (i.e. 6-pin header) while soldering it into place. -You may notice that each hole has been shifted either up or down by 0.005 of an inch from it's more standard position (which is a perfectly straight line). -This slight alteration caused the pins (the squares in the middle) to touch the edges of the holes. Because they are alternating, it causes a "brace" -to hold the component in place. 0.005 has proven to be the perfect amount of "off-center" position when using our standard breakaway headers. -Although looks a little odd when you look at the bare footprint, once you have a header in there, the alteration is very hard to notice. Also, -if you push a header all the way into place, it is covered up entirely on the bottom side. This idea of altering the position of holes to aid alignment -will be further integrated into the Sparkfun Library for other footprints. It can help hold any component with 3 or more connection pins. - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - ->NAME ->VALUE - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - ->Name ->Value -+ -- -S - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - ->Value ->Name - - - - - - - - - - - - - - - - - - - - -<h3>SMD 3-Pin Male Right-Angle Header w/ Alignment posts</h3> - -Matches 4UCONN part # 11026<br> -<a href="http://www.4uconnector.com/online/object/4udrawing/11026.pdf">http://www.4uconnector.com/online/object/4udrawing/11026.pdf</a> - - - - - - - - - - - - - - - - - - - - -This 3-pin connector mates with the JST cable sold on SparkFun. - - - - - - - - - - - ->Name ->Value -+ -- -S - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - - - - - - ->VALUE ->NAME - - - - - - - -Standard 2-pin 0.1" header. Use with <br> -- straight break away headers ( PRT-00116)<br> -- right angle break away headers (PRT-00553)<br> -- swiss pins (PRT-00743)<br> -- machine pins (PRT-00117)<br> -- female headers (PRT-00115)<br><br> - - Molex polarized connector foot print use with: PRT-08233 with associated crimp pins and housings.<br><br> - -2.54_SCREWTERM for use with PRT-10571.<br><br> - -3.5mm Screw Terminal footprints for PRT-08084<br><br> - -5mm Screw Terminal footprints for use with PRT-08432 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Header 3</b> -Standard 3-pin 0.1" header. Use with straight break away headers (SKU : PRT-00116), right angle break away headers (PRT-00553), swiss pins (PRT-00743), machine pins (PRT-00117), and female headers (PRT-00115). Molex polarized connector foot print use with SKU : PRT-08232 with associated crimp pins and housings. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - ->NAME ->VALUE - - - - - ->Name ->Value - - - - - - - - - ->Name ->Value - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - ->NAME ->VALUE - - - - - -<b>CAPACITOR</b><p> -chip - - - - - - - - - ->NAME ->VALUE - - - - - - - - ->Name ->Value - - - - - - - - - - - - ->Name ->Value - - - - - - - - - - ->NAME ->VALUE - - -CTZ3 Series land pattern for variable capacitor - CTZ3E-50C-W1-PF - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -<h3>CAP-PTH-SMALL-KIT</h3> -Commonly used for small ceramic capacitors. Like our 0.1uF (http://www.sparkfun.com/products/8375) or 22pF caps (http://www.sparkfun.com/products/8571).<br> -<br> -<b>Warning:</b> This is the KIT version of this package. This package has a smaller diameter top stop mask, which doesn't cover the diameter of the pad. This means only the bottom side of the pads' copper will be exposed. You'll only be able to solder to the bottom side. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -This is the "EZ" version of the .1" spaced ceramic thru-hole cap.<br> -It has reduced top mask to make it harder to put the component on the wrong side of the board. - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - ->Value ->Name - - - - - - ->Name ->Value - - - - - - - - - - - - ->Name ->Value - - -<b>Panasonic Aluminium Electrolytic Capacitor VS-Serie Package G</b> - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - -<b>Panasonic Aluminium Electrolytic Capacitor VS-Serie Package E</b> - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - -<b>Panasonic Aluminium Electrolytic Capacitor VS-Serie Package E</b> - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - ->Value ->Name - - - - - - ->Value ->Name - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - -Type J2 package for SMD supercap PRT-10317 (p# EEC-EN0F204J2) - - - - - - - - - - - - - - - ->NAME ->VALUE - - -<h3>EIA3528-KIT</h3> -<b>Warning:</b> This is the KIT version of this package. This package has longer pads to make hand soldering easier.<br> - - - - - - - - - - - ->NAME ->VALUE - - -<h3>EIA3216-KIT</h3> -<b>Warning:</b> This is the KIT version of this package. This package has longer pads to make hand soldering easier.<br> - - - - - - - - - - - ->NAME ->VALUE - - - - ->NAME ->VALUE - - -Small solder jumper with no paste layer so it will open after reflow. - - - - - - - - ->NAME ->VALUE - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - -Solder jumper, small, shorted with trace. No paste layer. Trace is cuttable. - - - - - - - - - ->NAME ->VALUE - - - - - ->NAME ->VALUE - - - - - - - - - - - - ->Name ->Value - - -<b>RESISTOR</b><p> -chip - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -<b>CAPACITOR</b><p> -chip - - - - - - - - ->NAME ->VALUE - - - - - - -1/6W Thru-hole Resistor - *UNPROVEN* - - - - - - ->NAME ->VALUE - - - - - - ->NAME ->VALUE - - - - -1/4W Resistor, 0.4" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -1/2W Resistor, 0.5" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -1W Resistor, 0.6" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -2W Resistor, 0.8" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -<h3>AXIAL-0.3-KIT</h3> - -Commonly used for 1/4W through-hole resistors. 0.3" pitch between holes.<br> -<br> - -<b>Warning:</b> This is the KIT version of the AXIAL-0.3 package. This package has a smaller diameter top stop mask, which doesn't cover the diameter of the pad. This means only the bottom side of the pads' copper will be exposed. You'll only be able to solder to the bottom side. - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - - - - - - - - - - - -This is the "EZ" version of the standard .3" spaced resistor package.<br> -It has a reduced top mask to make it harder to install upside-down. - - - - - - - - - - ->Name ->Value - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -<b>Capacitor</b> -Standard 0603 ceramic capacitor, and 0.1" leaded capacitor. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Capacitor Polarized</b> -These are standard SMD and PTH capacitors. Normally 10uF, 47uF, and 100uF in electrolytic and tantalum varieties. Always verify the external diameter of the through hole cap, it varies with capacity, voltage, and manufacturer. The EIA devices should be standard. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Resistor</b> -Basic schematic elements and footprints for 0603, 1206, and PTH resistors. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find all manner of retired footprints for resistors, capacitors, board names, ICs, etc., that are no longer used in our catalog.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b>Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - -Small solder jumper with big paste layer so it will short during reflow. - - - - - - - - - - ->NAME ->VALUE - - - -Small solder jumper with no paste layer so it will open after reflow. - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - ->NAME ->VALUE - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -<b>Jumper</b> -Basic 0.1" spaced jumper. Use with breakaway headers. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find discrete semiconductors- transistors, diodes, TRIACs, optoisolators, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - - - - ->NAME ->VALUE - - -<b>TO 220 Vertical</b> Package works with various parts including N-Channel MOSFET SparkFun SKU: COM-10213 - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -D -S -G - - - - - - - - - - -Generic PMOSFET - -<ul> -<li> -IRLML2244 - TRANS-11153 -(SOT-23 -20V -4.3A) -(1.Gate 2.Source 3.Drain) -</li> -<li> -FQP27P06 - -<a href="http://www.sparkfun.com/products/10349">COM-10349</a> -(TO-220 -60V -27A) -(1.Gate 2.Source 3.Drain) -</li> -</ul> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - -<b>Chip Resistor Array</b> size 4 × 0603<p> -convex termination - Phycomp Components<br> -Source: RS Components - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -<b>Array Chip Resistor</b><p> -Source: RS Component / Phycomp - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Frames for Sheet and Layout</b> - - - - - - - - - - - - - - - - - - - - - - - ->DRAWING_NAME ->LAST_DATE_TIME ->SHEET -Sheet: - - - - - -<b>FRAME</b><p> -DIN A3, landscape with location and doc. field - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find non-functional items- supply symbols, logos, notations, frame blocks, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> Creative Commons ShareAlike 4.0 International - https://creativecommons.org/licenses/by-sa/4.0/ -<br><br> -You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - ->VALUE - - - - - -<b>SUPPLY SYMBOL</b> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -I2C ADDRESSES - - - - -PI ZERO -I2C PWM - - -POWER -OUTPUTS - -PI POWER JUMPER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hardware/Mk2/ESCapemk2.zip b/hardware/Mk2/ESCapemk2.zip deleted file mode 100644 index 742693e9ffa6215dfc7d314a1c05de2b883634ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 92938 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�F)FYi0~%TTqs0Rt?qUvKCRa2&W!@;c{c_y~v-w0RXAD5~fb(_O_g??_J)b|G!~401;q< zAe1S(auN=sDflV9gi@iS8Iy4T^4Qqr3HgtF48p&>*W>7)y!D@aGc4qZMes^_V*krO zdGyEXAN($77MTEms+)g#iN^*0e_rN|;-CD{trzwGs*mwQJNsYN|K-2@j9y#|I{^St z8}TnM!}d3?@+WUvJM_e3FS0%H|K-2D&zOdM*kc=-QUB!&B>(2${>g(e=b!kabG0Y_ zzx ze*FABb6|#l@k)R7zRG3&iGNVyAO{eSr{j~Bc;JNCG0D^dRC zO@{yGRsUSI^A^^lx#WQs3@^|*|~cC`3rbbH!Y6T b8O=XaRRQU-UH|~|@$H2O0Qgxvb_ei(s_WLb diff --git a/hardware/readme.md b/hardware/readme.md deleted file mode 100644 index dd8b666..0000000 --- a/hardware/readme.md +++ /dev/null @@ -1 +0,0 @@ -Placeholder for the Escape board hardware files diff --git a/license.txt b/license.txt deleted file mode 100644 index 34ec65f..0000000 --- a/license.txt +++ /dev/null @@ -1,425 +0,0 @@ -Attribution-ShareAlike 4.0 International - -======================================================================= - -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. - -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More_considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution-ShareAlike 4.0 International Public -License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-ShareAlike 4.0 International Public License ("Public -License"). To the extent this Public License may be interpreted as a -contract, You are granted the Licensed Rights in consideration of Your -acceptance of these terms and conditions, and the Licensor grants You -such rights in consideration of benefits the Licensor receives from -making the Licensed Material available under these terms and -conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - l. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - m. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - - including for purposes of Section 3(b); and - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public licenses. -Notwithstanding, Creative Commons may elect to apply one of its public -licenses to material it publishes and in those instances will be -considered the "Licensor." Except for the limited purpose of indicating -that material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the public -licenses. - -Creative Commons may be contacted at creativecommons.org.