Trouble debouncing buttons + some code logic questions

CircuitPython on hardware including Adafruit's boards, and CircuitPython libraries using Blinka on host computers.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
burrito_poots
 
Posts: 134
Joined: Thu May 30, 2019 5:02 pm

Trouble debouncing buttons + some code logic questions

Post by burrito_poots »

Hey gang,

So with my code below I'm having an issue figuring out how to debounce the buttons that I use. Right now I'm using a time.sleep option which works, but I'd like to go about doing this the correct way. But when I try to implement what I'm seeing here: https://www.youtube.com/watch?v=ktlRv83UvjY it doesn't work and I'm not really sure why that is.

Also, for my code logic: right now, I have two subprograms that I run ("Fil" and "CIP") -- the way my code is set up, switching between these with button_d works fine, but I can't wrap my head around the logic design for allowing a third subprogram, so I can cycle between them all. Any ideas on how to accomplish that? As best as I understand it, currently the logic I have setup only allows for the back and forth between the two subprograms. Thanks in advance!

Code: Select all

import board
import displayio
import terminalio
import busio
import digitalio
import adafruit_displayio_sh1107

from adafruit_display_shapes.roundrect import RoundRect
from adafruit_display_shapes.rect import Rect
from adafruit_display_shapes.circle import Circle
from adafruit_display_shapes.triangle import Triangle

from adafruit_display_text import label
import adafruit_displayio_sh1107

displayio.release_displays()
# old_reset = board.D9

# Use for I2C
i2c = board.I2C()
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)

# SH1107 is vertically oriented 64x128
WIDTH = 128
HEIGHT = 64
BORDER = 2

display = adafruit_displayio_sh1107.SH1107(display_bus, width=WIDTH, height=HEIGHT)

color_bitmap = displayio.Bitmap(WIDTH, HEIGHT, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF # White

# Make the display context
splash = displayio.Group()

display.show(splash)

fillscreen = displayio.Group()
CIPscreen = displayio.Group()
dropleticon = displayio.Group()
bubbleicon = displayio.Group()

import rotaryio
import time
from adafruit_motorkit import MotorKit
import adafruit_vl6180x
from adafruit_debouncer import Debouncer

sensor = adafruit_vl6180x.VL6180X(i2c)

encoderB = rotaryio.IncrementalEncoder(board.D12, board.D11)
button_e = digitalio.DigitalInOut(board.D10)
button_e.direction = digitalio.Direction.INPUT
button_e.pull = digitalio.Pull.UP
switch_e = Debouncer(button_e)


encoderA = rotaryio.IncrementalEncoder(board.A4, board.A3)
button_d = digitalio.DigitalInOut(board.A2)
button_d.direction = digitalio.Direction.INPUT
button_d.pull = digitalio.Pull.UP
switch_d = Debouncer(button_d)


range_mm = sensor.range

kit = MotorKit()

buttond_was_pushed = False
buttone_was_pushed = False
current_program = "Monarch"
program_running = False

lastA_position = None
lastB_position = None

text_area = label.Label(terminalio.FONT, text="monarch", scale=3, color=0xFFFFFF, x=3, y=12)
splash.append(text_area)
text_area2 = label.Label(terminalio.FONT, text="FLUID SYSTEMS", scale=1, color=0xFFFFFF, x=28, y=36)
splash.append(text_area2)
text_area3 = label.Label(terminalio.FONT, text="nano MK.I", scale=1, color=0xFFFFFF, x=70, y=55)
splash.append(text_area3)

color_bitmap = displayio.Bitmap(WIDTH, HEIGHT, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF  # White

# Draw some white squares
sm_bitmap = displayio.Bitmap(20, 12, 1)
sm_square = displayio.TileGrid(sm_bitmap, pixel_shader=color_palette, x=83, y=0)
fillscreen.append(sm_square)

# Draw some white squares
sm_bitmapCIP = displayio.Bitmap(20, 12, 1)
sm_squareCIP = displayio.TileGrid(sm_bitmapCIP, pixel_shader=color_palette, x=83, y=0)
CIPscreen.append(sm_squareCIP)

triangle = Triangle(40, 18, 37, 25, 43, 25, fill=0x000000, outline=0xFFFFFF)
dropleticon.append(triangle)
circle = Circle(40, 25, 3, fill=0x000000, outline=0xFFFFFF)
dropleticon.append(circle)
rectDroplet = Rect(39, 22, 3, 1, fill=0x000000)
dropleticon.append(rectDroplet)

dropleticon.x = 27
dropleticon.y = -17

fillscreen.append(dropleticon)

circle2 = Circle(68, 43, 3, fill=0x000000, outline=0xFFFFFF)
bubbleicon.append(circle2)
circle3 = Circle(64, 46, 4, fill=0x000000, outline=0xFFFFFF)
bubbleicon.append(circle3)
circle4 = Circle(70, 49, 3, fill=0x000000, outline=0xFFFFFF)
bubbleicon.append(circle4)

bubbleicon.x = 3
bubbleicon.y = -40

CIPscreen.append(bubbleicon)

rectTime = Rect(3, 29, 58, 34, outline=0xFFFFFF)
fillscreen.append(rectTime)
rectFoam = Rect(77, 29, 43, 34, outline=0xFFFFFF)
fillscreen.append(rectFoam)

roundrectTime = RoundRect(0, 22, 33, 15, 7, fill=0xFFFFFF, stroke=1)
fillscreen.append(roundrectTime)
roundrectFoam = RoundRect(74, 22, 38, 15, 7, fill=0xFFFFFF, stroke=1)
fillscreen.append(roundrectFoam)

text_area4 = label.Label(terminalio.FONT, text="Fill Mode:", scale=1, color=0xFFFFFF, x=0, y=5)
fillscreen.append(text_area4)
text_area5 = label.Label(terminalio.FONT, text="OFF", scale=1, color=0x000000, x=85, y=5)
fillscreen.append(text_area5)
text_area6 = label.Label(terminalio.FONT, text="ON", scale=1, color=0xFFFFFF, x=110, y=5)
fillscreen.append(text_area6)
text_area7 = label.Label(terminalio.FONT, text="Time", scale=1, color=0x000000, x=5, y=28)
fillscreen.append(text_area7)
text_area8 = label.Label(terminalio.FONT, text="0.0", scale=2, color=0xFFFFFF, x=8, y=47)
fillscreen.append(text_area8)
text_area9 = label.Label(terminalio.FONT, text="Pulse", scale=1, color=0x000000, x=79, y=28)
fillscreen.append(text_area9)
text_area10 = label.Label(terminalio.FONT, text="0", scale=2, color=0xFFFFFF, x=90, y=47)
fillscreen.append(text_area10)

text_area11 = label.Label(terminalio.FONT, text=" CIP Mode:", scale=1, color=0xFFFFFF, x=0, y=5)
CIPscreen.append(text_area11)
text_area12 = label.Label(terminalio.FONT, text="OFF", scale=1, color=0x000000, x=85, y=5)
CIPscreen.append(text_area12)
text_area13 = label.Label(terminalio.FONT, text="ON", scale=1, color=0xFFFFFF, x=110, y=5)
CIPscreen.append(text_area13)

triangle2 = Triangle(26, 22, 6, 62, 46, 62, fill=0xFFFFFF)
CIPscreen.append(triangle2)
triangle3 = Triangle(26, 50, 24, 34, 28, 34, fill=0x000000)
CIPscreen.append(triangle3)
circle5 = Circle(26, 57, 2, fill=0x000000)
CIPscreen.append(circle5)
circle6 = Circle(26, 33, 2, fill=0x000000)
CIPscreen.append(circle6)

text_area15 = label.Label(terminalio.FONT, text="WARNING:", scale=1, color=0xFFFFFF, x=64, y=25)
CIPscreen.append(text_area15)
text_area16 = label.Label(terminalio.FONT, text="Valves will", scale=1, color=0xFFFFFF, x=55, y=41)
CIPscreen.append(text_area16)
text_area17 = label.Label(terminalio.FONT, text="stay open!", scale=1, color=0xFFFFFF, x=59, y=53)
CIPscreen.append(text_area17)



#display.refresh()

while True:
    #dropleticon = displayio.Group()
    if button_d.value == 0:
        # Button_d has been pressed
        buttond_was_pushed = True
        time.sleep(.10)

    if button_e.value == 0:
        # Button_e has been pressed
        buttone_was_pushed = True
        time.sleep(.10)

    #if current_program == "Monarch" and buttond_was_pushed:

    if current_program != "Fil" and buttond_was_pushed:
        # We are on main screen or CIP, but want Fil.
        # Go there
        display.show(fillscreen)
        current_program = "Fil"
        buttond_was_pushed = False

    if current_program == "Fil" and buttone_was_pushed and not program_running:
        # Button was pushed, but program not yet running.
        # Make it run!
        program_running = True
        buttone_was_pushed = False

    #try:
        #range_mm = sensor.range
        #print('Range: {0}mm'.format(range_mm))
    #except RuntimeError:
        #print("retrying!")
    # time.sleep(.00001)

    if current_program == "Fil" and not buttone_was_pushed and program_running:
        # Fill program running, but button is not pushed... now what?
        positionA = encoderA.position
        if lastA_position is None or positionA != lastA_position:
            print(positionA)
        lastA_position = positionA
        timingA_value = 0.1*encoderA.position
        #print(timingA_value)  # can remove this once verified it works
        sm_square.x = 106
        text_area5.color = 0xFFFFFF
        text_area6.color = 0x000000
        text_area8.text = str(timingA_value)
        triangle.fill = 0xFFFFFF
        triangle.outline = 0xFFFFFF
        circle.fill = 0xFFFFFF
        circle.outline = 0xFFFFFF
        rectDroplet.fill = 0xFFFFFF

        positionB = encoderB.position
        if lastB_position is None or positionB != lastB_position:
            print(positionB)
        lastB_position = positionB
        timingB_value = encoderB.position
        #print(timingB_value)  # can remove this once verified it works
        text_area10.text = str(timingB_value)
        
        
    if current_program == "Fil" and buttone_was_pushed and program_running:
        # Button was pushed while fill program running so we want it off.
        # Switch it to off!
        sm_square.x = 83
        text_area5.color = 0x000000
        text_area6.color = 0xFFFFFF
        program_running = False
        triangle.outline = 0xFFFFFF
        triangle.fill = 0x000000
        circle.outline = 0xFFFFFF
        circle.fill = 0x000000
        rectDroplet.fill = 0x000000
        buttone_was_pushed = False

        if (range_mm >= 70): #"if program_running and (range_mm >= 70):" may need to update to this
            kit.motor2.throttle = 1.0       # Load can
            time.sleep(.8)                  # Piston extension time
            kit.motor2.throttle = 0         # Piston retract
            time.sleep(1)                   # need for can to fall into chute
            kit.motor4.throttle = 1.0       # Drop lift piston
            kit.motor1.throttle = 1.0       # Start Purge
            time.sleep(1.5)                 # Hold for 1.5 s
            kit.motor1.throttle = 0         # Stop Purge
            kit.motor3.throttle = 1.0       # Start Fill
            time.sleep(timingA_value)       # Hold for set time
            kit.motor3.throttle = 0         # End fill
            for _ in range(timingB_value):
                time.sleep(0.05)                # Hold for set time
                kit.motor3.throttle = 1.0       # Start Foam Pulse
                time.sleep(0.05)                # Hold for set time
                kit.motor3.throttle = 0         # End Foam Pulse
            kit.motor4.throttle = 0             # Raise lift
            time.sleep(.75)

    #try:
        #range_mm = sensor.range
        #print('Range2: {0}mm'.format(range_mm))
    #except RuntimeError:
        #print("retrying!")
    # time.sleep(.00001)

    if current_program != "CIP" and buttond_was_pushed:
        # We are on Monarch #or fill, and want CIP.
        # Go there
        display.show(CIPscreen)
        time.sleep(.20)
        triangle2.fill = 0x000000
        triangle3.fill = 0xFFFFFF
        circle5.fill = 0xFFFFFF
        circle6.fill = 0xFFFFFF
        time.sleep(.20)
        triangle2.fill = 0xFFFFFF
        triangle3.fill = 0x000000
        circle5.fill = 0x000000
        circle6.fill = 0x000000
        time.sleep(.20)
        triangle2.fill = 0x000000
        triangle3.fill = 0xFFFFFF
        circle5.fill = 0xFFFFFF
        circle6.fill = 0xFFFFFF
        time.sleep(.20)
        triangle2.fill = 0xFFFFFF
        triangle3.fill = 0x000000
        circle5.fill = 0x000000
        circle6.fill = 0x000000
        kit.motor4.throttle = 0.0
        kit.motor3.throttle = 0.0
        current_program = "CIP"
        program_running = False
        buttond_was_pushed = False

    if current_program == "CIP" and buttone_was_pushed and not program_running:
        # Button was pushed, but program not yet running.
        # Make it run!
        sm_squareCIP.x = 106
        text_area12.color = 0xFFFFFF
        text_area13.color = 0x000000 
        circle2.fill = 0xFFFFFF
        circle2.outline = 0xFFFFFF
        circle3.fill = 0xFFFFFF
        circle3.outline = 0xFFFFFF
        circle4.fill = 0xFFFFFF
        circle4.outline = 0xFFFFFF
        kit.motor4.throttle = 1.0
        time.sleep(.5)
        kit.motor3.throttle = 1.0
        current_program = "CIP"
        program_running = True
        buttone_was_pushed = False

    if current_program == "CIP" and buttone_was_pushed and program_running:
        # Button was pushed and program running.
        # Make it stop!
        sm_squareCIP.x = 83
        text_area12.color = 0x000000
        text_area13.color = 0xFFFFFF 
        circle2.fill = 0x000000
        circle2.outline = 0xFFFFFF
        circle3.fill = 0x000000
        circle3.outline = 0xFFFFFF
        circle4.fill = 0x000000
        circle4.outline = 0xFFFFFF
        kit.motor4.throttle = 0.0
        kit.motor3.throttle = 0.0
        current_program = "CIP"
        program_running = False
        buttone_was_pushed = False

User avatar
burrito_poots
 
Posts: 134
Joined: Thu May 30, 2019 5:02 pm

Re: Trouble debouncing buttons + some code logic questions

Post by burrito_poots »

Alright, so still unsure on the button debouncing but here's what I'm attempting to do logic wise to allow me to switch between three programs, basically I added in a little value that I set at the end of each subprogram: "previous_program == XYZ"

But I don't seem to have it working. My code is running, but my "Statsscreen" doesn't show up after my Fil screen, it just goes straight to CIP screen.

Code: Select all

import board
import displayio
import terminalio
import busio
import digitalio
import adafruit_displayio_sh1107

from adafruit_display_shapes.roundrect import RoundRect
from adafruit_display_shapes.rect import Rect
from adafruit_display_shapes.circle import Circle
from adafruit_display_shapes.triangle import Triangle

from adafruit_display_text import label
import adafruit_displayio_sh1107

displayio.release_displays()
# old_reset = board.D9

# Use for I2C
i2c = board.I2C()
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)

# SH1107 is vertically oriented 64x128
WIDTH = 128
HEIGHT = 64
BORDER = 2

display = adafruit_displayio_sh1107.SH1107(display_bus, width=WIDTH, height=HEIGHT)

color_bitmap = displayio.Bitmap(WIDTH, HEIGHT, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF # White

# Make the display context
splash = displayio.Group()

display.show(splash)

fillscreen = displayio.Group()
Statsscreen = displayio.Group()
CIPscreen = displayio.Group()
dropleticon = displayio.Group()
bubbleicon = displayio.Group()

import rotaryio
import time
from adafruit_motorkit import MotorKit
import adafruit_vl6180x
from adafruit_debouncer import Debouncer

sensor = adafruit_vl6180x.VL6180X(i2c)

encoderB = rotaryio.IncrementalEncoder(board.D12, board.D11)
button_e = digitalio.DigitalInOut(board.D10)
button_e.direction = digitalio.Direction.INPUT
button_e.pull = digitalio.Pull.UP
switch_e = Debouncer(button_e)


encoderA = rotaryio.IncrementalEncoder(board.A4, board.A3)
button_d = digitalio.DigitalInOut(board.A2)
button_d.direction = digitalio.Direction.INPUT
button_d.pull = digitalio.Pull.UP
switch_d = Debouncer(button_d)


range_mm = sensor.range

kit = MotorKit()

buttond_was_pushed = False
buttone_was_pushed = False
current_program = "Monarch"
program_running = False
previous_program = "CIP"

lastA_position = None
lastB_position = None

text_area = label.Label(terminalio.FONT, text="monarch", scale=3, color=0xFFFFFF, x=3, y=12)
splash.append(text_area)
text_area2 = label.Label(terminalio.FONT, text="FLUID SYSTEMS", scale=1, color=0xFFFFFF, x=28, y=36)
splash.append(text_area2)
text_area3 = label.Label(terminalio.FONT, text="nano MK.I", scale=1, color=0xFFFFFF, x=70, y=55)
splash.append(text_area3)

color_bitmap = displayio.Bitmap(WIDTH, HEIGHT, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF  # White

# Draw some white squares
sm_bitmap = displayio.Bitmap(20, 12, 1)
sm_square = displayio.TileGrid(sm_bitmap, pixel_shader=color_palette, x=83, y=0)
fillscreen.append(sm_square)

# Draw some white squares
sm_bitmapCIP = displayio.Bitmap(20, 12, 1)
sm_squareCIP = displayio.TileGrid(sm_bitmapCIP, pixel_shader=color_palette, x=83, y=0)
CIPscreen.append(sm_squareCIP)

triangle = Triangle(40, 18, 37, 25, 43, 25, fill=0x000000, outline=0xFFFFFF)
dropleticon.append(triangle)
circle = Circle(40, 25, 3, fill=0x000000, outline=0xFFFFFF)
dropleticon.append(circle)
rectDroplet = Rect(39, 22, 3, 1, fill=0x000000)
dropleticon.append(rectDroplet)

dropleticon.x = 27
dropleticon.y = -17

fillscreen.append(dropleticon)

circle2 = Circle(68, 43, 3, fill=0x000000, outline=0xFFFFFF)
bubbleicon.append(circle2)
circle3 = Circle(64, 46, 4, fill=0x000000, outline=0xFFFFFF)
bubbleicon.append(circle3)
circle4 = Circle(70, 49, 3, fill=0x000000, outline=0xFFFFFF)
bubbleicon.append(circle4)

bubbleicon.x = 3
bubbleicon.y = -40

CIPscreen.append(bubbleicon)

rectTime = Rect(3, 29, 58, 34, outline=0xFFFFFF)
fillscreen.append(rectTime)
rectFoam = Rect(77, 29, 43, 34, outline=0xFFFFFF)
fillscreen.append(rectFoam)

roundrectTime = RoundRect(0, 22, 33, 15, 7, fill=0xFFFFFF, stroke=1)
fillscreen.append(roundrectTime)
roundrectFoam = RoundRect(74, 22, 38, 15, 7, fill=0xFFFFFF, stroke=1)
fillscreen.append(roundrectFoam)

text_area4 = label.Label(terminalio.FONT, text="Fill Mode:", scale=1, color=0xFFFFFF, x=0, y=5)
fillscreen.append(text_area4)
text_area5 = label.Label(terminalio.FONT, text="OFF", scale=1, color=0x000000, x=85, y=5)
fillscreen.append(text_area5)
text_area6 = label.Label(terminalio.FONT, text="ON", scale=1, color=0xFFFFFF, x=110, y=5)
fillscreen.append(text_area6)
text_area7 = label.Label(terminalio.FONT, text="Time", scale=1, color=0x000000, x=5, y=28)
fillscreen.append(text_area7)
text_area8 = label.Label(terminalio.FONT, text="0.0", scale=2, color=0xFFFFFF, x=8, y=47)
fillscreen.append(text_area8)
text_area9 = label.Label(terminalio.FONT, text="Pulse", scale=1, color=0x000000, x=79, y=28)
fillscreen.append(text_area9)
text_area10 = label.Label(terminalio.FONT, text="0", scale=2, color=0xFFFFFF, x=90, y=47)
fillscreen.append(text_area10)

text_area11 = label.Label(terminalio.FONT, text=" CIP Mode:", scale=1, color=0xFFFFFF, x=0, y=5)
CIPscreen.append(text_area11)
text_area12 = label.Label(terminalio.FONT, text="OFF", scale=1, color=0x000000, x=85, y=5)
CIPscreen.append(text_area12)
text_area13 = label.Label(terminalio.FONT, text="ON", scale=1, color=0xFFFFFF, x=110, y=5)
CIPscreen.append(text_area13)

triangle2 = Triangle(26, 22, 6, 62, 46, 62, fill=0xFFFFFF)
CIPscreen.append(triangle2)
triangle3 = Triangle(26, 50, 24, 34, 28, 34, fill=0x000000)
CIPscreen.append(triangle3)
circle5 = Circle(26, 57, 2, fill=0x000000)
CIPscreen.append(circle5)
circle6 = Circle(26, 33, 2, fill=0x000000)
CIPscreen.append(circle6)

text_area15 = label.Label(terminalio.FONT, text="WARNING:", scale=1, color=0xFFFFFF, x=64, y=25)
CIPscreen.append(text_area15)
text_area16 = label.Label(terminalio.FONT, text="Valves will", scale=1, color=0xFFFFFF, x=55, y=41)
CIPscreen.append(text_area16)
text_area17 = label.Label(terminalio.FONT, text="stay open!", scale=1, color=0xFFFFFF, x=59, y=53)
CIPscreen.append(text_area17)


text_area18 = label.Label(terminalio.FONT, text="Canning Stats:", scale=1, color=0xFFFFFF, x=0, y=5)
Statsscreen.append(text_area18)
text_area19 = label.Label(terminalio.FONT, text="OFF", scale=1, color=0x000000, x=85, y=5)
Statsscreen.append(text_area19)
text_area20 = label.Label(terminalio.FONT, text="ON", scale=1, color=0xFFFFFF, x=110, y=5)
Statsscreen.append(text_area20)
text_area21 = label.Label(terminalio.FONT, text="Cans", scale=1, color=0x000000, x=5, y=28)
Statsscreen.append(text_area21)
text_area22 = label.Label(terminalio.FONT, text="24", scale=2, color=0xFFFFFF, x=8, y=47)
Statsscreen.append(text_area22)
text_area23 = label.Label(terminalio.FONT, text="Cases", scale=1, color=0x000000, x=79, y=28)
Statsscreen.append(text_area23)
text_area24 = label.Label(terminalio.FONT, text="1", scale=2, color=0xFFFFFF, x=90, y=47)
Statsscreen.append(text_area24)

#display.refresh()

while True:
    #dropleticon = displayio.Group()
    if button_d.value == 0:
        # Button_d has been pressed
        buttond_was_pushed = True
        time.sleep(.10)

    if button_e.value == 0:
        # Button_e has been pressed
        buttone_was_pushed = True
        time.sleep(.10)

    #if current_program == "Monarch" and buttond_was_pushed:

    if current_program != "Fil" and buttond_was_pushed and previous_program == "CIP":
        # We are on main screen or CIP, but want Fil.
        # Go there
        display.show(fillscreen)
        current_program = "Fil"
        buttond_was_pushed = False
        previous_program = "Fill"

    if current_program == "Fil" and buttone_was_pushed and not program_running:
        # Button was pushed, but program not yet running.
        # Make it run!
        program_running = True
        buttone_was_pushed = False

    #try:
        #range_mm = sensor.range
        #print('Range: {0}mm'.format(range_mm))
    #except RuntimeError:
        #print("retrying!")
    # time.sleep(.00001)

    if current_program == "Fil" and not buttone_was_pushed and program_running:
        # Fill program running, but button is not pushed... now what?
        positionA = encoderA.position
        if lastA_position is None or positionA != lastA_position:
            print(positionA)
        lastA_position = positionA
        timingA_value = 0.1*encoderA.position
        #print(timingA_value)  # can remove this once verified it works
        sm_square.x = 106
        text_area5.color = 0xFFFFFF
        text_area6.color = 0x000000
        text_area8.text = str(timingA_value)
        triangle.fill = 0xFFFFFF
        triangle.outline = 0xFFFFFF
        circle.fill = 0xFFFFFF
        circle.outline = 0xFFFFFF
        rectDroplet.fill = 0xFFFFFF

        positionB = encoderB.position
        if lastB_position is None or positionB != lastB_position:
            print(positionB)
        lastB_position = positionB
        timingB_value = encoderB.position
        #print(timingB_value)  # can remove this once verified it works
        text_area10.text = str(timingB_value)
        
        
    if current_program == "Fil" and buttone_was_pushed and program_running:
        # Button was pushed while fill program running so we want it off.
        # Switch it to off!
        sm_square.x = 83
        text_area5.color = 0x000000
        text_area6.color = 0xFFFFFF
        program_running = False
        triangle.outline = 0xFFFFFF
        triangle.fill = 0x000000
        circle.outline = 0xFFFFFF
        circle.fill = 0x000000
        rectDroplet.fill = 0x000000
        buttone_was_pushed = False

        if (range_mm >= 70): #"if program_running and (range_mm >= 70):" may need to update to this
            kit.motor2.throttle = 1.0       # Load can
            time.sleep(.8)                  # Piston extension time
            kit.motor2.throttle = 0         # Piston retract
            time.sleep(1)                   # need for can to fall into chute
            kit.motor4.throttle = 1.0       # Drop lift piston
            kit.motor1.throttle = 1.0       # Start Purge
            time.sleep(1.5)                 # Hold for 1.5 s
            kit.motor1.throttle = 0         # Stop Purge
            kit.motor3.throttle = 1.0       # Start Fill
            time.sleep(timingA_value)       # Hold for set time
            kit.motor3.throttle = 0         # End fill
            for _ in range(timingB_value):
                time.sleep(0.05)                # Hold for set time
                kit.motor3.throttle = 1.0       # Start Foam Pulse
                time.sleep(0.05)                # Hold for set time
                kit.motor3.throttle = 0         # End Foam Pulse
            kit.motor4.throttle = 0             # Raise lift
            time.sleep(.75)

    #try:
        #range_mm = sensor.range
        #print('Range2: {0}mm'.format(range_mm))
    #except RuntimeError:
        #print("retrying!")
    # time.sleep(.00001)
    
    if current_program != "Stats" and buttond_was_pushed and previous_program == "Fill":
        # We are on fill, and want Stats
        display.show(Statsscreen)
        current_program = "Stats"
        previous_program = "Stats"

    if current_program != "CIP" and buttond_was_pushed and previous_program == "Stats":
        # We are on Stats, and want CIP.
        # Go there
        display.show(CIPscreen)
        time.sleep(.20)
        triangle2.fill = 0x000000
        triangle3.fill = 0xFFFFFF
        circle5.fill = 0xFFFFFF
        circle6.fill = 0xFFFFFF
        time.sleep(.20)
        triangle2.fill = 0xFFFFFF
        triangle3.fill = 0x000000
        circle5.fill = 0x000000
        circle6.fill = 0x000000
        time.sleep(.20)
        triangle2.fill = 0x000000
        triangle3.fill = 0xFFFFFF
        circle5.fill = 0xFFFFFF
        circle6.fill = 0xFFFFFF
        time.sleep(.20)
        triangle2.fill = 0xFFFFFF
        triangle3.fill = 0x000000
        circle5.fill = 0x000000
        circle6.fill = 0x000000
        kit.motor4.throttle = 0.0
        kit.motor3.throttle = 0.0
        current_program = "CIP"
        program_running = False
        buttond_was_pushed = False
        previous_program = "CIP"

    if current_program == "CIP" and buttone_was_pushed and not program_running:
        # Button was pushed, but program not yet running.
        # Make it run!
        sm_squareCIP.x = 106
        text_area12.color = 0xFFFFFF
        text_area13.color = 0x000000 
        circle2.fill = 0xFFFFFF
        circle2.outline = 0xFFFFFF
        circle3.fill = 0xFFFFFF
        circle3.outline = 0xFFFFFF
        circle4.fill = 0xFFFFFF
        circle4.outline = 0xFFFFFF
        kit.motor4.throttle = 1.0
        time.sleep(.5)
        kit.motor3.throttle = 1.0
        current_program = "CIP"
        program_running = True
        buttone_was_pushed = False

    if current_program == "CIP" and buttone_was_pushed and program_running:
        # Button was pushed and program running.
        # Make it stop!
        sm_squareCIP.x = 83
        text_area12.color = 0x000000
        text_area13.color = 0xFFFFFF 
        circle2.fill = 0x000000
        circle2.outline = 0xFFFFFF
        circle3.fill = 0x000000
        circle3.outline = 0xFFFFFF
        circle4.fill = 0x000000
        circle4.outline = 0xFFFFFF
        kit.motor4.throttle = 0.0
        kit.motor3.throttle = 0.0
        current_program = "CIP"
        program_running = False
        buttone_was_pushed = False

User avatar
burrito_poots
 
Posts: 134
Joined: Thu May 30, 2019 5:02 pm

Re: Trouble debouncing buttons + some code logic questions

Post by burrito_poots »

Figured out why that loop wasn't working!

In this section of code:

Code: Select all

    if current_program != "Stats" and buttond_was_pushed and previous_program == "Fill":
        # We are on fill, and want Stats
        display.show(Statsscreen)
        current_program = "Stats"
        previous_program = "Stats"
I needed this line added in:

Code: Select all

    if current_program != "Stats" and buttond_was_pushed and previous_program == "Fill":
        # We are on fill, and want Stats
        display.show(Statsscreen)
        current_program = "Stats"
        buttond_was_pushed = False
        previous_program = "Stats"
Now I just need help figuring out the debouncing :)

User avatar
adafruit_support_bill
 
Posts: 88154
Joined: Sat Feb 07, 2009 10:11 am

Re: Trouble debouncing buttons + some code logic questions

Post by adafruit_support_bill »

Basic question: Are you seeing problems that you think are caused by bouncing?

I see lots of convoluted debouncing schemes - many of which serve no purpose for many applications. If the action associated with a button press takes more than a few milliseconds, then the bounces will never be seen, so the added logic is unnecessary.

In your case, it looks like a button press initiates a sequence of operations that should outlast any mechanical bouncing. So you can probably just look for the initial press.

User avatar
burrito_poots
 
Posts: 134
Joined: Thu May 30, 2019 5:02 pm

Re: Trouble debouncing buttons + some code logic questions

Post by burrito_poots »

adafruit_support_bill wrote:Basic question: Are you seeing problems that you think are caused by bouncing?

I see lots of convoluted debouncing schemes - many of which serve no purpose for many applications. If the action associated with a button press takes more than a few milliseconds, then the bounces will never be seen, so the added logic is unnecessary.

In your case, it looks like a button press initiates a sequence of operations that should outlast any mechanical bouncing. So you can probably just look for the initial press.

When you say look for the initial press, do you mean like utilizing the "fell" thingy from this guide: https://learn.adafruit.com/debouncer-li ... debouncing?

I am seeing some debouncing issues. Basically using the buttons to also turn off or on a "subprogram" and they're quickly switching between or not registering because they switch there and back. Adding a time.sleep has all but solved this but I'd like to go about it the debouncing way as I imagine that will run smoother and such as my code grows.

User avatar
burrito_poots
 
Posts: 134
Joined: Thu May 30, 2019 5:02 pm

Re: Trouble debouncing buttons + some code logic questions

Post by burrito_poots »

Got it figured out! I needed to add the switch update part (in this instance "switch_d.update()" and "switch_d.update()" at the end of each loop where that particular switch was being "watched for" if that makes sense.

Heres the solved and working code in case anyone runs into a similar problem and this can help in the future:

Code: Select all

import board
import displayio
import terminalio
import busio
import digitalio
import adafruit_displayio_sh1107

from adafruit_display_shapes.roundrect import RoundRect
from adafruit_display_shapes.rect import Rect
from adafruit_display_shapes.circle import Circle
from adafruit_display_shapes.triangle import Triangle

from adafruit_display_text import label
import adafruit_displayio_sh1107

displayio.release_displays()
# old_reset = board.D9

# Use for I2C
i2c = board.I2C()
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)

# SH1107 is vertically oriented 64x128
WIDTH = 128
HEIGHT = 64
BORDER = 2

display = adafruit_displayio_sh1107.SH1107(display_bus, width=WIDTH, height=HEIGHT)

color_bitmap = displayio.Bitmap(WIDTH, HEIGHT, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF # White

# Make the display context
splash = displayio.Group()

display.show(splash)

fillscreen = displayio.Group()
Statsscreen = displayio.Group()
CIPscreen = displayio.Group()
dropleticon = displayio.Group()
bubbleicon = displayio.Group()

import rotaryio
import time
from adafruit_motorkit import MotorKit
import adafruit_vl6180x
from adafruit_debouncer import Debouncer

sensor = adafruit_vl6180x.VL6180X(i2c)

encoderB = rotaryio.IncrementalEncoder(board.D12, board.D11)
button_e = digitalio.DigitalInOut(board.D10)
button_e.direction = digitalio.Direction.INPUT
button_e.pull = digitalio.Pull.UP
switch_e = Debouncer(button_e)


encoderA = rotaryio.IncrementalEncoder(board.A4, board.A3)
button_d = digitalio.DigitalInOut(board.A2)
button_d.direction = digitalio.Direction.INPUT
button_d.pull = digitalio.Pull.UP
switch_d = Debouncer(button_d)


range_mm = sensor.range

kit = MotorKit()

#buttond_was_pushed = False
#buttone_was_pushed = False
current_program = "Monarch"
program_running = False
previous_program = "CIP"

lastA_position = None
lastB_position = None

text_area = label.Label(terminalio.FONT, text="monarch", scale=3, color=0xFFFFFF, x=3, y=12)
splash.append(text_area)
text_area2 = label.Label(terminalio.FONT, text="FLUID SYSTEMS", scale=1, color=0xFFFFFF, x=28, y=36)
splash.append(text_area2)
text_area3 = label.Label(terminalio.FONT, text="nano MK.I", scale=1, color=0xFFFFFF, x=70, y=55)
splash.append(text_area3)

color_bitmap = displayio.Bitmap(WIDTH, HEIGHT, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF  # White

# Draw some white squares
sm_bitmap = displayio.Bitmap(20, 12, 1)
sm_square = displayio.TileGrid(sm_bitmap, pixel_shader=color_palette, x=83, y=0)
fillscreen.append(sm_square)

# Draw some white squares
sm_bitmapCIP = displayio.Bitmap(20, 12, 1)
sm_squareCIP = displayio.TileGrid(sm_bitmapCIP, pixel_shader=color_palette, x=83, y=0)
CIPscreen.append(sm_squareCIP)

triangle = Triangle(40, 18, 37, 25, 43, 25, fill=0x000000, outline=0xFFFFFF)
dropleticon.append(triangle)
circle = Circle(40, 25, 3, fill=0x000000, outline=0xFFFFFF)
dropleticon.append(circle)
rectDroplet = Rect(39, 22, 3, 1, fill=0x000000)
dropleticon.append(rectDroplet)

dropleticon.x = 27
dropleticon.y = -17

fillscreen.append(dropleticon)

circle2 = Circle(68, 43, 3, fill=0x000000, outline=0xFFFFFF)
bubbleicon.append(circle2)
circle3 = Circle(64, 46, 4, fill=0x000000, outline=0xFFFFFF)
bubbleicon.append(circle3)
circle4 = Circle(70, 49, 3, fill=0x000000, outline=0xFFFFFF)
bubbleicon.append(circle4)

bubbleicon.x = 3
bubbleicon.y = -40

CIPscreen.append(bubbleicon)

rectTime = Rect(3, 29, 58, 34, outline=0xFFFFFF)
fillscreen.append(rectTime)
rectFoam = Rect(77, 29, 43, 34, outline=0xFFFFFF)
fillscreen.append(rectFoam)

roundrectTime = RoundRect(0, 22, 33, 15, 7, fill=0xFFFFFF, stroke=1)
fillscreen.append(roundrectTime)
roundrectFoam = RoundRect(74, 22, 38, 15, 7, fill=0xFFFFFF, stroke=1)
fillscreen.append(roundrectFoam)

text_area4 = label.Label(terminalio.FONT, text="Fill Mode:", scale=1, color=0xFFFFFF, x=0, y=5)
fillscreen.append(text_area4)
text_area5 = label.Label(terminalio.FONT, text="OFF", scale=1, color=0x000000, x=85, y=5)
fillscreen.append(text_area5)
text_area6 = label.Label(terminalio.FONT, text="ON", scale=1, color=0xFFFFFF, x=110, y=5)
fillscreen.append(text_area6)
text_area7 = label.Label(terminalio.FONT, text="Time", scale=1, color=0x000000, x=5, y=28)
fillscreen.append(text_area7)
text_area8 = label.Label(terminalio.FONT, text="0.0", scale=2, color=0xFFFFFF, x=8, y=47)
fillscreen.append(text_area8)
text_area9 = label.Label(terminalio.FONT, text="Pulse", scale=1, color=0x000000, x=79, y=28)
fillscreen.append(text_area9)
text_area10 = label.Label(terminalio.FONT, text="0", scale=2, color=0xFFFFFF, x=90, y=47)
fillscreen.append(text_area10)

text_area11 = label.Label(terminalio.FONT, text=" CIP Mode:", scale=1, color=0xFFFFFF, x=0, y=5)
CIPscreen.append(text_area11)
text_area12 = label.Label(terminalio.FONT, text="OFF", scale=1, color=0x000000, x=85, y=5)
CIPscreen.append(text_area12)
text_area13 = label.Label(terminalio.FONT, text="ON", scale=1, color=0xFFFFFF, x=110, y=5)
CIPscreen.append(text_area13)

triangle2 = Triangle(26, 22, 6, 62, 46, 62, fill=0xFFFFFF)
CIPscreen.append(triangle2)
triangle3 = Triangle(26, 50, 24, 34, 28, 34, fill=0x000000)
CIPscreen.append(triangle3)
circle5 = Circle(26, 57, 2, fill=0x000000)
CIPscreen.append(circle5)
circle6 = Circle(26, 33, 2, fill=0x000000)
CIPscreen.append(circle6)

text_area15 = label.Label(terminalio.FONT, text="WARNING:", scale=1, color=0xFFFFFF, x=64, y=25)
CIPscreen.append(text_area15)
text_area16 = label.Label(terminalio.FONT, text="Valves will", scale=1, color=0xFFFFFF, x=55, y=41)
CIPscreen.append(text_area16)
text_area17 = label.Label(terminalio.FONT, text="stay open!", scale=1, color=0xFFFFFF, x=59, y=53)
CIPscreen.append(text_area17)


text_area18 = label.Label(terminalio.FONT, text="Canning Stats:", scale=1, color=0xFFFFFF, x=0, y=5)
Statsscreen.append(text_area18)
text_area19 = label.Label(terminalio.FONT, text="OFF", scale=1, color=0x000000, x=85, y=5)
Statsscreen.append(text_area19)
text_area20 = label.Label(terminalio.FONT, text="ON", scale=1, color=0xFFFFFF, x=110, y=5)
Statsscreen.append(text_area20)
text_area21 = label.Label(terminalio.FONT, text="Cans", scale=1, color=0x000000, x=5, y=28)
Statsscreen.append(text_area21)
text_area22 = label.Label(terminalio.FONT, text="24", scale=2, color=0xFFFFFF, x=8, y=47)
Statsscreen.append(text_area22)
text_area23 = label.Label(terminalio.FONT, text="Cases", scale=1, color=0x000000, x=79, y=28)
Statsscreen.append(text_area23)
text_area24 = label.Label(terminalio.FONT, text="1", scale=2, color=0xFFFFFF, x=90, y=47)
Statsscreen.append(text_area24)

#display.refresh()

while True:
    switch_e.update()
    switch_d.update()

    if current_program != "Fil" and switch_d.fell and previous_program == "CIP":
        # We are on main screen or CIP, but want Fil.
        # Go there
        display.show(fillscreen)
        current_program = "Fil"
        #buttond_was_pushed = False
        previous_program = "Fill"
        switch_d.update()
    
    if current_program == "Fil" and switch_e.fell and not program_running:
        # Button was pushed, but program not yet running.
        # Make it run!
        program_running = True
        switch_e.update()

    #try:
        #range_mm = sensor.range
        #print('Range: {0}mm'.format(range_mm))
    #except RuntimeError:
        #print("retrying!")
    # time.sleep(.00001)

    if current_program == "Fil" and program_running:
        # Fill program running, but button is not pushed... now what?
        positionA = encoderA.position
        if lastA_position is None or positionA != lastA_position:
            print(positionA)
        lastA_position = positionA
        timingA_value = 0.1*encoderA.position
        #print(timingA_value)  # can remove this once verified it works
        sm_square.x = 106
        text_area5.color = 0xFFFFFF
        text_area6.color = 0x000000
        text_area8.text = str(timingA_value)
        triangle.fill = 0xFFFFFF
        triangle.outline = 0xFFFFFF
        circle.fill = 0xFFFFFF
        circle.outline = 0xFFFFFF
        rectDroplet.fill = 0xFFFFFF

        positionB = encoderB.position
        if lastB_position is None or positionB != lastB_position:
            print(positionB)
        lastB_position = positionB
        timingB_value = encoderB.position
        #print(timingB_value)  # can remove this once verified it works
        text_area10.text = str(timingB_value)
    
    if current_program == "Fil" and switch_e.fell and program_running:
        # Button was pushed while fill program running so we want it off.
        # Switch it to off!
        sm_square.x = 83
        text_area5.color = 0x000000
        text_area6.color = 0xFFFFFF
        program_running = False
        triangle.outline = 0xFFFFFF
        triangle.fill = 0x000000
        circle.outline = 0xFFFFFF
        circle.fill = 0x000000
        rectDroplet.fill = 0x000000
        switch_e.update()

        if (range_mm >= 70): #"if program_running and (range_mm >= 70):" may need to update to this
            kit.motor2.throttle = 1.0       # Load can
            time.sleep(.8)                  # Piston extension time
            kit.motor2.throttle = 0         # Piston retract
            time.sleep(1)                   # need for can to fall into chute
            kit.motor4.throttle = 1.0       # Drop lift piston
            kit.motor1.throttle = 1.0       # Start Purge
            time.sleep(1.5)                 # Hold for 1.5 s
            kit.motor1.throttle = 0         # Stop Purge
            kit.motor3.throttle = 1.0       # Start Fill
            time.sleep(timingA_value)       # Hold for set time
            kit.motor3.throttle = 0         # End fill
            for _ in range(timingB_value):
                time.sleep(0.05)                # Hold for set time
                kit.motor3.throttle = 1.0       # Start Foam Pulse
                time.sleep(0.05)                # Hold for set time
                kit.motor3.throttle = 0         # End Foam Pulse
            kit.motor4.throttle = 0             # Raise lift
            time.sleep(.75)

    #try:
        #range_mm = sensor.range
        #print('Range2: {0}mm'.format(range_mm))
    #except RuntimeError:
        #print("retrying!")
    # time.sleep(.00001)

    if current_program != "Stats" and switch_d.fell and previous_program == "Fill":
        # We are on fill, and want Stats
        display.show(Statsscreen)
        current_program = "Stats"
        #buttond_was_pushed = False
        previous_program = "Stats"
        switch_d.update()
    
    if current_program != "CIP" and switch_d.fell and previous_program == "Stats":
        # We are on Stats, and want CIP.
        # Go there
        display.show(CIPscreen)
        time.sleep(.20)
        triangle2.fill = 0x000000
        triangle3.fill = 0xFFFFFF
        circle5.fill = 0xFFFFFF
        circle6.fill = 0xFFFFFF
        time.sleep(.20)
        triangle2.fill = 0xFFFFFF
        triangle3.fill = 0x000000
        circle5.fill = 0x000000
        circle6.fill = 0x000000
        time.sleep(.20)
        triangle2.fill = 0x000000
        triangle3.fill = 0xFFFFFF
        circle5.fill = 0xFFFFFF
        circle6.fill = 0xFFFFFF
        time.sleep(.20)
        triangle2.fill = 0xFFFFFF
        triangle3.fill = 0x000000
        circle5.fill = 0x000000
        circle6.fill = 0x000000
        kit.motor4.throttle = 0.0
        kit.motor3.throttle = 0.0
        current_program = "CIP"
        program_running = False
        #buttond_was_pushed = False
        previous_program = "CIP"
        switch_d.update()
    
    if current_program == "CIP" and switch_e.fell and not program_running:
        # Button was pushed, but program not yet running.
        # Make it run!
        sm_squareCIP.x = 106
        text_area12.color = 0xFFFFFF
        text_area13.color = 0x000000 
        circle2.fill = 0xFFFFFF
        circle2.outline = 0xFFFFFF
        circle3.fill = 0xFFFFFF
        circle3.outline = 0xFFFFFF
        circle4.fill = 0xFFFFFF
        circle4.outline = 0xFFFFFF
        kit.motor4.throttle = 1.0
        time.sleep(.5)
        kit.motor3.throttle = 1.0
        current_program = "CIP"
        program_running = True
        switch_e.update()
    
    if current_program == "CIP" and switch_e.fell and program_running:
        # Button was pushed and program running.
        # Make it stop!
        sm_squareCIP.x = 83
        text_area12.color = 0x000000
        text_area13.color = 0xFFFFFF 
        circle2.fill = 0x000000
        circle2.outline = 0xFFFFFF
        circle3.fill = 0x000000
        circle3.outline = 0xFFFFFF
        circle4.fill = 0x000000
        circle4.outline = 0xFFFFFF
        kit.motor4.throttle = 0.0
        kit.motor3.throttle = 0.0
        current_program = "CIP"
        program_running = False
        switch_e.update()

User avatar
adafruit_support_bill
 
Posts: 88154
Joined: Sat Feb 07, 2009 10:11 am

Re: Trouble debouncing buttons + some code logic questions

Post by adafruit_support_bill »

When you say look for the initial press, do you mean like utilizing the "fell" thingy from this guide:
Yes. The initial press is a real event and you can use that to initiate an action. If the action takes longer than the bouncing action of the contacts, no further logic is required. For shorter actions, the simplest thing to do is add a short delay before continuing the main loop.

Locked
Please be positive and constructive with your questions and comments.

Return to “Adafruit CircuitPython”