MattiMTB
Posts: 4
Joined: Fri Jun 28, 2019 3:14 pm

tkinter and GPIO, how to set up a physical input button

Fri Jun 28, 2019 4:01 pm

Hello to all the Raspberry Pi people out there!

I'm new to the forum and I only have a couple of months experience with the Raspberry Pi and the Python programming language.
The project I am working on is a little unusual.... it is a timing system for a dog sport called 'flyball'.

In a nutshell, flyball is a relay racing event where people race their dogs. They go over jumps, activate a trigger in a 'box' to get a ball and bring the ball back to their handler by running over the jumps again. If you would like more info it would be easier to google it or even better still, watch a video of a race on YouTube.
At competitions, there is an electronic timing system which uses beams running along the start/finish line. When the dogs run through these beams, the timer records the time they've done (it's like hitting the Lap button on a stopwatch).

Okay, I'll get to the problem that I need help with......
I have successfully written a Python3 script which simulates the timing system at an event. I've used tkinter to create a GUI. The program runs by clicking the mouse on a 'Start' button on the screen.
In addition to this, I'd like to run a press button on a breadboard which will also execute the start command. The problem is that the only examples I have come across for GPIO input require the use of a while loop.

This won't work for my program as the GUI won't appear when the while loop is running.
Has anybody reading this done a project where you have both a GUI computer screen AND a physical input device which can execute the same command?
Is there some way to use tk.bind to assign a command to a GPIO input, or something similar?

Even if you could point me in the right direction regarding online learning, reference material or tutorials it would be greatly appreciated.

Some additional info about my project so far.....
I have a 7 inch touch screen which I plan to install as part of the timing system. The mouse buttons WORK by pressing them with your finger on the touchscreen so you may not think an additional push button would be necessary, but touchscreens can be unpredictable at the best of times. Down the line, I'd like to incorporate a remote control to begin the start sequence as well.
I have a set of 'drag lights' on my GUI which light up as a countdown to go. I also have LEDs on the breadboard which do exactly the same thing. Because they are a GPIO output command this was easy.

I haven't got to the 'laser tripwire' part of the project yet, but I'll cross that bridge when (or if I ever) get to it.

User avatar
MrYsLab
Posts: 351
Joined: Mon Dec 15, 2014 7:14 pm
Location: Noo Joysey, USA

Re: tkinter and GPIO, how to set up a physical input button

Fri Jun 28, 2019 10:16 pm

Below is a small tkinter program that converts feet to meters. It also includes code to set a pin as a GPIO input (connected to a pushbutton) and another connected to an LED. Anytime the pushbutton is pressed it will light the LED and when it is released, it will turn off the LED.

It uses the pigpio library. To run the program, you may need to first start the pigpio daemon with the following command:

Code: Select all

sudo pigpiod
The code makes use of the pigpio callback method http://abyz.me.uk/rpi/pigpio/python.html#callback

Code: Select all

from tkinter import *
from tkinter import ttk
import pigpio

class TkAndGPIO:
    def __init__(self):
        root = Tk()
        root.title("Feet to Meters")

        mainframe = ttk.Frame(root, padding="3 3 12 12")
        mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
        root.columnconfigure(0, weight=1)
        root.rowconfigure(0, weight=1)

        self.feet = StringVar()
        self.meters = StringVar()

        feet_entry = ttk.Entry(mainframe, width=7, textvariable=self.feet)
        feet_entry.grid(column=2, row=1, sticky=(W, E))

        ttk.Label(mainframe, textvariable=self.meters).grid(column=2, row=2, sticky=(W, E))
        ttk.Button(mainframe, text="Calculate", command=self.calculate).grid(column=3, row=3, sticky=W)

        ttk.Label(mainframe, text="feet").grid(column=3, row=1, sticky=W)
        ttk.Label(mainframe, text="is equivalent to").grid(column=1, row=2, sticky=E)
        ttk.Label(mainframe, text="meters").grid(column=3, row=2, sticky=W)

        for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5)

        feet_entry.focus()
        root.bind('<Return>', self.calculate)

        # instantiate pigpio
        self.pi = pigpio.pi()

        # set bcm pin 19 as an input
        self.pi.set_mode( 19, pigpio.INPUT)
        # assign a callback to the pin
        self.pi.callback(19, pigpio.EITHER_EDGE, self.hdw_button_pressed)

        # set mode for pin connected to LED
        self.pi.set_mode(5, pigpio.OUTPUT)

        root.mainloop()

    def calculate(self, *args):
        try:
            value = float(self.feet.get())
            self.meters.set((0.3048 * value * 10000.0 + 0.5)/10000.0)
        except ValueError:
            pass

    def hdw_button_pressed(self, gpio, level, tick):
        self.pi.write(5, level)


# instantiate the class
TkAndGPIO()
BTW, I shamelessly borrowed the tkinter code from: https://tkdocs.com/tutorial/firstexample.html

MattiMTB
Posts: 4
Joined: Fri Jun 28, 2019 3:14 pm

Re: tkinter and GPIO, how to set up a physical input button

Sun Jun 30, 2019 12:13 pm

Thank you MrY!

I'll delve deeper into this pigipod module. Hopefully I'll be able to adapt it to my program.
I just finished a project from the book titled "Adventures in Raspberry Pi 2nd Edition", where the final project in the book is to turn your pi into a MP3 player.... controlled by 4 buttons on the breadboard.

I got it working, and it was great to do. The only problem is this program uses the infamous while loop to actively detect inputs.

Another theory I have is that I could "thread" the while loop which is waiting for a button press. All it would need is a boolean value to terminate the loop once the button (or the start icon on the screen) is pressed.

User avatar
MrYsLab
Posts: 351
Joined: Mon Dec 15, 2014 7:14 pm
Location: Noo Joysey, USA

Re: tkinter and GPIO, how to set up a physical input button

Sun Jun 30, 2019 2:49 pm

I believe the book you are using, uses the RPi.GPIO library. If I am correct then, RPi.GPIO has a very similar construct to pigpio and instead of callback, they use different terminology and call it interrupt. You may read about it here - just scroll down the page to find the section on interrupts:
https://sourceforge.net/p/raspberry-gpi ... ki/Inputs/

There is nothing wrong with using threading to do what you wish, and I applaud you for making the effort to add more tools to your tool chest.
Google "python threading tutorial" and you should find many fine articles that will help explain threading.

If you go the threading route, you will see that adds more code than the callback/interrupt route.

Where threading would be a good choice to use is if your application needed to communicate with either a serially connected device (arduino, keyboard, etc,) or the need to support socket type I/O - Bluetooth, TCP/IP etc.

Good luck, and if you need help, the community is here for you.

MattiMTB
Posts: 4
Joined: Fri Jun 28, 2019 3:14 pm

Re: tkinter and GPIO, how to set up a physical input button

Sun Jul 07, 2019 1:03 pm

Hey MrY,

I came up with a solution to my problem but it was something a little different.
I noticed that there are really only 2 ways a user can input into a tkinter app........ with a mouse click on a button OR with a press of a keyboard button.

The Adventures in Raspberry Pi book has a project where you use a "Marshmallow" as an input button (I found marshmallows are somewhat sticky to work with, a sponge works just as well). Anyhow, this project uses a module called PyUserInput which allows you to assign a GPIO input to a keyboard key of your choice.

So for my physical start button I wrote a class with a while loop which has a True/False flag used to activate/deactivate it. When the timer is not running, the while loop is active 'looking' for an input from the physical button OR from a press of the mouse button (the keyboard letter works as well). When "START" has been pressed, the loop is terminated.
When the timer has finished it's job, the flag for the while loop is set to True enabling it to wait for a button press again!

This while loop is threaded so it doesn't affect the overall performance of the timer!

The next challenge is the laser tripwire. I have successfully followed the tutorial on the Pi website to run a tripwire using the parts listed. It is working okay, and thanks to the PyUserInput, I can get a trip in the laser to record a lap time on the screen......... now to the current problem.

The response time for the timer is a little slow...... I find myself having to block the laser for a fraction of a second longer than I should need to in order for a lap time to record. My theory is that it is due to the 1uF capacitor.
I think it takes too long to discharge the capacitor, so therefore if you run through the beam too quickly the capacitor will not discharge quickly enough to allow the ZERO condition to be true. I even tried using a condition where the light value is less than 0.88 to trigger the lap function (I found running a small program with a print value loop, the sensor value tended to be 0.94 give or take a little).

Still has the slight delay. Would using a smaller capacitor, say a 0.1uF ceramic capacitor improve the reaction time?
Would it be possible to use a capacitor which is a nano-farad or even a pico-farad to improve the reaction time?

Should I consider ditching the light dependent resistor and look into using a photo diode or photo transistor instead?
If so, what parts do I need? Specific photo diode, resistors to prevent frying the Pi? Do you know where I can go to find out how to use a photo diode or even a photo transistor instead?

Any help, advice or references to tutorials which would help me would be greatly appreciated. I am getting close to finishing the prototype of this timer now........ If I can get the tripwire reaction fast enough to use I'll be in business!

User avatar
MrYsLab
Posts: 351
Joined: Mon Dec 15, 2014 7:14 pm
Location: Noo Joysey, USA

Re: tkinter and GPIO, how to set up a physical input button

Sun Jul 07, 2019 2:40 pm

Wow! You are doing a lot of research. I don't have a lot of experience in this realm, but found a posting that may be of some help:
https://www.raspberrypi.org/forums/view ... p?t=205523

You may also want to look at something like this sensor: https://www.adafruit.com/product/2168

ghp
Posts: 1392
Joined: Wed Jun 12, 2013 12:41 pm
Location: Stuttgart Germany
Contact: Website

Re: tkinter and GPIO, how to set up a physical input button

Sun Jul 07, 2019 3:22 pm

If you already own a LDR, you could use a comparator like LM293 to do a faster conversion. LDR react in 2 to 50ms to light changes (these are times found in data sheets).
Use a 20k resistor in line with LDR to form a voltage divider, and a trim-poti with 10k to build an adjustable reference voltage. Something like described here https://electronut.in/ambient-light-sen ... omparator/

Or you could use a digital comparator ads1115 with its ALERT output, but needing more software.

MattiMTB
Posts: 4
Joined: Fri Jun 28, 2019 3:14 pm

Re: tkinter and GPIO, how to set up a physical input button

Tue Jul 09, 2019 4:24 am

Thank you ghp, I'll add this to my list of possibilities.

I've been posting on a forum at one of the electronics stores I've done business with "Core Electronics", and they've have offered some great advice. Some of it is more simple to start off with, some of it is more complex and I may need to get into something like that later on.

One particularly interesting reply I got was about a built-in ADC on Arduino boards which the Pi does not have. I assume ADC means 'Analogue-Digital-Converter', but I could be wrong...... please excuse my ignorance.

I'll probably start off with experimenting with the most simple solutions first, and if they don't work out then I will need to dive deeper so this post you have shared with me could be very useful. Thank you again! :D

BeeryChisels
Posts: 18
Joined: Sat Apr 13, 2013 7:00 pm

Re: tkinter and GPIO, how to set up a physical input button

Thu Jul 25, 2019 11:45 pm

Hi MattiMTB, its good to hear of somebody experimenting with real hardware these days!

The common Cadmium Sulphide LDR's are very slow and non-linear - ok for photographic exposure meters and things where a bit of damping can be beneficial. For something faster I'd be tempted to go for infra-red transmitters and receivers, as used in TV remote controllers etc.

I don't know what distance you would need between the transmitter and receiver, you'd have to check the spec of a few devices to see if they are suitable. Here's a link that might work...

https://uk.rs-online.com/web/c/displays ... receivers/

You may have to copy and paste it into your browser if it won't work by clicking a mouse button. Other suppliers of infra-red devices are available.

Some of the ones shown have the transmitter and receiver in the same unit, these need a reflector so that the beam can leave the transmitter and get reflected back again into the receiver. It thus has to cover twice the distance, but the mechanical set-up is much easier. You can get reflectors that will work when not at exactly 90 degrees to the intended infra-red path. They look a bit like the reflectors that are fitted to pedal cycles - lots of little inverted pyramids - except they are white and not red.

Beam-breakers of this sort are common in industrial processes but tend to be extremely expensive!

Have fun,
Electronic Biker

Return to “Python”