14. Interface and application programming

Goals

Individual assignment:

  • [x] Week an application that interfaces a user with an input &/or output device that you made

Group assignment:

  • [x] Compare as many tool options as possible

Tools Used

TLDR; Nice images


Group Project

For this weeks group we compared different approaches to Interface and application programming

Link to group project

Summary

I used Tkinter for python and further developed my final project.

Individual Project

Back to top

1. Making a custom HID

For this assignment I will be sending inputs over USB serial to a desktop application. I will be implementing a lot of the code I have written in previous assignments, but now rather than using a HID library on the device I will be using a desktop application to receive the inputs and convert them into key and mouse events.

1.0 Starting Point

Back to top

As a starting point I wanted to recreate my blender view toggle from week 10.

But before I got there I wanted to just send a button press over USB serial to a desktop application.

See code below:

Firmware
from machine import Pin
import time
import sys

button = Pin(0, Pin.IN, Pin.PULL_UP)

previous_state = button.value()

while True:
    current_state = button.value()
    if current_state is not previous_state:
        if current_state ==0:
            sys.stdout.write("Pressed\n")  # Send message over USB serial
        else:
            sys.stdout.write("Released\n")  # Send message over USB serial
        previous_state = current_state
    time.sleep(0.01)

The send the value “Pressed” or “Released” depending on the button state.

desktop
import serial
import time

try:
    ser = serial.Serial("/dev/tty.usbmodem21201", 115200, timeout=1)  # Use correct port
    print("Serial port opened.")
except serial.SerialException as e:
    print("Error opening serial port:", e)
    exit(1)

while True:
    try:
        if ser.in_waiting:
            line = ser.readline().decode("utf-8", errors="ignore").strip()
            print("Received:", line)
    except serial.SerialException as e:
        print("Serial communication error:", e)
        break
    except Exception as e:
        print("Unexpected error:", e)
        break
    time.sleep(0.01)

This opens up a serial connection on the same port as the device and listens for incoming messages. When it gets a message it prints “Recieved: ” followed by the message

1.1 Adding a GUI with Tkinter

Back to top

Now that we can send data over serial lets add a GUI for the desktop app so we have a more user friendly interface.

The code is as follows;

import tkinter as tk
import serial
import threading

def read_serial():
    while True:
        if ser.in_waiting:
            line = ser.readline().decode().strip()
            if line == "Pressed":
                label.config(text="Button Pressed", fg="green")
            elif line == "Released":
                label.config(text="Button Released", fg="black")

ser = serial.Serial("/dev/tty.usbmodem21201", 115200)

root = tk.Tk()
root.title("Macro Pad GUI")
label = tk.Label(root, text="Waiting for input...", font=("Helvetica", 16))
label.pack(pady=20)

thread = threading.Thread(target=read_serial, daemon=True)
thread.start()

root.mainloop()

1.2 Install guide

Back to top

The tools to use the above are installed using pip in your local environment;

pip install tkinter pip install serial pip install threading

2 bonus Making a new board for the Pico

Back to top

Up until now I have been using my RP2040 based Fab-Xiao for weekly projects and testing.

For my final project I will need to step up to a Raspberry Pi Pico 2 W to add more pins and Blueooth support.

So now I need a new board to develop my code on for my final project as working with the breadboards has been very frustrating and time consuming.

I downloaded a Pico V2 footprint from the link above

Downloaded the symbols and footprint for my encoders from Digikey

And imported my OLED screen and linear pot symbols from previous weeks

Pushed the design to the board design workspace

rearranged the parts until autoroute completed successfully

And tweaked the layout until I was happy with how everything looked and used export->image to get my files ready from CAM.

The sittings I used were:
[x] monochrome images
1000 dpi
*.png file format
Area: Full

There were some elements that were included in some of my downloaded footprint’s that I could not hide with layers in Fusion 360 so took the

Pushed the file to a 3D pcb and designed a quick housing for it.

Handled my CAM in mods, I am still finding the 60 deg vbit is working for me.

And got to cutting!

Traces part way complete

And started soldering parts. One of the more interesting things on the board is the way the through hole 4 pin header is mounted.

The pins are removed from the header, soldered in place and then the plastic header is then placed down over the top.

I then realised that I was using a double sided board… this meant that all my pins on the picos headers were shorting on the underside of the board.

So I recut the board and removed some of the copper on the underside with a dremmel.

NOTE: only do this with FR1 board and still make sure to use eye and dust protection.

And we are up and running with the code from earlier!


In Summary

This week the I kept the brief for the week pretty simple as I spent a lot of time rewriting a lot of my scrips for handling the logic.

The goal for my final project will be a mix of a desktop based GUI program that is reading serial from the device so this was a critical step towards that.

Things I would do differently next time

The reason I made a new board this week was due to frustration with bread boarding but I know that this was not a optimal use of time.

It would have been ideal if I had already had a working prototype and done more ambitious things with tkinter.

For me the ideal thing would have been to have made a test file where I manipulate a cube using the device. Spinning, zooming etc.


See below link to to files created this week:

Week 14 Files


End

Back to top