gpiod and tkinter?

I have been working on a tk script in python3 for handling GPIO with gpiod and sys along with time.

Has anyone attempted Python scripting with tkinter for gpiod?

I am using the beagley-ai and it seems every route I take with the driver in question is dictating nothing. My commands seem to not work. I can make the motor move in other scripts without tkinter but not with it so far.

It seems most of the internet is filled with ways of using it but with BCM or RPi libs. (something that does not help currently with the beagley-ai. Oh! Here is the source in case you see error for concern.

#!/usr/bin/python3

import tkinter as tk
import gpiod
import sys

from time import sleep

# --- GPIO Setup ---
# Define the chip and line number for your Motor Driver

CHIP_NAME1 = 'gpiochip1'
LED_LINE_OFFSET1 = 38
CHIP_NAME2 = 'gpiochip2'
LED_LINE_OFFSET2 = 14

try:
    chip1 = gpiod.Chip(CHIP_NAME1)
    left_line1 = chip1.get_line(LED_LINE_OFFSET1)
    left_line1.request(consumer="Left_Control", type=gpiod.LINE_REQ_DIR_OUT)

    chip2 = gpiod.Chip(CHIP_NAME2)
    right_line2 = chip2.get_line(LED_LINE_OFFSET2)
    right_line2.request(consumer="Right_Control", type=gpiod.LINE_REQ_DIR_OUT)

except gpiod.FileNotFoundError:
    print(f"Error: GPIO chip '{CHIP_NAME1}' '{CHIP_NAME2}' not found. Ensure gpiod is installed and you are running on a compatible device.")
    sys.exit(1)
except Exception as e:
    print(f"Error initializing GPIO: {e}")
    sys.exit(1)

# --- Tkinter GUI Setup ---
def toggle_motor():
    val1 = left_line1.get_value()
    val2 = right_line2.get_value()
    new_val1 = 1 if val1 == 0 else 0
    left_line1.set_value(val1)
    right_line2.set_value(val2)
    if val1 == 1:
        left_line1.set_value(0) # Turn Left on
        right_line2.set_value(1)
        toggle_button.config(text="Turn Motor Left")
    else:
        left_line1.set_value(1) # Turn Right on
        right_line2.set_value(1)
        toggle_button.config(text="Turn Motor Right")

def cleanup_gpio():
    left_line1.release()
    right_line2.release()
    chip1.close()
    chip2.close()
    root.destroy()

root = tk.Tk()
root.title("Motor Control")

toggle_button = tk.Button(root, text="Turn Motor Left", command=toggle_motor)
toggle_button.pack(pady=20)

exit_button = tk.Button(root, text="Exit", command=cleanup_gpio)
exit_button.pack(pady=10)

# Ensure GPIO is cleaned up when the window is closed
root.protocol("WM_DELETE_WINDOW", cleanup_gpio)

root.mainloop()

That is as far as I have gotten and it is filthy with bugs. I understand. I am building around it still…

Yes,

But, you need to have control over the gpio devices verified. I use tkinter for HMI builds and it works fine on all the boards we have tested it on. What is the simplest and most reliable is to ditch the gpio header stuff and use a coprocessor that is deterministic and simple to configure. The overlay non-sense is not very practical for many reasons. Use uart to uart if that is fast enough or ethernet to the device. Much more robust, let the bigger board do the servicing of the hmi and networking/whatever else what it does best and let the coprocessor do what it does best.

1 Like

So…

Without deterministic configurations like with the PRU or other coprocessors available on the chips made usable by beagleboard.org, would it be possible to use tkinter for “slow” use cases?

For instance, I have a HDMI display and it connects to the beagley-ai but I cannot get the LED or driver to recognize my button usage from tkinter. I have used GPIO peripherals access before today. So, I sort of understand what is needed.

But…I do not know how to incorporate the display and GPIO with tkinter, to say, light a LED.

If it is possible without coprocessors, please let me know. I keep finding RPi stuff online with the websites saying it works.

I try and then it does not work and I have no background on why it is not working.

I update the software to work with specific boards and yet I cannot illuminate a LED via the HDMI display and tkinter. I know it is not magic the way it works… I just figured once I get the source calling a GPIO pin that is wired done correctly, I could then apply the HDMI display for a use case.

Seth

P.S. I saw in the docs.beagleboard.org pages online, using the GPIO for the BeagleY-AI is a bit different compared to plain, ole gpiod. There is a way to use actual name recognition instead of what gpiod states is the location and naming scheme.

Like so:

gpio14 = gpiod.find_line('GPIO14')
gpio14.request(consumer='beagle', type=gpiod.LINE_REQ_DIR_OUT, default_val=0)

Send guidance and/or ideas while I update the source code and I will return service. There has to be a way to handle it that I am unaware of currently.

Blah…

Wrong pin. it works!

Seth

# For anyone testing the capabilities of the BeagleY-AI

#!/usr/bin/python3

import tkinter as tk
import gpiod
import sys

from time import sleep

try:
    gpio8 = gpiod.find_line("GPIO14")
    gpio8.request(consumer="Beagsss", type=gpiod.LINE_REQ_DIR_OUT, default_val=0)

except gpiod.FileNotFoundError:
    print(f"Error: GPIO chip '{CHIP_NAME1}' '{CHIP_NAME2}' not found. Ensure gpiod is installed and you are running on a compatible device.")
    sys.exit(1)
except Exception as e:
    print(f"Error initializing GPIO: {e}")
    sys.exit(1)

# --- Tkinter GUI Setup ---
def LED():
    gpio8.get_value()
    try:
        for i in range(1, 10, 1):
            sleep(0.4)

            gpio8.set_value(0)
            sleep(2)
            gpio8.set_value(1)
            sleep(2)
    except KeyboardInterrupt:
        gpio8.set_value(0)
        print ('Yeppers...')

def LED_OFF():
    gpio8.set_value(0)
    root.destroy()

root = tk.Tk()
root.title("LED ACTS")

toggle_button = tk.Button(root, text="LED ON/OFF", command=LED)
toggle_button.pack(pady=20)

exit_button = tk.Button(root, text="Exit", command=LED_OFF)
exit_button.pack(pady=10)

# Ensure GPIO is cleaned up when the window is closed
root.protocol("WM_DELETE_WINDOW", LED_OFF)

root.mainloop()

Update

Two GPIO pins needing to be toggled via Python3 source code is not so easy when attempting to promote bidirectional movement on a driver with a set of commands within tkinter.

I know…I have been trying for days. Off to the docs.

I think calling my latest code does nothing since it abruptly ends with errors while the tkinter GUI runs in the foreground. I will keep trying, i.e. as I have no better options for promoting things for now!

Yes, your code would have to introduce some latching or buffering if your gpio input is short duration.

1 Like

I changed the file many times. Currently, no working motor driver with tkinter but I am working towards that goal with slow motion.

Hey @foxsquirrel , do you think that a RT kernel may provide lower latency?

I always wondered about it since Linux CNC works with only RT kernels. There must be a catch somewhere that I am missing or is the kernel P or RT just for patches needing to be made?

I mean…yes. Writing drivers is good and fun but patching them is the easier part of the two if they indeed work. Anyway, just day-skipping over here. I need to reconcile on more research still.

It does make the application more deterministic. However the short fall is you will bottleneck and have negative performance events due to that if you have other processes running. If you are running a board like BBB headless, very mission specific project and coded for that than yes, it would help.

Most of this depends on your end game, if you are controlling a plasma cutter, then any thing flies. It all depends, keep in mind Okuma OSP300 has been running a windows OS…The industry fawns over Okuma.

Start simple and test, if the outliers are acceptable to the dynamics of your system don’t waste time trying to get an RT kernel patched up.

Nope, no plasma cutter here (for now).

But for now, I am basically trying to make the driver react quickly to my commands without the PRU or other coprocessors available on the boards.

For instance, I can make the motor(s) turn via driver(s) just with two GPIO pins but…

  1. Would a RT kernel work better than just Dynamic for making the driver understand to move the motor(s) quicker?
  2. And, if that answer is yes, would I need to write patches to the kernel to handle GPIO in a more timely fashion?

I just have not found the correct data yet and I am attempting things from scratch at times.

Even with the driver and/or source code for the Teknic.com SC Servos, I am still moving slow in their C++ driver(s) and builds.

It seems the data is there for some people who have already learned the correct books to attain but I am slow to the game. I am still learning how to incorporate the GPIO on the beagleboard.org boards along with speed and accuracy to do what I command of them.

Now, does anyone know of any good books or should I look to the PRU and/or other processos to handle such tasks?

I know what you say. Some processors are made for certain tasks like the PRUSS for handling sub-200MHz of repetition. I will try to learn more about the PRUSS in general but without some real background in the PRUSS and them being unavailable on specific boards, I was thinking that porting a M4F or R5F set of cores would be a bit leveraging on the builds.

Seth

P.S. For instance, without UART to send commands, how else would I send commands to the coprocessors and make the major processor, AM67A in this case, understand what to do and when…?

I mean…there is a Linux RT kernel I use with Linux CNC and the board that I have acquired but it is not so Open Source (I think). I will need to research more on it. 7I96S from Mesa Cards is what I purchased years ago. I have yet to port it to the machines for use cases.

Anyway, thank you for your words and taking time out to handle my ideas. Off to try again…

Okay…

I found a M4 chip with peripheral access from TI. I am going to try it.

Seth