0

I am running out of ideas to get this Python code working the way I want it to. Please take a look at my code and help me figure out what's wrong, or if it's a hardware issue with the Pi causing my issue.

Goal: Use a fingerprint reader to start my car. Car is controlled via RPi GPIO pins and relays.

The setup: I'm using a fingerprint reader module and a modified version of the Adafruit fingerprint reader script. I have a button wired into my dash in the car that when turned on, will activate the Ignition and Accessory circuits (Windows, Radio, cigarette lighter, etc.), and then the fingerprint reader will activate until a registered finger is placed, or the button is switched off again. the button is wired between GPIO 5 and a ground pin on the Raspberry Pi, and pulls the pin "LOW" when active. GPIO 5 is initially pulled up.

The problem: I seem to be having issues getting a "button_state" variable to read reliably here. The following code is almost function perfect, but every time I switch the button "OFF" after the car is started, a repeated command happens where it will print "Accessories Off", as it should, but then it prints "Accessories On", followed by "Accessories Off" again. I really can't understand why this part of the code is creating this unwanted repetition here, especially because "Accessories On" should only print if the button is on (0) but the button is clearly off (1)

This makes me wonder if the RPi pin is giving false signals and confusing the code, or is there something wrong with the flow of my Python code here?

The code:

import RPi.GPIO as io
import time
import adafruit_fingerprint
import serial
io.setwarnings(False)
io.setmode(io.BCM)
io.setup(5, io.IN, io.PUD_UP)
BUTTON = 5
ACC = 23
IGN = 27
START = 22
uart = serial.Serial("/dev/ttyAMA0", baudrate=57600, timeout=1)
finger = adafruit_fingerprint.Adafruit_Fingerprint(uart)
started = 0
ignition = 0

##################################################


# This block is pretty much straight from the Adafruit code, slightly 
# modified with my button checks, this segment seems to work fine

def get_fingerprint():
    while finger.get_image() != adafruit_fingerprint.OK:
        button_off = io.input(BUTTON)
        if button_off == 1:
            return False
        if button_off == 0:
            pass
    if finger.image_2_tz(1) != adafruit_fingerprint.OK:
        return False
    if finger.finger_fast_search() != adafruit_fingerprint.OK:
        return False
    return True

while True:

    button_off = io.input(BUTTON) ### Constantly checking for the button state because 
# when I dont it seems to just remember the state from a certain point instead of giving reliable updated readings

#Button is on
    if started == 0: #car is not started yet
        if ignition == 0: #Accessory and Ignition are not on
            if button_off == 0:
                print ("Accessories on") #This message displays after turning the button off... why?? The if statement clearly says 0 so I don't get why this part of the code would execute
                ignition = 1
        if ignition == 1:
            if button_off == 0:
                if get_fingerprint():
                    print("Car started.")
                    started = 1
    if started == 1:
        pass

#Button is off
    if button_off == 1:

        if ignition == 1: #should only do this once if the button was on, otherwise just continue polling the input state of the button.
            print("Accessories off") ###This statement works fine before the finger print, but will execute twice if I turn off the button after the finger sequence. Why?
            ignition = 0
            started = 0
  • What is the button? If it is a mechanical button how have you mitigated against contact bounce? – joan Nov 9 at 18:00
  • 1
    I did not read the code, but the description of your problem sounds like it could be caused by contact bounce, which affects all physical buttons. To mitigate that you need to use some debouncing algorithm; gpio libraries may have one built in you can use. If not, do not use anything too simplistic, there are some naive/lazy ones around that won't hold up well in practice. – goldilocks Nov 9 at 18:06
  • 1
    These are the type of button I am using: amazon.com/gp/product/B011U1NU90/… I was not aware of contact bounce, any recommendations to add to the code as a double check? Everything I have tried to confirm the button state after a brief waiting period seems to have failed so far – cornerpocket Nov 9 at 19:11
  • 1
    Perhaps run monitor.py while switching the button. E.g. sudo pigpiod then ./monitor.py 5 22 23 27 to see what happens. – joan Nov 9 at 20:15
  • Ah, let me see: "Amazon 12VDC 20A Car Truck Rocker Round, RGBY LED Toggle On-Off SPST Mechanical Switch - US$7/12pcs", amazon.com/dp/B011U1NU90. I once used my scope to check the bouncing time of this type of (used made in TW, now CN) and found around 50mS (good switches usually < 10mS). Anyway, I would suggest to insert a software debouncing function in you python GPIO read switch code. PS - when I was a Rpi and python newbie, and in case of any problem, first thing I did was cursing Rpi and python. Now I am a ninja, first thing I do is googling! :) Cheers. – tlfong01 Nov 10 at 1:16
0

Thanks everyone for the suggestions. I suspected something like contact bounce wasn't the issue here because the button response works perfectly before the fingerprint sequence of the code executed, it was only after the get_fingerprint block returning True that the button would have the effect, making me think the python code was repeating somewhere it shouldn't.

To anyone googling this in the future or anyone interested in doing a similar project, here is the tweaked code that I got working with the help of a friend. Using a fingerprint reader compatible with the Adafruit fingerprint library and a switch, I can start my car using a fingerprint. I have the script boot at startup using crontab.

Some differences from my original code are the get_button() block, and reversing the negative logic to make it less confusing.

Here is the working code. I haven't field tested it extensively yet but everything appears to work perfect now.

import RPi.GPIO as io
import time
import adafruit_fingerprint
import serial
io.setwarnings(False)
io.setmode(io.BCM)

#GPIO Names
BUTTON = 5
ACC = 23
IGN = 27
START = 22
DOME = 20

#GPIO Setup
io.setup(BUTTON, io.IN, io.PUD_UP)
io.setup(ACC, io.OUT)
io.setup(IGN, io.OUT)
io.setup(START, io.OUT)
io.setup(DOME, io.OUT)
io.output(ACC, 1)
io.output(IGN, 1)
io.output(START, 1)
io.output(DOME, 1)

#UART/Fingerprint Setup
uart = serial.Serial("/dev/ttyAMA0", baudrate=57600, timeout=1)
finger = adafruit_fingerprint.Adafruit_Fingerprint(uart)

##################################################

def get_button():
    result = (not io.input(BUTTON))
    time.sleep(.1)
    return result

def get_fingerprint():
    while finger.get_image() != adafruit_fingerprint.OK: #Waiting for finger, loops
        if io.input(BUTTON) == 1: #Exit finger sequence if button off
            return False
    if finger.image_2_tz(1) != adafruit_fingerprint.OK:
        return False
    if finger.finger_fast_search() != adafruit_fingerprint.OK:
        return False
    return True

while True:

    car_on = get_button()

#Button is on
    if car_on:
        if io.input(IGN) == 1:
            io.output(IGN, 0) #Ignition and Accessory on
            io.output(ACC, 0)
        if get_fingerprint():
            io.output(ACC, 1) #Starter sequence
            time.sleep(.3)
            io.output(START, 0)
            time.sleep(.6)
            io.output(START, 1)
            time.sleep(.3)
            io.output(ACC, 0)
            while car_on:
                car_on = get_button() #Check for button off

        if io.input(BUTTON) == 1:
            io.output(IGN, 1) #Button Off = All Systems Off.
            io.output(ACC, 1)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.