Tamagotchi – Grupo 10

Introducción
Este proyecto consiste en un Tamagotchi electrónico interactivo, un sistema empotrado que permite al usuario cuidar de una mascota virtual a través de interacciones físicas y retroalimentación visual y sonora.
El sistema simula tres necesidades básicas de la mascota: amor, comida y sueño, mostrando su estado en una pantalla LCD 16×2 y alertando al usuario mediante LEDs y un buzzer. Además, la mascota se representa mediante un sprite animado que se desplaza horizontalmente en la pantalla, ofreciendo una interfaz visual intuitiva.
Materiales y coste teórico
A continuación se muestra una tabla con el presupuesto aproximado, pese a que se ha llevado a cabo únicamente con componentes presentes en la caja proporcionada en la asignatura o propios y, por ende, el coste real ha sido nulo. Los precios son orientativos, ya que pueden variar en función de la tienda región.
| Componente | Precio (€) |
| Placa Elegoo Uno R3 | 6,00 |
| Protoboard de 840 puntos | 3,29 |
| Pantalla LCD 16×2 | 3,95 |
| LEDs x3 | 0,36 |
| Buzzer pasivo | 0,90 |
| Resistencias x5 (220 Ohmios y 2k Ohmios) | 0,50 |
| Pulsadores x3 | 1,20 |
| Cables jumper macho-macho x28 | 2,80 |
| Cable de alimentación | 1,50 |
| Total | 20,50 |
Diseño hardware
El Tamagotchi funciona con Arduino Uno y utiliza lo siguiente:
- Pantalla LCD 16×2 para mostrar el estado de la mascota.
- LEDs para alertas visuales (uno para cada necesidad: amor, comida y sueño).
- Buzzer para alertas sonoras.
- Botones para restaurar cada necesidad.
- Powerbank para alimentación portátil.
El montaje se hizo sobre una protoboard de 840 puntos para poder distrubuir los distintos componentes de manera óptima y amigable con el usuario.

En la imagen anterior hay demasiados cables superpuestos, por lo que, para mayor claridad, también se incluye el diagrama original del hardware, donde se muestra cómo deber conectarse cada componente a la placa de Arduino:

Diseño software
El programa encargado del funcionamiento está estructurado en tres bloques principales: la declaración de variables y recursos, la inicialización del sistema (setup) y el ciclo principal de ejecución (loop), apoyados por funciones auxiliares. A continuación se presenta el código fuente del proyecto:
Código fuente
#include <LiquidCrystal.h>
int LedPinH= 13;
int LedPinE = 12;
int LedPinD = 11;
int En;
int Di;
int Ha;
int a = 9;
int b = 9;
int p = 0;
int ButPinH = A0;
int ButStateH;
int ButPinD = A2;
int ButStateD;
int ButPinE = A1;
int ButStateE;
int death = 0;
int pinBuzzer = A3;
LiquidCrystal lcd(2, 3, 4, 5, 7, 8); // RS, E, D4, D5, D6, D7
byte happy1[] = {
B00001,
B00110,
B01000,
B10001,
B10001,
B10001,
B10001,
B10000
};
byte happy2[] = {
B11111,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte happy3[] = {
B10000,
B01100,
B00010,
B10001,
B10001,
B10001,
B10001,
B00001
};
byte happy4[] = {
B10000,
B01000,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte happy5[] = {
B00000,
B00000,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte happy6[] = {
B00001,
B00010,
B11100,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte muerto1[] = {
B00001,
B00110,
B01000,
B10000,
B10101,
B10010,
B10101,
B10000
};
byte muerto2[] = {
B10000,
B01100,
B00010,
B00001,
B10101,
B01001,
B10101,
B00001
};
void setup() {
// put your setup code here, to run once:
randomSeed(analogRead(0));
lcd.begin(16, 2);
lcd.createChar(0, happy1);
lcd.createChar(1, happy2);
lcd.createChar(2, happy3);
lcd.createChar(3, happy4);
lcd.createChar(4, happy5);
lcd.createChar(5, happy6);
lcd.createChar(6, muerto1);
lcd.createChar(7, muerto2);
lcd.home();
pinMode(LedPinH, OUTPUT);
pinMode(LedPinE, OUTPUT);
pinMode(LedPinD, OUTPUT);
pinMode(pinBuzzer, OUTPUT);
if(death == 0){
pinMode(ButPinH, INPUT_PULLUP);
pinMode(ButPinD, INPUT_PULLUP);
pinMode(ButPinE, INPUT_PULLUP);
}
En= random(200,251);
Di= random(150,200);
Ha= random(100,151);
analogWrite(LedPinH, 255);
analogWrite(LedPinE, 255);
analogWrite(LedPinD, 255);
lcd.setCursor(a-1,1);
lcd.write(byte(3));
lcd.setCursor(a-1,0);
lcd.write(byte(0));
lcd.setCursor(a,1);
lcd.write(byte(4));
lcd.setCursor(a,0);
lcd.write(byte(1));
lcd.setCursor(a+1,1);
lcd.write(byte(5));
lcd.setCursor(a+1,0);
lcd.write(byte(2));
lcd.setCursor(0,0);
lcd.print("z");
lcd.setCursor(1,0);
lcd.print("Z");
lcd.setCursor(0,1);
lcd.print("<");
lcd.setCursor(1,1);
lcd.print("3");
lcd.setCursor(14,1);
lcd.print("(");
lcd.setCursor(15,1);
lcd.print(")");
}
void loop() {
// put your main code here, to run repeatedly:
ButStateH = digitalRead(ButPinH);
ButStateD = digitalRead(ButPinD);
ButStateE = digitalRead(ButPinE);
if(death == 0){
mover();
if(ButStateE == HIGH)
{
if(En>0)
{
En--;
if(En == 50){
buzzer(100);
}
if(En<50){
lcd.setCursor(1,0);
lcd.print(" ");
analogWrite(LedPinE, 10);
delay(100);
analogWrite(LedPinE, 255);
}
if(En<15)
{
buzzer(100);
}
} else {
lcd.setCursor(0,0);
lcd.print(" ");
lcd.setCursor(1,0);
lcd.print(" ");
death = 1;
}
}
if(ButStateE == LOW)
{
En=255;
analogWrite(LedPinE, En);
lcd.setCursor(0,0);
lcd.print("z");
lcd.setCursor(1,0);
lcd.print("Z");
}
if(ButStateD == HIGH)
{
if(Di>0)
{
Di--;
if(Di == 50){
buzzer(100);
}
if(Di<50){
lcd.setCursor(1,1);
lcd.print(" ");
analogWrite(LedPinD, 10);
delay(100);
analogWrite(LedPinD, 255);
}
if(Di<15)
{
buzzer(100);
}
} else {
lcd.setCursor(0,1);
lcd.print(" ");
lcd.setCursor(1,1);
lcd.print(" ");
death = 1;
}
}
if(ButStateD == LOW)
{
Di=255;
analogWrite(LedPinD, Di);
lcd.setCursor(0,1);
lcd.print("<");
lcd.setCursor(1,1);
lcd.print("3");
}
if(ButStateH == HIGH)
{
if(Ha>0)
{
Ha--;
if(Ha == 50){
buzzer(100);
}
if(Ha<50){
lcd.setCursor(15,1);
lcd.print(" ");
analogWrite(LedPinH, 10);
delay(100);
analogWrite(LedPinH, 255);
}
if(Ha<15)
{
buzzer(100);
}
} else {
lcd.setCursor(15,1);
lcd.print(" ");
lcd.setCursor(14,1);
lcd.print(" ");
death = 1;
}
}
if(ButStateH == LOW)
{
Ha=255;
analogWrite(LedPinH, Ha);
lcd.setCursor(14,1);
lcd.print("(");
lcd.setCursor(15,1);
lcd.print(")");
}
delay(1000);
}else{
lcd.setCursor(p-1,0);
lcd.write(byte(6));
lcd.setCursor(p+1,0);
lcd.write(byte(7));
if(death == 1){
buzzer(1000);
death = 2;
}
}
}
void mover()
{
if(a>6)
{
lcd.setCursor(a-1,1);
lcd.write(" ");
lcd.setCursor(a-2,1);
lcd.write(byte(3));
lcd.setCursor(a-1,0);
lcd.write(" ");
lcd.setCursor(a-2,0);
lcd.write(byte(0));
lcd.setCursor(a,1);
lcd.write(" ");
lcd.setCursor(a-1,1);
lcd.write(byte(4));
lcd.setCursor(a,0);
lcd.write(" ");
lcd.setCursor(a-1,0);
lcd.write(byte(1));
lcd.setCursor(a+1,1);
lcd.write(" ");
lcd.setCursor(a,1);
lcd.write(byte(5));
lcd.setCursor(a+1,0);
lcd.write(" ");
lcd.setCursor(a,0);
lcd.write(byte(2));
a--;
p=a;
delay(1000);
}
if(a == 6){b=6;
a--;
}
if(b<8)
{
lcd.setCursor(b+1,1);
lcd.write(" ");
lcd.setCursor(b+2,1);
lcd.write(byte(5));
lcd.setCursor(b+1,0);
lcd.write(" ");
lcd.setCursor(b+2,0);
lcd.write(byte(2));
lcd.setCursor(b,1);
lcd.write(" ");
lcd.setCursor(b+1,1);
lcd.write(byte(4));
lcd.setCursor(b,0);
lcd.write(" ");
lcd.setCursor(b+1,0);
lcd.write(byte(1));
lcd.setCursor(b-1,1);
lcd.write(" ");
lcd.setCursor(b,1);
lcd.write(byte(3));
lcd.setCursor(b-1,0);
lcd.write(" ");
lcd.setCursor(b,0);
lcd.write(byte(0));
b++;
p=b;
delay(1000);
}
if(b == 8){a=8;
b++;
}
}
void buzzer(int del)
{
digitalWrite(pinBuzzer, HIGH);
delay(del);
digitalWrite(pinBuzzer, LOW);
}
message.txt
message.txt (6 KB)
6 KB
Proceso de empotrado
El diseño de la estructura de empotrado para el tamagotchi está inspirado en el slime Pusddle de Slime Rancher, ya que la propia mascota del tamagotchi es un slime.

La caja contenedora se diseño a medida para el prototipo a partir de trozos de cartón, haciendo los agujeros necesarios para los componentes interactuables, y se ensambló con ayuda de silicona caliente. Con la estructura base terminada, se procedió con la decoración utilizando papeles de colores, obteniendo el siguiente resultado:


Funcionamiento
El Tamagotchi electrónico simula la vida de una mascota virtual, gestionando tres necesidades básicas: amor, comida y sueño. Cada una de estas necesidades se representa mediante un LED específico (rojo, azul o amarillo) y un símbolo ASCII en la pantalla LCD 16×2. La mascota en sí se representa con un sprite animado que se desplaza horizontalmente por la pantalla.
El sistema utiliza distintos tipos de retroalimentación para alertar al usuario sobre las necesidades de la mascota:
- Alertas visuales: Cuando una necesidad alcanza un valor crítico, el LED correspondiente parpadea y el símbolo ASCII asociado se modifica parcialmente para indicar la urgencia.
- Alertas sonoras: El buzzer emite pitidos de distinta duración según la gravedad de la necesidad. Cuando la necesidad es crítica, se realiza un pitido corto; si queda menos de 15 segundos para llegar a cero, los pitidos se vuelven intermitentes; finalmente, si la necesidad llega a cero, se emite un pitido largo que indica la muerte de la mascota.
- Animación continua: El sprite de la mascota se mueve de izquierda a derecha en la pantalla de manera constante, proporcionando retroalimentación visual adicional sobre el estado del sistema.
El usuario puede restaurar cada necesidad pulsando el botón correspondiente, situado debajo del LED de la necesidad. Al hacerlo, el valor de la necesidad se reinicia al máximo y el símbolo ASCII se restablece.