Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

Componentes y suministros

Microchip ATtiny85 × 1
OLED Gráfico 128x64 × 1
SparkFun microB USB Breakout × 1
Arduino Nano R3 × 1 Para programar el ATtiny85

Herramientas necesarias

Aplicaciones y servicios en línea

Sobre este proyecto

Inspiración y proyecto anterior

En diciembre de 2017 creé una consola Arduino Pong portátil con Arduino Nano, pantalla OLED y dos botones.

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

Era funcional pero demasiado grande. Ahora quiero recrear proyectos pasados haciendo una consola minúscula para jugar a Snake.

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

Componentes elegidos

Para lograr tamaño mínimo, no use placa Arduino de desarrollo, sino un ATtiny85.

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

Tiene suficientes I/O: dos pines ADC, puerto I2C y un GPIO. Usé un joystick analógico de 2 ejes con pulsador, fácil de interfazar y solo necesita 3 pines de señal.

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

Para la pantalla, elegí la OLED 128x64 de DFRobot por su tamaño reducido y buena resolución.

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

Soldando el sistema

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED
ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED
  1. Soldé un ATtiny85 en un adaptador SOP-8 a DIP-8 y luego en una pequeña placa perforada.
  2. Añadí dos headers: uno para programación y otro para la pantalla.
  3. Conecté los pines del joystick analógico a la placa y cableé entsprechend.
  4. Finalmente, cableé una placa breakout micro USB para alimentación.

Diseñando la carcasa

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED
ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

La carcasa se diseñó en Fusion 360. Creé y coloqué los componentes reales y luego modelé la carcasa alrededor. Quería imitar una máquina arcade de los 80 manteniendo tamaño minúsculo. Aquí algunos renders:

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED
ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

Programando el juego

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

Snake es fácil de programar. Longitud máxima 30 segmentos para ahorrar RAM (gana al comer 29 píxeles). Uso un array 2D que almacena pares ordenados para cada segmento.

Cuando la cabeza se mueve, las posiciones anteriores se desplazan hacia abajo. Al comer, aparece un nuevo segmento en punto aleatorio. Colisiones: itero coordenadas de cada segmento comparando con la cabeza. Golpear paredes también pierde.

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

Jugando a Snake

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

Enciendo la consola, espero a que cargue la comida y el primer segmento. Luego piloto la serpiente moviendo el joystick. Es divertido y mata el aburrimiento en un paquete diminuto.

Código

Código ATTiny85 C/C++

Instale primero la librería U8g2lib

//#include <TinyWireM.h>
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g(U8G2_R0, /* clock=*/ 2, /* data=*/ 0, /* reset=*/ U8X8_PIN_NONE);
#define MAX_LENGTH 30
#define X 0
#define Y 1
#define JOYSTICK_X 2
#define JOYSTICK_Y 3
#define DIR_THRESH 300
uint8_t segmentPositions[MAX_LENGTH][2];
uint8_t headPosition[2] = {63, 31};
uint8_t foodPosition[2];
uint8_t tempPosition0[2];
uint8_t tempPosition1[2];
int segmentLength = 1;
void gameUpdate();
enum DIRECTIONS { RIGHT, DOWN, LEFT, UP } currentDirection;

void setup() {
  //TinyWireM.begin();
  u8g.begin();
  u8g.setPowerSave(0);
  pinMode(JOYSTICK_X, INPUT);
  pinMode(JOYSTICK_Y, INPUT);
  randomSeed(analogRead(0));
  beginGame();
}

void loop() {
  u8g.firstPage();
  do {
    gameUpdate();
    u8g.setColorIndex(1);
  } while(u8g.nextPage());
}

void beginGame(){
  currentDirection = RIGHT;
  spawnFood();
  delay(1000);
}

bool checkCollisions(){
  for(int i=1; i<segmentLength; i++){
    if(segmentPositions[i][X] == headPosition[X]){
      if(segmentPositions[i][Y] == headPosition[Y]){
        return 1;
      }
    }
  }
  if(headPosition[X] <= 0 || headPosition[X] >= 128) return 1;
  else if(headPosition[Y] <= 0 || headPosition[Y] >= 64) return 1;
  return false;
}

void spawnFood(){
  int randomX = random(5, 123);
  int randomY = random(5, 60);
  foodPosition[X] = randomX;
  foodPosition[Y] = randomY;
}

void checkFoodEaten(){
  if(headPosition[X] == foodPosition[X] || headPosition[Y] == foodPosition[Y]){
    segmentLength += 1;
    spawnFood();
  }
}

void updateDirection(){
  int joy_x_val = analogRead(JOYSTICK_X);
  int joy_y_val = analogRead(JOYSTICK_Y);
  if(joy_x_val <= DIR_THRESH) currentDirection = LEFT;
  else if(joy_x_val >= 1023-DIR_THRESH) currentDirection = RIGHT;
  else if(joy_y_val <= DIR_THRESH) currentDirection = UP;
  else if(joy_y_val >= 1023-DIR_THRESH) currentDirection = DOWN;
}

void displaySegments(){
  for(int segment=0; segment < segmentLength; segment++){
    u8g.drawPixel(segmentPositions[segment][X], segmentPositions[segment][Y]);
  }
  u8g.drawPixel(foodPosition[X], foodPosition[Y]);
}

void gameUpdate(){
  updateDirection();
  tempPosition0[X] = headPosition[X];
  tempPosition0[Y] = headPosition[Y];
  switch(currentDirection){
    case UP: headPosition[Y] -= 1; break;
    case DOWN: headPosition[Y] += 1; break;
    case LEFT: headPosition[X] -= 1; break;
    case RIGHT: headPosition[X] += 1; break;
  }
  for(int segment=1; segment < segmentLength; segment+= 2){
    tempPosition1[X] = segmentPositions[segment][X];
    tempPosition1[Y] = segmentPositions[segment][Y];
    segmentPositions[segment][X] = tempPosition0[X];
    segmentPositions[segment][Y] = tempPosition0[Y];
    tempPosition0[X] = segmentPositions[segment+1][X];
    tempPosition0[Y] = segmentPositions[segment+1][Y];
    segmentPositions[segment+1][X] = tempPosition1[X];
    segmentPositions[segment+1][Y] = tempPosition1[Y];
  }
  displaySegments();
  checkFoodEaten();
  if(checkCollisions()) endGame();
  if(segmentLength >= MAX_LENGTH) endGame();
  delay(50);
}

void endGame(){
  segmentLength = 1;
  headPosition[0] = 63;
  headPosition[1] = 31;
  beginGame();
}

Piezas personalizadas y envoltorios

(Archivos STL no incluidos en el original)

Esquemáticos

ATtiny85 Mini Arcade: Snake – Construye una Consola Portátil OLED

Proceso de manufactura

  1. Detector de idiomas TinyML con Edge Impulse en Arduino Nano 33 BLE Sense
  2. Construye un Juego Giroscópico en Tiempo Real con Arduino Nano y Sensor MPU-6050
  3. Proyecto Dados Digitales Arduino: Construye tu Propio Generador de Números Aleatorios con LCD
  4. Construye tu Propio Juego de Ruleta de 37 LEDs con Arduino Nano
  5. Detector de Rango Portátil – Kit DIY Arduino Nano con HC-SR04, Batería 18650 y Carcasa Impresa en 3D
  6. Construir una lámpara de escritorio reactiva al audio con Arduino Nano
  7. Proyecto de electroplacado de cobre: Construye un sistema inteligente con Arduino UNO
  8. Pong Neón en Matriz NeoPixel con Arduino Nano
  9. Crea Secuencias de Luz Impactantes con Arduino y Registro de Desplazamiento
  10. Enchufe Inteligente: Toma 120 V Basada en Arduino con Reloj Tiempo Real
  11. Sistema de seguridad Arduino: Detección de movimiento inteligente y alerta