Week 14 Interface and Application Programming

This is the group assignment Website Fab Lab Puebla

  • Group assignment:
    • Compare as many tool options as possible.
    • Document your work on the group work page and reflect on your individual page what you learned.
  • Individual assignment:
    • Write an application that interfaces a user with an input and/or output device(s) on a board that you made.
UI Framework Comparison
1. Tkinter (Python)

Description: Tkinter is Python’s built-in library for creating desktop GUIs.

Advantages:

  • Easy to learn and use.
  • Lightweight and cross-platform.
  • Ideal for rapid prototyping.

Disadvantages:

  • Limited aesthetic appeal.
  • Not ideal for large or complex applications.
2. PyQt or PySide (Python)

Description: Python wrappers for the Qt framework offering sophisticated GUI design capabilities.

Advantages:

  • Extensive widget library.
  • Modern and polished UIs.
  • Highly scalable.

Disadvantages:

  • Steeper learning curve.
  • Resource intensive.
3. Qt (C++)

Description: A powerful C++ framework for developing advanced, cross-platform applications.

Advantages:

  • High performance and customizable.
  • Professional-grade UIs.
  • Broad platform support.

Disadvantages:

  • Steep learning curve.
  • Slower development speed.
Comparison Summary Table
Feature Tkinter PyQt/PySide Qt (C++)
Ease of Use Easy Medium Hard
Aesthetic Flexibility Basic High Very High
Cross-Platform Support Yes Yes Yes
Target Platforms Desktop Desktop Desktop & Mobile
Resource Usage Low Medium Low
Development Speed Fast Medium Slower
Best For Simple GUIs Professional GUIs High-performance GUIs

For this week assignment i decided yo use Tkinter, i saw one friend that did his week with this tool of phyton and i really like the simplicity

I watch this video on YouTube to understand some basic things about this software Tkinter i had to take more time that i expected, this assignment was really out of my knowledge area, so i had to dedicate more hours to understand how it works programming and i saw a several videos on YT of this guy. If you are new in programming interfaces on Tkinter take a look.

Learning Tkinter - Step-by-Step Guide
Step 1: Learn Basic Tkinter Elements

I started by watching YouTube tutorials to understand Tkinter’s functionality. Here's what I learned:

  • Create a Button: Add a button to your interface.
  • Create a Label: Use labels to display text or other information.
  • Input and Output: Send data from the interface to the terminal by clicking a button and input data directly into the interface.

These foundational skills will be useful for building more complex applications.

Step 2: Connect the Interface to Hardware (OLED Screen)

After learning the basics, I decided to connect the interface to an OLED screen (SCD-306). My goal was to:

  1. Allow the user to select an image from their file library through the interface.
  2. Display the selected image on the OLED screen.

This builds on my previous work where I used the OLED screen to display sensor data.

Step 3: Install Python and Tkinter

Before you begin, ensure you have Python and Tkinter installed on your system.

Installing Python:
  1. Download Python: Go to the official Python website and download the latest version.
  2. Install Python: Follow the installation instructions and make sure to check the box for adding Python to your system's PATH.
>Within the code, add comments to explain each function’s purpose. This practice will help you and others understand how each part of the program works.

Note: By following these steps, you'll be equipped to create user-friendly interfaces for future projects.

PIP INSTALL PILLOW

The command pip install Pillow is used to install Pillow, a Python library for working with images. Pillow is an improved and actively maintained version of the old PIL (Python Imaging Library).

I made a few trials following the tutorial and i'll show you below

Here i made a button to printing a message in the terminal

This is the code to run the interface

CODE
                            
import tkinter as tk

app = tk.Tk()
palabra = tk.StringVar(app)
entrada = tk.StringVar(app)
#dimensions height x width 
app.geometry("300x540")
#TO CHANGE THE TITLE OF THE WINDOW 
tk.Wm.wm_title(app, "hello roy")
tk.Button(
    app,
    text="click me!",
    font=("Courier",14),
    bg="#00a8e8",
    fg="white",
    command=lambda: print("WEEK INTERFACES"+ entrada.get()),

).pack(
    fill=tk.BOTH,
    expand=True,
)
tk.Entry(

    fg="white",
    bg="black",
    justify="center",
    textvariable= entrada
).pack(
    fill=tk.BOTH,
    expand=True,
)
app.mainloop()
                            
                          

Video

This week, I focused on creating a Tkinter interface that can load an image from my local drive and send the image data to an LCD connected via Arduino IDE. The LCD receives the data from the interface and displays the image.

Interface code
Image Processing and Arduino Communication
1. Image Upload

Function upload_image():

  • The user selects an image from their system using a dialog box (filedialog.askopenfilename).
  • The uploaded image is resized to 128x64 pixels using img.resize((128, 64)). This is because Arduino typically works with small displays like OLED screens.
  • It is converted to a black-and-white format with convert("1"), meaning each pixel will be 0 (black) or 1 (white).
2. Image Processing

The converted image is transformed into a list of pixels with list(img_resized.getdata()).

This list is reorganized into a 128x64 pixel matrix (pixel_matrix), representing each row of the image as a list of values.

3. Preview

An enlarged version of the image (img_resized.resize((256, 128))) is generated to display it in the graphical interface on the preview_panel.

4. Sending to Arduino

Function send_to_arduino(pixel_matrix):

  • For each row of the pixel matrix (pixel_matrix), a bit string (row_data) is generated, where each pixel is converted to a 1 or a 0 depending on its value (black = 1, white = 0).
  • This bit string is sent to the Arduino via the serial port using arduino.write.
  • A small delay (time.sleep(0.1)) is added to avoid overloading the communication channel.
CODE OF Tkinter
 
                                
import tkinter as tk
from tkinter import filedialog, ttk
from PIL import Image, ImageTk
import serial
import time

# Configurar conexión serial con Arduino
arduino = serial.Serial(port='COM3', baudrate=9600, timeout=1)  # Cambia 'COM3' por tu puerto
time.sleep(2)  # Espera a que Arduino se inicialice

def upload_image():
    filepath = filedialog.askopenfilename(filetypes=[("Image Files", "*.png;*.jpg;*.jpeg;*.bmp")])
    if filepath:
        img_label.config(text=f"File uploaded: {filepath.split('/')[-1]}")  # Mostrar nombre del archivo
        img = Image.open(filepath)
        img_resized = img.resize((128, 64)).convert("1")  # Redimensionar y convertir a blanco y negro
        pixel_data = list(img_resized.getdata())
        pixel_matrix = [pixel_data[i:i+128] for i in range(0, len(pixel_data), 128)]
        
        # Mostrar la imagen en el panel de previsualización
        preview_img = ImageTk.PhotoImage(img_resized.resize((256, 128)))  # Escalar para mejor visualización
        preview_panel.config(image=preview_img)
        preview_panel.image = preview_img

        send_to_arduino(pixel_matrix)

def send_to_arduino(pixel_matrix):
    for row in pixel_matrix:
        row_data = ''.join(['1' if pixel == 0 else '0' for pixel in row])
        arduino.write((row_data + '\n').encode())
        time.sleep(0.1)  # Pequeña pausa para evitar sobrecarga
    status_label.config(text="Image sent ", foreground="green")

# Crear la interfaz gráfica
app = tk.Tk()
app.title("Week 14: Interface and Application Programming")
app.geometry("500x350")
app.resizable(False, False)

# Título
title_label = tk.Label(app, text="Fab Academy Rodrigo", font=("Arial", 12, "bold"))
title_label.pack(pady=10)

# Marco para contener los elementos
frame = ttk.Frame(app, padding=10)
frame.pack(fill=tk.BOTH, expand=True)

# Botón para cargar la imagen
boton = ttk.Button(frame, text="Upload Image", command=upload_image)
boton.pack(pady=5)

# Label para mostrar el archivo cargado
img_label = tk.Label(frame, text="nothing uploaded yet", font=("Arial", 10), foreground="blue")
img_label.pack(pady=5)

# Panel de previsualización de la imagen
preview_panel = tk.Label(frame, text="preview", bg="black", width=32, height=16)
preview_panel.pack(pady=10)

# Label para el estado de la operación
status_label = tk.Label(frame, text="", font=("Arial", 10))
status_label.pack(pady=5)

app.mainloop()

                                
                            
CODE of ARDUINO which receive data and show it in LCD

The Python interface sends image data row by row via serial communication. Each row is 128 characters long, representing the pixels of the OLED screen:

  • '1': White pixel
  • '0': Black pixel

The Arduino reads each row and updates the corresponding pixels on the OLED screen.

2. Key Arduino Functions
  • Serial.begin(9600): Initializes serial communication at 9600 baud.
  • Serial.readStringUntil('\n'): Reads a row of data until a newline character is received.
  • display.drawPixel(x, y, color): Draws a pixel at position (x, y) with the specified color.
  • display.display(): Updates the OLED to show the drawn pixels.
3. Data Processing Loop

The Arduino processes data as follows:

  1. Wait for data from the serial connection.
  2. Read a row (128 characters).
  3. Draw each character as a pixel on the OLED.
  4. Repeat for all rows (64 rows for a 128x64 screen).
  5. Once all rows are processed, update the display to show the complete image.
CODE for Arduino
 
                                
#include Wire.h
#include Adafruit_GFX.h
#include Adafruit_SSD1306.h

// Definición de ancho y alto de la pantalla
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

#define OLED_RESET    -1 // Reset pin # (o -1 si no se usa)
#define SCREEN_ADDRESS 0x3C // Dirección I2C estándar

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
  Serial.begin(9600);  // Inicializa comunicación serial con PC
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("Error: No se pudo inicializar la pantalla OLED"));
    for (;;);  // Detener si falla la inicialización de la pantalla
  }

  // Mostrar el mensaje inicial
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 10);  // Posición vertical ajustada
  display.println(F("Hola chiva hermano,"));
  display.setCursor(0, 20);  // Siguiente línea
  display.println(F("sube tu imagen:"));
  display.display();  // Mostrar el mensaje
  Serial.println("Esperando imagen...");
}

void loop() {
  static int y = 0;  // Línea actual en la pantalla OLED

  if (Serial.available() > 0) {
    String row = Serial.readStringUntil('\n');  // Leer una fila completa hasta un salto de línea

    if (row.length() == SCREEN_WIDTH) {  // Verificar que la fila recibida tenga exactamente 128 caracteres
      for (int x = 0; x < SCREEN_WIDTH; x++) {
        if (row[x] == '1') {
          display.drawPixel(x, y, SSD1306_WHITE);  // Dibujar píxel blanco
        } else {
          display.drawPixel(x, y, SSD1306_BLACK);  // Dibujar píxel negro
        }
      }
      y++;  // Avanzar a la siguiente fila
    } else {
      Serial.println("Error: Fila con longitud incorrecta.");
    }

    if (y >= SCREEN_HEIGHT) {  // Si se recibieron todas las filas
      display.display();  // Mostrar la imagen completa en la pantalla
      Serial.println("Imagen completa mostrada.");
      y = 0;  // Reiniciar para una nueva imagen
      display.clearDisplay();  // Limpiar la pantalla para la siguiente imagen
    }
  }
}
                                
                            

Video of the FINAL results

Video 2

Files
  • Codes_ino
  • Codes_phyton