diff --git a/.gitignore b/.gitignore index bc9ceee..91e17ea 100644 --- a/.gitignore +++ b/.gitignore @@ -221,3 +221,4 @@ pybcdc.inf _SYNCAPP/ _SYNCAPP/metadata.xml +_SYNCAPP/metadata.xml diff --git a/Lib/L298N.py b/Lib/L298N.py new file mode 100644 index 0000000..d5e996a --- /dev/null +++ b/Lib/L298N.py @@ -0,0 +1,44 @@ +#Driver for the L298N Dual HBridge motor controller. + +from PWM import PWM +from pyb import Pin + +#motordata +#Forward pin +#Back pin +#Speed pin (PWM) + +class Motor( ): + """docstring for Motor""" + + def __init__(self, forward, backward, speed): + """Speed = (pin name, timer#)""" + self._forward = Pin(forward, Pin.OUT_PP) + self._backward = Pin(backward, Pin.OUT_PP) + self._speedControl = PWM(speed[0], speed[1]) + self._speed = 0 + + @property + def speed(self): return self._speed + + @speed.setter + def speed(self, value): + self._speed = value + if (value == 0): + self._forward.low() + self._backward.low() + elif (value < 0): + self._forward.low() + self._backward.high() + else: + self._forward.high() + self._backward.low() + + self._speedControl.pulse_width_percent = abs(value) + + def brake( self ) : + """ """ + self._forward.high() + self._backward.high() + self._speedControl.pulse_width_percent(1.0) + diff --git a/Lib/PIR.py b/Lib/PIR.py index 9dd11c5..df00209 100644 --- a/Lib/PIR.py +++ b/Lib/PIR.py @@ -1,4 +1,4 @@ -#Passive infrared motion sensor. +#Passive infrared motipower sensor. import pyb @@ -10,28 +10,35 @@ class PIR(object): """Power and trigger pins, optional interrupt callback in the format of fun( bOnOff ). This will be called whenever the trigger state changes.""" - self._power = pyb.Pin(power, pyb.Pin.OUT_PP) - self._power.low() + if power != None: + self._power = pyb.Pin(power, pyb.Pin.OUT_PP) + self._power.low() + else: + self._power = None self._trigger = pyb.Pin(trigger, pyb.Pin.IN, pyb.Pin.PULL_DOWN) self.interrupt = callback - def _on( self, aTF ) : + def _onoff( self, aTF ) : """Turn device on/off""" - if (aTF): - oldon = self.inton - self.inton = False #Make sure interrupt is off while turning on power to avoid false callbacks. - self._power.high() - if (oldon): - pyb.delay(200) #Need to wait a bit after turning on to make sure we don't get false values. - self.inton = oldon - else: - self._power.low() + if (self._power != None): + if (aTF): + oldon = self.inton + self.inton = False #Make sure interrupt is off while turning on power to avoid false callbacks. + self._power.high() + if (oldon): + pyb.delay(200) #Need to wait a bit after turning on to make sure we don't get false values. + self.inton = oldon + else: + self._power.low() @property - def on(self): return self._power.value() + def power(self): return True if (self._power == None) else self._power.value() - @on.setter - def on(self, value): self._on(value) + @power.setter + def power(self, value): self._onoff(value) + + def on( self ) : self.power = True + def off( self ) : self.power = False @property def trigger(self): return self._trigger.value() @@ -43,13 +50,12 @@ class PIR(object): def interrupt(self, func): self._interrupt = None; self._func = func - if (aFunc != None): + if (func != None): self._interrupt = pyb.ExtInt(self._trigger, pyb.ExtInt.IRQ_RISING_FALLING, pyb.Pin.PULL_DOWN, self._inthandler) self._inton = True - def _inthandler(self, aLine): + def _inthandler(self, line): '''Function to handle interrupts and pass on to callback with on/off trigger state.''' - call if (self._func != None): self._func(self.trigger) @@ -64,4 +70,3 @@ class PIR(object): self._interrupt.enable() else: self._interrupt.disable() - diff --git a/Lib/PWM.py b/Lib/PWM.py new file mode 100644 index 0000000..c008108 --- /dev/null +++ b/Lib/PWM.py @@ -0,0 +1,81 @@ +# PWM driver. + +from pyb import Timer, Pin + +class PWM(object): + """docstring for PWMM""" + + #Dict pin name: timer #, channel #. + PinChannels = { + 'X1': [(2,1), (5,1)], + 'X2': [(2,2), (5,2)], + 'X3': [(2,3), (5,3), (9,1)], + 'X4': [(2,4), (5,4), (9,2)], + 'X6': [(2,1), (8,1)], + 'X7': [(13, 1)], + 'X8': [(1,1), (8,1), (14,1)], + 'X9': [(4,1)], + 'X10': [(4,2)], + 'Y1': [(8,1)], + 'Y2': [(8,2)], + 'Y3': [(4,3), (10,1)], + 'Y4': [(4,4), (11,1)], + 'Y6': [(1,1)], + 'Y7': [(1,2), (8,2), (12,1)], + 'Y8': [(1,3), (8,3), (12,2)], + 'Y9': [(2,3)], + 'Y10': [(2,4)], + 'Y11': [(1,2), (8,2)], + 'Y12': [(1,3), (8,3)] + } + + class PWMException(Exception): + def __init__(self, msg): + self.msg = msg + + @staticmethod + def timerandchannel( pinname, timernum ): + try: + a = PWM.PinChannels[pinname] + if timernum <= 0: + return a[0] + else: + for v in a: + if v[0] == timernum: + return v + except Exception as e : + raise PWM.PWMException("Pin {} cannot be used for PWM".format(pinname)) + + raise PWM.PWMException("Pin {} cannot use timer {}".format(pinname, timernum)) + + def __init__( self, p, timernum, afreq = 100 ): + isname = type(p) == str + pinname = p if isname else p.name() + timernum, channel = PWM.timerandchannel(pinname, timernum) + if isname: + p = Pin(pinname) + + self._timer = Timer(timernum, freq = afreq) + self._channel = self._timer.channel(channel, Timer.PWM, pin = p) + + @property + def pulse_width(self): return self._channel.pulse_width() + + @pulse_width.setter + def pulse_width(self, value): self._channel.pulse_width(value) + + @property + def pulse_width_percent(self): return self._channel.pulse_width_percent() + + @pulse_width_percent.setter + def pulse_width_percent(self, value): self._channel.pulse_width_percent(value) + + @property + def freq(self): return self._timer.freq() + + @freq.setter + def freq(self, value): self._timer.freq(value) + + def callback(self, value): + self._channel.callback(value) + diff --git a/Lib/ST7735/__init__.py b/Lib/ST7735.py similarity index 78% rename from Lib/ST7735/__init__.py rename to Lib/ST7735.py index c6f535b..377c59c 100644 --- a/Lib/ST7735/__init__.py +++ b/Lib/ST7735.py @@ -4,51 +4,6 @@ import pyb from math import sqrt -ST_NOP = 0x0 -ST_SWRESET = 0x01 -ST_RDDID = 0x04 -ST_RDDST = 0x09 - -ST_SLPIN = 0x10 -ST_SLPOUT = 0x11 -ST_PTLON = 0x12 -ST_NORON = 0x13 - -ST_INVOFF = 0x20 -ST_INVON = 0x21 -ST_DISPOFF = 0x28 -ST_DISPON = 0x29 -ST_CASET = 0x2A -ST_RASET = 0x2B -ST_RAMWR = 0x2C -ST_RAMRD = 0x2E - -ST_COLMOD = 0x3A -ST_MADCTL = 0x36 - -ST_FRMCTR1 = 0xB1 -ST_FRMCTR2 = 0xB2 -ST_FRMCTR3 = 0xB3 -ST_INVCTR = 0xB4 -ST_DISSET5 = 0xB6 - -ST_PWCTR1 = 0xC0 -ST_PWCTR2 = 0xC1 -ST_PWCTR3 = 0xC2 -ST_PWCTR4 = 0xC3 -ST_PWCTR5 = 0xC4 -ST_VMCTR1 = 0xC5 - -ST_RDID1 = 0xDA -ST_RDID2 = 0xDB -ST_RDID3 = 0xDC -ST_RDID4 = 0xDD - -ST_PWCTR6 = 0xFC - -ST_GMCTRP1 = 0xE0 -ST_GMCTRN1 = 0xE1 - #TFTRotations and TFTRGB are bits to set # on MADCTL to control display rotation/color layout #Looking at display with pins on top. @@ -66,9 +21,11 @@ TFTRotations = [0x00, 0x60, 0xC0, 0xA0] TFTBGR = 0x08 #When set color is bgr else rgb. TFTRGB = 0x00 +@micropython.native def clamp( aValue, aMin, aMax ) : return max(aMin, min(aMax, aValue)) +@micropython.native def TFTColor( aR, aG, aB ) : '''Create a 16 bit rgb value from the given R,G,B from 0-255. This assumes rgb 565 layout and will be incorrect for bgr.''' @@ -79,6 +36,51 @@ ScreenSize = (128, 160) class TFT(object) : """Sainsmart TFT 7735 display driver.""" + NOP = 0x0 + SWRESET = 0x01 + RDDID = 0x04 + RDDST = 0x09 + + SLPIN = 0x10 + SLPOUT = 0x11 + PTLON = 0x12 + NORON = 0x13 + + INVOFF = 0x20 + INVON = 0x21 + DISPOFF = 0x28 + DISPON = 0x29 + CASET = 0x2A + RASET = 0x2B + RAMWR = 0x2C + RAMRD = 0x2E + + COLMOD = 0x3A + MADCTL = 0x36 + + FRMCTR1 = 0xB1 + FRMCTR2 = 0xB2 + FRMCTR3 = 0xB3 + INVCTR = 0xB4 + DISSET5 = 0xB6 + + PWCTR1 = 0xC0 + PWCTR2 = 0xC1 + PWCTR3 = 0xC2 + PWCTR4 = 0xC3 + PWCTR5 = 0xC4 + VMCTR1 = 0xC5 + + RDID1 = 0xDA + RDID2 = 0xDB + RDID3 = 0xDC + RDID4 = 0xDD + + PWCTR6 = 0xFC + + GMCTRP1 = 0xE0 + GMCTRN1 = 0xE1 + BLACK = 0 RED = TFTColor(0xFF, 0x00, 0x00) MAROON = TFTColor(0x80, 0x00, 0x00) @@ -116,19 +118,23 @@ class TFT(object) : def size( self ): return self._size +# @micropython.native def on( self, aTF = True ) : '''Turn display on or off.''' - self._writecommand(ST_DISPON if aTF else ST_DISPOFF) + self._writecommand(TFT.DISPON if aTF else TFT.DISPOFF) +# @micropython.native def invertcolor( self, aBool ) : '''Invert the color data IE: Black = White.''' - self._writecommand(ST_INVON if aBool else ST_INVOFF) + self._writecommand(TFT.INVON if aBool else TFT.INVOFF) +# @micropython.native def rgb( self, aTF = True ) : '''True = rgb else bgr''' self._rgb = aTF self._setMADCTL() +# @micropython.native def rotation( self, aRot ) : '''0 - 3. Starts vertical with top toward pins and rotates 90 deg clockwise each step.''' @@ -141,12 +147,14 @@ class TFT(object) : self._size =(self._size[1], self._size[0]) self._setMADCTL() + @micropython.native def pixel( self, aPos, aColor ) : '''Draw a pixel at the given position''' if 0 <= aPos[0] < self._size[0] and 0 <= aPos[1] < self._size[1]: self._setwindowpoint(aPos) self._pushcolor(aColor) +# @micropython.native def text( self, aPos, aString, aColor, aFont, aSize = 1 ) : '''Draw a text at the given position. If the string reaches the end of the display it is wrapped to aPos[0] on the next line. aSize may be an integer @@ -173,6 +181,7 @@ class TFT(object) : py += aFont["Height"] * wh[1] + 1 px = aPos[0] +# @micropython.native def char( self, aPos, aChar, aColor, aFont, aSizes ) : '''Draw a character at the given position using the given font and color. aSizes is a tuple with x, y as integer scales indicating the @@ -211,6 +220,7 @@ class TFT(object) : c >>= 1 px += aSizes[0] +# @micropython.native def line( self, aStart, aEnd, aColor ) : '''Draws a line from aStart to aEnd in the given color. Vertical or horizontal lines are forwarded to vline and hline.''' @@ -255,6 +265,7 @@ class TFT(object) : e += dx py += iny +# @micropython.native def vline( self, aStart, aLen, aColor ) : '''Draw a vertical line from aStart for aLen. aLen may be negative.''' start = (clamp(aStart[0], 0, self._size[0]), clamp(aStart[1], 0, self._size[1])) @@ -265,6 +276,7 @@ class TFT(object) : self._setwindowloc(start, stop) self._draw(aLen, aColor) +# @micropython.native def hline( self, aStart, aLen, aColor ) : '''Draw a horizontal line from aStart for aLen. aLen may be negative.''' start = (clamp(aStart[0], 0, self._size[0]), clamp(aStart[1], 0, self._size[1])) @@ -275,6 +287,7 @@ class TFT(object) : self._setwindowloc(start, stop) self._draw(aLen, aColor) +# @micropython.native def rect( self, aStart, aSize, aColor ) : '''Draw a hollow rectangle. aStart is the smallest coordinate corner and aSize is a tuple indicating width, height.''' @@ -283,6 +296,7 @@ class TFT(object) : self.vline(aStart, aSize[1], aColor) self.vline((aStart[0] + aSize[0] - 1, aStart[1]), aSize[1], aColor) +# @micropython.native def fillrect( self, aStart, aSize, aColor ) : '''Draw a filled rectangle. aStart is the smallest coordinate corner and aSize is a tuple indicating width, height.''' @@ -302,6 +316,7 @@ class TFT(object) : numPixels = (end[0] - start[0] + 1) * (end[1] - start[1] + 1) self._draw(numPixels, aColor) +# @micropython.native def circle( self, aPos, aRadius, aColor ) : '''Draw a hollow circle with the given radius and color with aPos as center.''' self.colorData[0] = aColor >> 8 @@ -336,6 +351,7 @@ class TFT(object) : self._setwindowpoint((xyn, yxn)) self._writedata(self.colorData) +# @micropython.native def fillcircle( self, aPos, aRadius, aColor ) : '''Draw a filled circle with given radius and color with aPos as center''' rsq = aRadius * aRadius @@ -353,6 +369,7 @@ class TFT(object) : '''Fill screen with the given color.''' self.fillrect((0, 0), self._size, aColor) +# @micropython.native def _draw( self, aPixels, aColor ) : '''Send given color to the device aPixels times.''' self.colorData[0] = aColor >> 8 @@ -364,39 +381,42 @@ class TFT(object) : self.spi.send(self.colorData) self.cs.high() +# @micropython.native def _setwindowpoint( self, aPos ) : '''Set a single point for drawing a color to.''' x = int(aPos[0]) y = int(aPos[1]) - self._writecommand(ST_CASET) #Column address set. + self._writecommand(TFT.CASET) #Column address set. self.windowLocData[0] = 0x00 self.windowLocData[1] = x self.windowLocData[2] = 0x00 self.windowLocData[3] = x self._writedata(self.windowLocData) - self._writecommand(ST_RASET) #Row address set. + self._writecommand(TFT.RASET) #Row address set. self.windowLocData[1] = y self.windowLocData[3] = y self._writedata(self.windowLocData) - self._writecommand(ST_RAMWR) #Write to RAM. + self._writecommand(TFT.RAMWR) #Write to RAM. +# @micropython.native def _setwindowloc( self, aPos0, aPos1 ) : '''Set a rectangular area for drawing a color to.''' - self._writecommand(ST_CASET) #Column address set. + self._writecommand(TFT.CASET) #Column address set. self.windowLocData[0] = 0x00 self.windowLocData[1] = int(aPos0[0]) self.windowLocData[2] = 0x00 self.windowLocData[3] = int(aPos1[0]) self._writedata(self.windowLocData) - self._writecommand(ST_RASET) #Row address set. + self._writecommand(TFT.RASET) #Row address set. self.windowLocData[1] = int(aPos0[1]) self.windowLocData[3] = int(aPos1[1]) self._writedata(self.windowLocData) - self._writecommand(ST_RAMWR) #Write to RAM. + self._writecommand(TFT.RAMWR) #Write to RAM. + @micropython.native def _writecommand( self, aCommand ) : '''Write given command to the device.''' self.dc.low() @@ -404,6 +424,7 @@ class TFT(object) : self.spi.send(aCommand) self.cs.high() + @micropython.native def _writedata( self, aData ) : '''Write given data to the device. This may be either a single int or a bytearray of values.''' @@ -412,18 +433,21 @@ class TFT(object) : self.spi.send(aData) self.cs.high() + @micropython.native def _pushcolor( self, aColor ) : '''Push given color to the device.''' self.colorData[0] = aColor >> 8 self.colorData[1] = aColor self._writedata(self.colorData) + @micropython.native def _setMADCTL( self ) : '''Set screen rotation and RGB/BGR format.''' - self._writecommand(ST_MADCTL) + self._writecommand(TFT.MADCTL) rgb = TFTRGB if self._rgb else TFTBGR self._writedata(TFTRotations[self.rotate] | rgb) + @micropython.native def _reset(self): '''Reset the device.''' self.dc.low() @@ -438,58 +462,58 @@ class TFT(object) : '''Initialize blue tab version.''' self._size = (ScreenSize[0] + 2, ScreenSize[1] + 1) self._reset() - self._writecommand(ST_SWRESET) #Software reset. + self._writecommand(TFT.SWRESET) #Software reset. pyb.delay(50) - self._writecommand(ST_SLPOUT) #out of sleep mode. + self._writecommand(TFT.SLPOUT) #out of sleep mode. pyb.delay(500) data1 = bytearray(1) - self._writecommand(ST_COLMOD) #Set color mode. + self._writecommand(TFT.COLMOD) #Set color mode. data1[0] = 0x05 #16 bit color. self._writedata(data1) pyb.delay(10) data3 = bytearray([0x00, 0x06, 0x03]) #fastest refresh, 6 lines front, 3 lines back. - self._writecommand(ST_FRMCTR1) #Frame rate control. + self._writecommand(TFT.FRMCTR1) #Frame rate control. self._writedata(data3) pyb.delay(10) - self._writecommand(ST_MADCTL) + self._writecommand(TFT.MADCTL) data1[0] = 0x08 #row address/col address, bottom to top refresh self._writedata(data1) data2 = bytearray(2) - self._writecommand(ST_DISSET5) #Display settings + self._writecommand(TFT.DISSET5) #Display settings data2[0] = 0x15 #1 clock cycle nonoverlap, 2 cycle gate rise, 3 cycle oscil, equalize data2[1] = 0x02 #fix on VTL self._writedata(data2) - self._writecommand(ST_INVCTR) #Display inversion control + self._writecommand(TFT.INVCTR) #Display inversion control data1[0] = 0x00 #Line inversion. self._writedata(data1) - self._writecommand(ST_PWCTR1) #Power control + self._writecommand(TFT.PWCTR1) #Power control data2[0] = 0x02 #GVDD = 4.7V data2[1] = 0x70 #1.0uA self._writedata(data2) pyb.delay(10) - self._writecommand(ST_PWCTR2) #Power control + self._writecommand(TFT.PWCTR2) #Power control data1[0] = 0x05 #VGH = 14.7V, VGL = -7.35V self._writedata(data1) - self._writecommand(ST_PWCTR3) #Power control + self._writecommand(TFT.PWCTR3) #Power control data2[0] = 0x01 #Opamp current small data2[1] = 0x02 #Boost frequency self._writedata(data2) - self._writecommand(ST_VMCTR1) #Power control + self._writecommand(TFT.VMCTR1) #Power control data2[0] = 0x3C #VCOMH = 4V data2[1] = 0x38 #VCOML = -1.1V self._writedata(data2) pyb.delay(10) - self._writecommand(ST_PWCTR6) #Power control + self._writecommand(TFT.PWCTR6) #Power control data2[0] = 0x11 data2[1] = 0x15 self._writedata(data2) @@ -499,36 +523,36 @@ class TFT(object) : # 0x1b, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10]) dataGMCTRP = bytearray([0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29, 0x25, 0x2b, 0x39, 0x00, 0x01, 0x03, 0x10]) - self._writecommand(ST_GMCTRP1) + self._writecommand(TFT.GMCTRP1) self._writedata(dataGMCTRP) # dataGMCTRN = bytearray([0x0f, 0x1b, 0x0f, 0x17, 0x33, 0x2c, 0x29, 0x2e, 0x30, # 0x30, 0x39, 0x3f, 0x00, 0x07, 0x03, 0x10]) dataGMCTRN = bytearray([0x03, 0x1d, 0x07, 0x06, 0x2e, 0x2c, 0x29, 0x2d, 0x2e, 0x2e, 0x37, 0x3f, 0x00, 0x00, 0x02, 0x10]) - self._writecommand(ST_GMCTRN1) + self._writecommand(TFT.GMCTRN1) self._writedata(dataGMCTRN) pyb.delay(10) - self._writecommand(ST_CASET) #Column address set. + self._writecommand(TFT.CASET) #Column address set. self.windowLocData[0] = 0x00 self.windowLocData[1] = 2 #Start at column 2 self.windowLocData[2] = 0x00 self.windowLocData[3] = self._size[0] - 1 self._writedata(self.windowLocData) - self._writecommand(ST_RASET) #Row address set. + self._writecommand(TFT.RASET) #Row address set. self.windowLocData[1] = 1 #Start at row 2. self.windowLocData[3] = self._size[1] - 1 self._writedata(self.windowLocData) - self._writecommand(ST_NORON) #Normal display on. + self._writecommand(TFT.NORON) #Normal display on. pyb.delay(10) - self._writecommand(ST_RAMWR) + self._writecommand(TFT.RAMWR) pyb.delay(500) - self._writecommand(ST_DISPON) + self._writecommand(TFT.DISPON) self.cs.high() pyb.delay(500) @@ -536,182 +560,183 @@ class TFT(object) : '''Initialize a red tab version.''' self._reset() - self._writecommand(ST_SWRESET) #Software reset. + self._writecommand(TFT.SWRESET) #Software reset. pyb.delay(150) - self._writecommand(ST_SLPOUT) #out of sleep mode. + self._writecommand(TFT.SLPOUT) #out of sleep mode. pyb.delay(500) data3 = bytearray([0x01, 0x2C, 0x2D]) #fastest refresh, 6 lines front, 3 lines back. - self._writecommand(ST_FRMCTR1) #Frame rate control. + self._writecommand(TFT.FRMCTR1) #Frame rate control. self._writedata(data3) - self._writecommand(ST_FRMCTR2) #Frame rate control. + self._writecommand(TFT.FRMCTR2) #Frame rate control. self._writedata(data3) data6 = bytearray([0x01, 0x2c, 0x2d, 0x01, 0x2c, 0x2d]) - self._writecommand(ST_FRMCTR3) #Frame rate control. + self._writecommand(TFT.FRMCTR3) #Frame rate control. self._writedata(data6) pyb.delay(10) data1 = bytearray(1) - self._writecommand(ST_INVCTR) #Display inversion control + self._writecommand(TFT.INVCTR) #Display inversion control data1[0] = 0x07 #Line inversion. self._writedata(data1) - self._writecommand(ST_PWCTR1) #Power control + self._writecommand(TFT.PWCTR1) #Power control data3[0] = 0xA2 data3[1] = 0x02 data3[2] = 0x84 self._writedata(data3) - self._writecommand(ST_PWCTR2) #Power control + self._writecommand(TFT.PWCTR2) #Power control data1[0] = 0xC5 #VGH = 14.7V, VGL = -7.35V self._writedata(data1) data2 = bytearray(2) - self._writecommand(ST_PWCTR3) #Power control + self._writecommand(TFT.PWCTR3) #Power control data2[0] = 0x0A #Opamp current small data2[1] = 0x00 #Boost frequency self._writedata(data2) - self._writecommand(ST_PWCTR4) #Power control + self._writecommand(TFT.PWCTR4) #Power control data2[0] = 0x8A #Opamp current small data2[1] = 0x2A #Boost frequency self._writedata(data2) - self._writecommand(ST_PWCTR5) #Power control + self._writecommand(TFT.PWCTR5) #Power control data2[0] = 0x8A #Opamp current small data2[1] = 0xEE #Boost frequency self._writedata(data2) - self._writecommand(ST_VMCTR1) #Power control + self._writecommand(TFT.VMCTR1) #Power control data1[0] = 0x0E self._writedata(data1) - self._writecommand(ST_INVOFF) + self._writecommand(TFT.INVOFF) - self._writecommand(ST_MADCTL) #Power control + self._writecommand(TFT.MADCTL) #Power control data1[0] = 0xC8 self._writedata(data1) - self._writecommand(ST_COLMOD) + self._writecommand(TFT.COLMOD) data1[0] = 0x05 self._writedata(data1) - self._writecommand(ST_CASET) #Column address set. + self._writecommand(TFT.CASET) #Column address set. self.windowLocData[0] = 0x00 self.windowLocData[1] = 0x00 self.windowLocData[2] = 0x00 self.windowLocData[3] = self._size[0] - 1 self._writedata(self.windowLocData) - self._writecommand(ST_RASET) #Row address set. + self._writecommand(TFT.RASET) #Row address set. self.windowLocData[3] = self._size[1] - 1 self._writedata(self.windowLocData) dataGMCTRP = bytearray([0x0f, 0x1a, 0x0f, 0x18, 0x2f, 0x28, 0x20, 0x22, 0x1f, 0x1b, 0x23, 0x37, 0x00, 0x07, 0x02, 0x10]) - self._writecommand(ST_GMCTRP1) + self._writecommand(TFT.GMCTRP1) self._writedata(dataGMCTRP) dataGMCTRN = bytearray([0x0f, 0x1b, 0x0f, 0x17, 0x33, 0x2c, 0x29, 0x2e, 0x30, 0x30, 0x39, 0x3f, 0x00, 0x07, 0x03, 0x10]) - self._writecommand(ST_GMCTRN1) + self._writecommand(TFT.GMCTRN1) self._writedata(dataGMCTRN) pyb.delay(10) - self._writecommand(ST_DISPON) + self._writecommand(TFT.DISPON) pyb.delay(100) - self._writecommand(ST_NORON) #Normal display on. + self._writecommand(TFT.NORON) #Normal display on. pyb.delay(10) self.cs.high() + @micropython.native def initg(self): '''Initialize a green tab version.''' self._reset() - self._writecommand(ST_SWRESET) #Software reset. + self._writecommand(TFT.SWRESET) #Software reset. pyb.delay(150) - self._writecommand(ST_SLPOUT) #out of sleep mode. + self._writecommand(TFT.SLPOUT) #out of sleep mode. pyb.delay(255) data3 = bytearray([0x01, 0x2C, 0x2D]) #fastest refresh, 6 lines front, 3 lines back. - self._writecommand(ST_FRMCTR1) #Frame rate control. + self._writecommand(TFT.FRMCTR1) #Frame rate control. self._writedata(data3) - self._writecommand(ST_FRMCTR2) #Frame rate control. + self._writecommand(TFT.FRMCTR2) #Frame rate control. self._writedata(data3) data6 = bytearray([0x01, 0x2c, 0x2d, 0x01, 0x2c, 0x2d]) - self._writecommand(ST_FRMCTR3) #Frame rate control. + self._writecommand(TFT.FRMCTR3) #Frame rate control. self._writedata(data6) pyb.delay(10) - self._writecommand(ST_INVCTR) #Display inversion control + self._writecommand(TFT.INVCTR) #Display inversion control self._writedata(0x07) - self._writecommand(ST_PWCTR1) #Power control + self._writecommand(TFT.PWCTR1) #Power control data3[0] = 0xA2 data3[1] = 0x02 data3[2] = 0x84 self._writedata(data3) - self._writecommand(ST_PWCTR2) #Power control + self._writecommand(TFT.PWCTR2) #Power control self._writedata(0xC5) data2 = bytearray(2) - self._writecommand(ST_PWCTR3) #Power control + self._writecommand(TFT.PWCTR3) #Power control data2[0] = 0x0A #Opamp current small data2[1] = 0x00 #Boost frequency self._writedata(data2) - self._writecommand(ST_PWCTR4) #Power control + self._writecommand(TFT.PWCTR4) #Power control data2[0] = 0x8A #Opamp current small data2[1] = 0x2A #Boost frequency self._writedata(data2) - self._writecommand(ST_PWCTR5) #Power control + self._writecommand(TFT.PWCTR5) #Power control data2[0] = 0x8A #Opamp current small data2[1] = 0xEE #Boost frequency self._writedata(data2) - self._writecommand(ST_VMCTR1) #Power control + self._writecommand(TFT.VMCTR1) #Power control self._writedata(0x0E) - self._writecommand(ST_INVOFF) + self._writecommand(TFT.INVOFF) self._setMADCTL() - self._writecommand(ST_COLMOD) + self._writecommand(TFT.COLMOD) self._writedata(0x05) - self._writecommand(ST_CASET) #Column address set. + self._writecommand(TFT.CASET) #Column address set. self.windowLocData[0] = 0x00 self.windowLocData[1] = 0x01 #Start at row/column 1. self.windowLocData[2] = 0x00 self.windowLocData[3] = self._size[0] - 1 self._writedata(self.windowLocData) - self._writecommand(ST_RASET) #Row address set. + self._writecommand(TFT.RASET) #Row address set. self.windowLocData[3] = self._size[1] - 1 self._writedata(self.windowLocData) dataGMCTRP = bytearray([0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29, 0x25, 0x2b, 0x39, 0x00, 0x01, 0x03, 0x10]) - self._writecommand(ST_GMCTRP1) + self._writecommand(TFT.GMCTRP1) self._writedata(dataGMCTRP) dataGMCTRN = bytearray([0x03, 0x1d, 0x07, 0x06, 0x2e, 0x2c, 0x29, 0x2d, 0x2e, 0x2e, 0x37, 0x3f, 0x00, 0x00, 0x02, 0x10]) - self._writecommand(ST_GMCTRN1) + self._writecommand(TFT.GMCTRN1) self._writedata(dataGMCTRN) - self._writecommand(ST_NORON) #Normal display on. + self._writecommand(TFT.NORON) #Normal display on. pyb.delay(10) - self._writecommand(ST_DISPON) + self._writecommand(TFT.DISPON) pyb.delay(100) self.cs.high() diff --git a/TreatThrower.py b/TreatThrower.py index 5f632d9..f517811 100644 --- a/TreatThrower.py +++ b/TreatThrower.py @@ -1,41 +1,48 @@ # Control bot that throws treats using a servo import pyb +import motion -servoNum = 1 -servoCenter = 1440 -servoSpeed = 100 -servoTime = 1450 -ledNum = 3 -triggerInput = 'X3' +class TreatThrower(object): + """Watch for trigger and throw treat using servo + when trigger is activated.""" -def runservo( aServo, aSpeed, aDelay ): - aServo.speed(aSpeed) - pyb.delay(aDelay) - aServo.speed(0) + servoCenter = 1440 + servoSpeed = 100 + servoTime = 1450 + ledNum = 3 -def main( ) : - s1 = pyb.Servo(servoNum) - btn = pyb.Pin(triggerInput, pyb.Pin.IN, pyb.Pin.PULL_UP) - mn, mx, _, a, s = s1.calibration() - s1.calibration(mn, mx, servoCenter, a, s) - s1.speed(0) - l = pyb.LED(ledNum) + def __init__(self, sensor, servonum = 3): + self._sensor = sensor + self._servo = pyb.Servo(servonum) + mn, mx, _, a, s = self._servo.calibration() + self._servo.calibration(mn, mx, TreatThrower.servoCenter, a, s) + self._servo.speed(0) + self._led = pyb.LED(TreatThrower.ledNum) - def throwit( ): - l.on() - runservo(s1, servoSpeed, servoTime) - l.off() + def runservo( self, time ) : + '''Run the servo for the given time.''' + self._servo.speed(TreatThrower.servoSpeed) + pyb.delay(time) + self._servo.speed(0) - sw = pyb.Switch() -# sw.callback(throwit) + def throwit( self ): + self._led.on() + self.runservo(TreatThrower.servoTime) + self._led.off() + while(self._sensor.trigger): + pass - while(1): - if (btn.value() == 0): - throwit() - if sw(): - break; - pyb.delay(20) + def adjust( self, time = 50 ) : + '''Adjust the servo position by running the servo + for the given amount of time.''' + for i in range(step) : + self.runservo(50) + + def run( self ) : + sw = pyb.Switch() + while(not sw()): + if self._sensor.trigger: + self.throwit() + pyb.delay(20) -if __name__ == '__main__': - main() diff --git a/_SYNCAPP/metadata.xml b/_SYNCAPP/metadata.xml index cd6995a..19bb3c1 100644 Binary files a/_SYNCAPP/metadata.xml and b/_SYNCAPP/metadata.xml differ diff --git a/main.py b/main.py index efca0e5..cfa72f7 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,5 @@ # main.py -- put your code here! -# import TreatThrower # import Balance # Balance.main() @@ -16,13 +15,13 @@ if pyt : from ST7735 import makeg t = makeg() else: - t = pyb.TFT("x", "X1", "X2") #makegp() + t = pyb.TFT("x", "X1", "X2") t.initg() t.fill(0) -import TFT -TFT.run(t) +# import TFT +# TFT.run(t) def tst( aColor ): s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-=_+[]{}l;'<>?,./!@#$%^&*():" @@ -41,9 +40,20 @@ def s(aRot, aColor): # b = bomber(t) # b.run() -from level import Level -l = Level(t) -l.run() +# from level import Level +# l = Level(t) +# l.run() # sd = SonarDisplay(t, "X3", "X4") # sd.run() + +# import motion +# m = motion.motion(t) +# # m.run() + +# import TreatThrower +# tt = TreatThrower.TreatThrower(m) +# tt.run() + +from L298N import Motor +m = Motor('Y2', 'Y1', ('Y3', 10)) diff --git a/motion.py b/motion.py new file mode 100644 index 0000000..b2fa767 --- /dev/null +++ b/motion.py @@ -0,0 +1,65 @@ + +import pyb +import PIR +from terminalfont import terminalfont + +class motion(PIR.PIR): + NONE = 0 + UP = 1 + DOWN = 2 + txtsize = 2 + displaytime = 4000 + processdelay = 100 + + """detect motion and print msg on TFT""" + def __init__(self, display): + super(motion, self).__init__(None, "X12", self.msg) + self._extpower = pyb.Pin("X11", pyb.Pin.OUT_PP) + self._extpower.high() + self._display = display + display.rotation(1) + self._state = motion.NONE + self._timer = 0 + self._dirty = False + self._font = terminalfont + self._fontW = terminalfont['Width'] + self._fontH = terminalfont['Height'] + + def msg( self, aArg ) : + self._state = motion.UP if aArg else motion.DOWN + + def txt( self, aText, aColor ) : + x, y = self._display.size() + y >>= 1 + y -= (self._fontH >> 1) * motion.txtsize + self._display.fillrect((0, y), (self._display.size()[0], self._fontH * motion.txtsize), self._display.BLACK) + self._dirty = (aText != None) + if self._dirty: + self._timer = 0 + x >>= 1 + x -= len(aText) * (self._fontW >> 1) * motion.txtsize + print(aText) + self._display.text((x, y), aText, aColor, terminalfont, motion.txtsize) + + def processmsg( self, dt ) : + state = self._state + if state != motion.NONE: + self._state = motion.NONE + if state == motion.UP: + self.txt("Hello", self._display.GREEN) + else: + self.txt("Goodbye", self._display.RED) + elif self._dirty: + self._timer += dt + if self._timer >= motion.displaytime: + self._timer = 0 + self.txt(None, 0) + + def run( self ) : + self._display.fill(0) + self.on() + sw = pyb.Switch() + while sw() == False : + self.processmsg(motion.processdelay) + pyb.delay(motion.processdelay) + self.off() \ No newline at end of file diff --git a/tft.py b/tft.py new file mode 100644 index 0000000..eede03f --- /dev/null +++ b/tft.py @@ -0,0 +1,234 @@ +#testing code for pyb.TFT + +import pyb +from sysfont import sysfont +from seriffont import seriffont +from terminalfont import terminalfont + +def randcolor( ) : + r = pyb.rng() & 0xFF + g = pyb.rng() & 0xFF + b = pyb.rng() & 0xFF + return pyb.TFT.color(r, g, b) + +def testpixel( display ) : + print('testing pixels') + displaysize = display.size() + r = 255 + x = -10 + g = 0 + b = 0 + for y in range(-10, displaysize[1] + 10) : + display.pixel((x, y), pyb.TFT.color(r, g, b)) + x += 1 + g += 2 + b += 1 + for i in range(100): + x = pyb.rng() % displaysize[0] + y = pyb.rng() % displaysize[1] + display.pixel((x,y), randcolor()) + pyb.delay(2000) + +def testline( display ) : + print('testing line') + displaysize = display.size() + start = (int(displaysize[0] / 2), int(displaysize[1] / 2)) + px = 0 + py = 0 + + def draw(x, y) : + display.line(start, (x, y), randcolor()) + + for x in range(displaysize[0]) : + draw(px, py) + px += 1 + + for y in range(displaysize[1]) : + draw(px, py) + py += 1 + + for x in range(displaysize[0]) : + draw(px, py) + px -= 1 + + for y in range(displaysize[1]) : + draw(px, py) + py -= 1 + pyb.delay(2000) + +def testrect( display ) : + print('testing rect') + displaysize = display.size() + size = (20, 10) + p0 = (0, 0) + p1 = (displaysize[0] - size[0], p0[1]) + p2 = (p1[0], displaysize[1] - size[1]) + p3 = (p0[0], p2[1]) + #fillrect at center, top left and bottom right + display.fillrect(p0, size, display.BLUE) + display.fillrect(p1, size, display.GRAY) + display.fillrect(p2, size, display.PURPLE) + display.fillrect(p3, size, display.NAVY) + + #now do border rect as well + display.rect(p0, size, display.CYAN) + display.rect(p1, size, display.WHITE) + display.rect(p2, size, display.YELLOW) + display.rect(p3, size, display.FOREST) + + #try negative sizes + size = (-10, -10) + center = (int((displaysize[0] / 2) - (size[0] / 2)), int((displaysize[1] / 2) - (size[1] / 2))) + display.fillrect(center, size, display.WHITE) + pyb.delay(1000) + display.rect(center, size, display.RED) + pyb.delay(1000) + size = (displaysize[0] * 2, 50) + pos = (-displaysize[0], center[1]) + display.fillrect(pos, size, display.GREEN) + display.rect(pos, size, display.WHITE) + pyb.delay(2000) + +def testcircle( display ) : + print('testing circle') + displaysize = display.size() + radius = 20 + p0 = (radius, radius) + p1 = (displaysize[0] - radius, p0[1]) + p2 = (p1[0], displaysize[1] - radius) + p3 = (p0[0], p2[1]) + #draw filled circle win upper right, center and lower left + display.fillcircle(p0, radius, display.BLUE) + display.fillcircle(p1, radius, display.GRAY) + display.fillcircle(p2, radius, display.PURPLE) + display.fillcircle(p3, radius, display.NAVY) + #Now do border. + display.circle(p0, radius, display.CYAN) + display.circle(p1, radius, display.MAROON) + display.circle(p2, radius, display.YELLOW) + display.circle(p3, radius, display.FOREST) + pyb.delay(2000) + center = ((displaysize[0] >> 1), (displaysize[1] >> 1)) + #try negative radius + display.fillcircle(center, -radius, display.WHITE) + pyb.delay(2000) + display.circle(center, -radius, display.GREEN) + #tedt big circle. + display.fillcircle(center, 90, display.WHITE) + pyb.delay(2000) + display.circle(center, 90, display.GREEN) + display.fill(0) + #draw near edge to test clipping. + pos = (center[0], 0) + display.fillcircle(pos, 30, display.RED) + display.circle(pos, 30, display.PURPLE) + pos = (center[0], displaysize[1] - 1) + display.fillcircle(pos, 30, display.RED) + display.circle(pos, 30, display.PURPLE) + pos = (0, center[1]) + display.fillcircle(pos, 30, display.RED) + display.circle(pos, 30, display.PURPLE) + pos = (displaysize[0] - 1, center[1]) + display.fillcircle(pos, 30, display.RED) + display.circle(pos, 30, display.PURPLE) + pyb.delay(2000) + +def testtext( display ) : + print('testing text') + displaysize = display.size() + txt = "Testing Text" + fontA = [None, sysfont, seriffont, terminalfont] + + def draw( ) : + x = 0 + f = 0 + for y in range(0, display.size()[1], 10) : + display.text((x, y), txt, pyb.TFT.CYAN, fontA[f]) + x += 2 + f = (f + 1) % len(fontA) + + #draw text + draw() + pyb.delay(2000) + display.rotation(1) + display.fill(0) + draw() + pyb.delay(2000) + + #try passing bogus font dict + bogus = { "Hello": 1, "Width": 8 } + try: + display.text((0, 0), txt, pyb.TFT.GREEN, bogus) + except Exception as e : + print("Bogus font failed with:") + print(e) + + pyb.delay(2000) + display.fill(0) + display.rotation(3) + #try different scales + display.text((0, 0), txt, pyb.TFT.GREEN, fontA[0], 2) + display.text((0, 20), txt, pyb.TFT.BLUE, fontA[1], (2, 1)) + display.text((0, 30), txt, pyb.TFT.PURPLE, fontA[2], (1, 2)) + + display.rotation(2) + + #try negative scales + display.text((50, 50), txt, pyb.TFT.YELLOW, fontA[1], -1) + + display.rotation(0) + pyb.delay(2000) + +def testfill( display ) : + print("testing fill") + display.fill(pyb.TFT.GREEN) + pyb.delay(2000) + display.rotation(1) + display.fill(pyb.TFT.RED) + pyb.delay(2000) + display.rotation(2) + display.fill(pyb.TFT.BLACK) + #left at rotation 2. + +def testrgb( display ) : + print("bgr") + display.rgb(False) #bgr + pyb.delay(2000) + print("rgb") + display.rgb(True) #rgb + pyb.delay(1000) + +def testinvert( display ) : + print("Invert Color") + display.invertcolor(True) #invert color + pyb.delay(2000) + display.invertcolor(False) + pyb.delay(2000) + +def testonoff( display ) : + print("Display on/off") + display.on(False) + pyb.delay(2000) + display.on(True) + pyb.delay(2000) + +def run( display ) : + testdisplay = display + #inits? +# display.initg() + displaysize = display.size() + #draw pixels all over, try out of range values as well. + testpixel(display) + #draw lines in 360 deg at center, top left and bottom right + testline(display) + #fill using difference colors and different rotations. + testfill(display) + testtext(display) + display.fill(0) + testrect(display) + testcircle(display) + testinvert(display) + testrgb(display) + #off/on + testonoff(display) + print("Test Done")