Big update
Needs testing
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
# escape
|
||||
Library for the escape board
|
||||
@@ -1,2 +0,0 @@
|
||||
# escape
|
||||
Library for the escape board
|
||||
@@ -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 );
|
||||
11
README.md
11
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
|
||||
|
||||
426
darkwater_escape/GPIO.py
Normal file
426
darkwater_escape/GPIO.py
Normal file
@@ -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.')
|
||||
200
darkwater_escape/I2C.py
Normal file
200
darkwater_escape/I2C.py
Normal file
@@ -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)
|
||||
167
darkwater_escape/PCA9685.py
Normal file
167
darkwater_escape/PCA9685.py
Normal file
@@ -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)
|
||||
106
darkwater_escape/Platform.py
Normal file
106
darkwater_escape/Platform.py
Normal file
@@ -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
|
||||
336
darkwater_escape/SPI.py
Normal file
336
darkwater_escape/SPI.py
Normal file
@@ -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
|
||||
249
darkwater_escape/darkwater_escape.py
Normal file
249
darkwater_escape/darkwater_escape.py
Normal file
@@ -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)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -1 +0,0 @@
|
||||
Placeholder for the Escape board hardware files
|
||||
425
license.txt
425
license.txt
@@ -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.
|
||||
Reference in New Issue
Block a user