Ya hemos visto como configurar una pantalla OLED de 128x64 en nuestra Raspberry Pi junto con la librería Adafruit.
Y como veía mi cluster Pi un poco "triste" decidí animarlo un poco con una pantalla OLED de tipo I2c y algunas animaciones programadas en Python que la hacen más "friendly".
Expresiones y dirección de la mirada
Podemos alternar entre las diferentes expresiones:
- Normal
- Contento
- Triste
- Sorpresa
- Dormido
También podemos dirigir la mirada en las siguientes direcciones:
- Izquierda
- Centro
- Derecha
def crear_ojos(expresion="normal", direccion_mirada="centro", estado_parpadeo=1.0):
"""
Ojos con sistema de parpadeo realista
estado_parpadeo: 1.0 = totalmente abierto, 0.0 = totalmente cerrado
"""
Para crear la animación de parpadeo:
def animar_parpadeo(expresion="normal", direccion_mirada="centro"):
"""Animación completa de parpadeo"""
Programa completo en python:
# Simulación de ojos con expresiones en OLED 128x64
import time
import random
import board
import adafruit_ssd1306
from PIL import Image, ImageDraw, ImageFont
# Use for I2C.
i2c = board.I2C() # uses board.SCL and board.SDA
try:
disp = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c, addr=0x3C)
print("\nAdafruit SSD1306 ok")
except Exception as errors:
print("\nError Adafruit SSD1306:",str(errors), "\nPlease check Raspi-config\n")
exit()
def crear_ojos(expresion="normal", direccion_mirada="centro", estado_parpadeo=1.0):
"""
Ojos con sistema de parpadeo realista
estado_parpadeo: 1.0 = totalmente abierto, 0.0 = totalmente cerrado
"""
# Crear imagen evitando la franja amarilla superior
img = Image.new('1', (128, 64), 0)
draw = ImageDraw.Draw(img)
# Posiciones fijas
centro_y = 40
ojo_izq_x = 45
ojo_der_x = 83
# Tamaño máximo reducido a 40
max_tam = 40
# Radio de redondeo
radio = 15
# Determinar tamaños según dirección de mirada
if direccion_mirada == "izquierda":
ancho_izq, alto_izq = max_tam, max_tam
ancho_der, alto_der = 30, 30
elif direccion_mirada == "derecha":
ancho_izq, alto_izq = 30, 30
ancho_der, alto_der = max_tam, max_tam
else: # centro
ancho_izq, alto_izq = 35, 40
ancho_der, alto_der = 35, 40
def dibujar_ojo(x, y, ancho, alto, radio, apertura=1.0):
"""Dibuja un ojo con sistema de parpadeo"""
if apertura >= 1.0:
# Ojo totalmente abierto
draw.rounded_rectangle([
(x - ancho//2, y - alto//2),
(x + ancho//2, y + alto//2)
], radius=radio, outline=1, fill=1)
elif apertura <= 0.0:
# Ojo totalmente cerrado (línea)
draw.line([
(x - ancho//2, y),
(x + ancho//2, y)
], fill=1, width=3)
else:
# Ojo parcialmente cerrado - calcular altura visible
alto_visible = int(alto * apertura)
if alto_visible < 2:
alto_visible = 2
# Dibujar el ojo recortado según la apertura
draw.rounded_rectangle([
(x - ancho//2, y - alto_visible//2),
(x + ancho//2, y + alto_visible//2)
], radius=min(radio, alto_visible//2), outline=1, fill=1)
# Aplicar expresiones (modifican la apertura base)
apertura_base = estado_parpadeo
if expresion == "normal":
apertura = apertura_base
elif expresion == "contento":
apertura = apertura_base * 0.7 # Ojos más cerrados
elif expresion == "triste":
apertura = apertura_base * 0.9 # Ojos casi normales pero caídos
elif expresion == "sorpresa":
apertura = min(apertura_base * 1.2, 1.0) # Ojos más abiertos
elif expresion == "dormido":
apertura = apertura_base * 0.3 # Ojos casi cerrados
# Dibujar ojos con la apertura calculada
dibujar_ojo(ojo_izq_x, centro_y, ancho_izq, alto_izq, radio, apertura)
dibujar_ojo(ojo_der_x, centro_y, ancho_der, alto_der, radio, apertura)
return img
def animar_parpadeo(expresion="normal", direccion_mirada="centro"):
"""Animación completa de parpadeo"""
frames = []
# Fases del parpadeo (apertura de 1.0 a 0.0 y vuelta)
fases = [1.0, 0.8, 0.5, 0.2, 0.0, 0.2, 0.5, 0.8, 1.0]
for apertura in fases:
frame = crear_ojos(expresion, direccion_mirada, apertura)
frames.append(frame)
return frames
# Bucle principal
if __name__ == "__main__":
expresiones = ["normal", "contento", "triste", "sorpresa", "dormido"]
direcciones = ["izquierda", "centro", "derecha"]
print("Mostrando expresiones sencillas...")
print("Presiona Ctrl+C para detener")
try:
while True:
for expresion in expresiones:
for direccion in direcciones:
print(f"Expresión: {expresion} dirección: {direccion}")
img = crear_ojos(expresion, direccion)
disp.image(img)
disp.show()
time.sleep(5)
# 30% de probabilidad de guiño entre animaciones
if random.random() < 0.2:
#lado_guiño = random.choice(["izquierdo", "derecho"])
print(f"¡papadeo {expresion}!")
frames_parpadeo = animar_parpadeo(expresion, direccion)
for frame in frames_parpadeo:
disp.image(frame)
disp.show()
except KeyboardInterrupt:
print("\nBucle detenido")
Es un programa que podemos ampliar con otras expresiones o incluso hacer llamadas desde otros programas por ejemplo conectandolo a una Raspi cam para simular que la mirada nos sigue.
Otro idea que se me ocurre es que las llamadas sean según diferentes eventos, como que despierte con el acceso por ssh o utilizar el sensor de temperatura para que nos "mire mal" si nuestra Raspberry Pi se pone lujuriosa.
Añadir programa al iniciar Raspberry PI
Lo ideal es que este programa se inicie al encender la Raspberry pi. Es un buen indicador para saber que la Raspberry Pi arranco sin problemas.
esto lo podemos hacer editando el crontab con el comando "crontab -e" (no hace falta sudo).
@reboot sleep 30 && python3 ~/Eyes_simulation/eyes_simulation.py > ~/Eyes_simulation/eyes.log 2>&1
Recuerda poner "@reboot sleep 30" para darle un tiempo prudente a la Raspberry para inicializar el puerto I2c.
Y siempre puedes ver si todo esta bien o hay algún fallo consultando el archivo que se genera en el inicio llamado "eyes.log".
Conclusión:
Es un programa sencillo que le dará a nuestra maquina un poco más de carisma (por si le faltaba un poco) y que deje de ser un puñado de lucecitas encima del escritorio.
Antes de montar el cluster con las 3 Raspberry Pi, la que máquina que usaba para estas cosas empezó a dar problemas con la tarjeta y lo pude detectar ya que no me miraba igual que siempre...
¿Le puedo poner nombre?
Aquí tienes otros enlaces de este blog relacionados con Raspberry Pi:




No hay comentarios :
Publicar un comentario