Cubo LED + serpiente

Prólogo


En este artículo, nosotros (ya que el artículo fue escrito y realizado por un proyecto de 2 personas) le diremos cómo damos vida al viejo juego, olvidado por todos.

imagen

Preparación


Comencemos con el cubo. No se nos ocurrió una "bicicleta" y decidimos buscar soluciones preparadas. El artículo se basó en un artículo de un autor noruego, aunque se hicieron algunos cambios que, a mi parecer, fueron beneficiosos.

Crea tu propio cubo LED


Habiendo discutido algunos puntos, se decidió hacer un cubo de 8x8x8. Logramos comprar 1000 LED a granel a un buen precio, justo lo que necesita, aunque estos no eran realmente LED adecuados. Visualmente, los LED azules con una lente mate se verían mejor, el brillo no es tan brillante y más uniforme. Hay otro problema con los LED transparentes; la capa inferior resalta las superiores. Sin embargo, a pesar de todo esto, los LED deben ser lo suficientemente brillantes como para aclarar la imagen. Para una mayor transparencia del cubo, es mejor tomar LED pequeños, por ejemplo, 3 mm. Otro punto al elegir los LED es la longitud de las patas. Haremos el marco del cubo a partir de las patas de los LED, por lo que no deben ser más pequeños que el tamaño de la jaula.

Otro punto importante al construir un cubo es su tamaño. Hacemos el marco usando las patas del LED, aunque hay formas en que se usan varillas de metal o alambre. La longitud de los cátodos de nuestros LED resultó ser de aproximadamente 25 mm, por lo que elegimos un tamaño de celda de 20 mm y decidimos usar el resto para soldar, para que el cubo fuera más fuerte. Esto es solo una ligera diferencia del diseño del autor del artículo anterior.

El siguiente paso es crear un diseño para soldar capas de cubos, esto ayudará a facilitar la soldadura y el cubo será más uniforme. El diseño es muy simple, tomé un trozo de madera contrachapada, lo dibujé al tamaño de mi cubo y perforé agujeros en la intersección de las líneas del tamaño de los LED.

imagen

Soldando varias capas, me di cuenta de que este diseño no tiene suficientes patas, que sirvieron como pernos largos.

Antes de comenzar a soldar el cubo, le aconsejo que prepare todo. Por experiencia personal, puedo decir que es mucho más conveniente hacer esto juntos, porque realmente no hay suficientes manos, una persona aplica cátodos y la segunda alimenta soldaduras y soldaduras. Debe hacer esto rápidamente, los LED son pequeños y tienen miedo de sobrecalentarse. También en diferentes manuales dicen que verifique cada LED antes de soldar. No veo el punto, paso mucho tiempo en una operación esencialmente sin sentido. Compramos nuevos LED y todos resultaron estar funcionando. Pero cuando soldaste la capa, ya vale la pena verificar todo bien, porque soldar el LED desde el centro es una tarea desagradable, fue comprobado por experiencia personal.

Entonces, procedamos directamente a la soldadura. No puedo decir que esta sea la forma más segura, pero lo hicimos así. Para empezar, tenemos todos los LED en nuestro diseño, es recomendable instalarlos sin problemas, entonces no habrá forma de arreglar algo.

imagen

imagen

Luego doblamos los cátodos para que se superpongan entre sí. Cuando todo esté listo, puede comenzar a soldar, pero debe recordar un posible sobrecalentamiento, y si la soldadura falla, no se apresure a soldar, es mejor dejar que el LED se enfríe.

Soldando todos los LED, obtenemos 8 tiras de 8 LED. Para convertirlo todo en una capa, utilizamos alambre de aluminio común, que anteriormente estaba enderezado. Decidimos usar solo 2 de estas "varillas", para no complicar el diseño, por cierto resultó ser bastante fuerte.

No es necesario soldar la última capa porque luego debe volver a insertarla. Ahora que tenemos las 8 capas, necesitamos combinarlas de alguna manera en un cubo. Para hacer el cubo más o menos parejo, tuve que doblar los ánodos como se muestra en la figura, ahora rodea el LED y se puede soldar perfectamente.

imagen

imagen

Soldamos el cubo desde la capa superior hasta la parte inferior, mientras verificamos constantemente el funcionamiento de los LED, es mejor no ser flojo, porque entonces será más difícil corregir el error. Es mejor establecer la altura entre las capas con la ayuda de algunas plantillas, el autor del artículo anterior usó coronas ordinarias. No teníamos nada adecuado, pero éramos dos, así que decidimos configurar todo manualmente. Resultó bastante bien, pero no perfecto.

Una vez que hayas realizado todas estas acciones, obtendrás el cubo de LED que recogiste y algunos dedos quemados, pero esto ya depende de tu precisión.

imagen

imagen

Diseño del circuito


Para implementar nuestras ideas, necesitábamos algún tipo de microcontrolador. Decidimos quedarnos en el microcontrolador Arduino Leonardo. No queríamos preocuparnos por los programadores y el software necesario, simplemente no necesitamos un procesador potente para nuestras tareas. Al tener el dispositivo terminado, nos dimos cuenta de que era posible usar Nano, pero esto no es tan crítico. Para controlar el cubo, decidimos usar un teléfono conectado al Arduino a través de Bluetooth, en nuestro caso se usa el HC-05, pero puede usar cualquier otro.

imagen

Pero lo que es realmente importante es la cantidad de pines del microcontrolador, porque tenemos 64 pines de ánodo y 8 pines de cátodo, pero hablaremos de conectarlos más tarde. Decidimos expandir los puertos IO con la ayuda de registros de desplazamiento, en nuestro caso, estos son los registros TI 74HC595 en el paquete DIP para soldar los enchufes a la placa e insertar los microcircuitos en ellos. Puede leer más sobre estos registros en la hoja de datos, solo diré que usamos todo excepto la señal de reinicio del registro, le aplicamos una unidad, porque es inversa, y giramos la entrada de habilitación de salida a tierra, también es inversa y siempre quisimos recibir datos de registros. También podría usar registros secuenciales, pero luego tendría que poner un decodificador para seleccionar en qué registro escribir información.

imagen

Para cerrar el circuito a tierra, eligiendo el nivel que queremos encender, necesitamos interruptores de transistor, bueno, o simplemente transistores. Utilizamos transistores bipolares de baja potencia de tipo NPN ordinarios conectados en paralelo en 2. No estoy seguro si esto tiene sentido, pero es como si la corriente fluyera mejor. La base a través de una resistencia pull-up de 100 Ohms está conectada al microcontrolador, que abrirá nuestros transistores. Las capas del cubo están conectadas al colector, y los emisores están conectados a la tierra.

imagen

imagen

Poniendo el cubo juntos


No pudieron encontrar nada mejor para suministrar el cubo que la fuente de alimentación de la tableta, cuyos parámetros son 5 V y 2 A. Quizás esto no sea suficiente, pero el cubo se ilumina con bastante intensidad. Para no quemar los LED, todos los terminales del ánodo están conectados a los registros a través de una resistencia limitadora de corriente. Según mis cálculos, deberían haber sido aproximadamente 40 ohmios, pero no los tenía, así que usé 100 ohmios.

Colocamos todo esto en 2 pequeñas placas de circuito impreso. No envenenaron nada intencionalmente debido a la falta de práctica, simplemente conectaron todo con conductores comunes. Los registros con los ánodos del cubo se conectaron usando los cables que sacamos de la computadora vieja. Es más fácil navegar por los cables.

imagen

Decidieron ensamblar el prototipo en el diseño utilizado para soldar.

imagen

Habiendo depurado todo y corrigiendo los errores cometidos, hicimos el cuerpo de nuestro laminado; resultó ser bueno porque no tenía que ser pintado. Aquí está el resultado final:

imagen

¡Que haya luz!


Hay un cubo, queda por hacerlo brillar. A continuación, se describirán varios modos (modos) del cubo, para cambiar qué bluetooth + Android se usó. La aplicación del teléfono fue escrita usando Cordova. El código de la aplicación no se describirá aquí, pero el enlace al repositorio se presenta en la conclusión.

Algoritmo de cubo


Debido al hecho de que no tenemos acceso a todos los LED a la vez, no podemos encenderlos todos a la vez. En cambio, necesitamos iluminarlos en capas.

El algoritmo es el siguiente:

  1. La capa actual es 0.
  2. Registre la máscara para la capa actual
  3. Cierre el transistor para la capa anterior. Si la capa actual es cero, entonces la capa anterior es la séptima capa
  4. Hacemos clic en los valores en los registros. El valor aparece en las salidas de los registros
  5. Abra el transistor para la capa actual. ¡Hurra, una capa brilla!
  6. Capa actual ++. ir a: 2

En total, este algoritmo se repite bastante rápido, lo que nos da la ilusión de que todos los LED están encendidos simultáneamente (pero sabemos que esto no es así). Las máscaras se almacenan en una matriz de bytes de 64x8.

Escribir mods

Estos modos no aparecieron en el orden en que se presentan aquí, así que no los castigue numerando en el código. Comencemos con lo más simple: encienda todos los LED.

Enciende el cubo
void Mode_2_Init() {
	for (byte z = 0; z < CUBE_EDGE_SIZE; z++) {
		for (byte y = 0; y < CUBE_EDGE_SIZE; y++) {
			for (byte x = 0; x < CUBE_EDGE_SIZE; x++) {
				cube->data[z * CUBE_LEVEL_SIZE + y * CUBE_EDGE_SIZE + x] = 1;
			}
		}
	}
}


El mod "pegajoso"

Idea: solo dos capas de cero y séptimo se queman, y son inversas entre sí (el LED en la posición X se enciende solo en una de las capas). La posición se selecciona aleatoriamente (por alguna razón, todos están tratando de encontrar un algoritmo para seleccionar la posición), y el LED en esta posición "se arrastra" a la capa superior si estaba iluminado en la capa inferior, y en consecuencia a la inferior si estaba iluminado en la superior.

Código adhesivo
void Mode_0() {
	byte positionToMove = random(CUBE_LEVEL_SIZE);
	byte fromLevel = cube->data[positionToMove] == 1 ? 0 : 7;
	bool top = fromLevel == 0;
	cube->ShowDataXTimes(5);
	while (true) {
		byte toLevel = top ? fromLevel + 1 : fromLevel - 1;
		if (toLevel >= CUBE_EDGE_SIZE || toLevel < 0) break;
		cube->data[fromLevel * CUBE_LEVEL_SIZE + positionToMove] = 0;
		cube->data[toLevel * CUBE_LEVEL_SIZE + positionToMove] = 1;
		cube->ShowDataXTimes(2);
		fromLevel = toLevel;
	}
}

void Mode_0_Init() {
	cube->Clear();
	for (byte i = 0; i < CUBE_LEVEL_SIZE; i++) {
		byte value = random(0, 2);  // max - 1
		cube->data[i] = value;  //first level
		cube->data[i + (CUBE_EDGE_SIZE - 1) * CUBE_LEVEL_SIZE] = !value;  //last level
	}
}


Cómo se ve en la vida:



"Otro mod pegajoso"

Este mod es similar al anterior, excepto que la capa no se está quemando, sino que la cara y las luces de esta cara, una por una, se mueven hacia la opuesta y luego regresan.

Otro código adhesivo
void Mode_3_Init() {
	cube->Clear();
	positions->clear();
	new_positions->clear();
	mode_3_direction = NORMAL;
	for (short y = 0; y < CUBE_LEVEL_SIZE * CUBE_EDGE_SIZE; y += CUBE_LEVEL_SIZE) {
		for (byte x = 0; x < CUBE_EDGE_SIZE; x++) {
			cube->data[x + y] = 1;
			positions->push_back(x + y);
		}		
	}
}

void Mode_3() {
	if (positions->size() == 0) {
		delete positions;
		positions = new_positions;
		new_positions = new SimpleList<short>();
		mode_3_direction = mode_3_direction == NORMAL ? INVERSE : NORMAL;
	}
	byte item = random(0, positions->size());
	short position = *((*positions)[item]);
	positions->erase(positions->begin() + item);
	byte i = 1;
	while(i++ < CUBE_EDGE_SIZE ) {
		cube->data[position] = 0;
		if(mode_3_direction == NORMAL) position += CUBE_EDGE_SIZE;
		else position -= CUBE_EDGE_SIZE;
		cube->data[position] = 1;
		cube->ShowDataXTimes(1);
	}
	new_positions->push_back(position);
}




Cubo dentro de un cubo

Idea: encienda los LED dentro del cubo en forma de caras del cubo con tamaños de 1 a 8 LED y viceversa.

Cubo dentro de un cubo
void Mode_1() {
	cube->Clear();
	for (byte cube_size = 0; cube_size < CUBE_EDGE_SIZE; cube_size++) {
		for (byte level = 0; level <= cube_size; level++) {
			for (byte x = 0; x <= cube_size; x++) {
				for (byte y = 0; y <= cube_size; y ++) {
					cube->data[level * CUBE_LEVEL_SIZE + y * CUBE_EDGE_SIZE + x] =
						(y % cube_size == 0 || x % cube_size == 0)
						&& level % cube_size == 0 ||
						(y % cube_size == 0) && (x % cube_size == 0) ? 1 : 0;
				}
			}
		}
		cube->ShowDataXTimes(5);
	}
	for (byte cube_size = CUBE_EDGE_SIZE - 1; cube_size > 0; cube_size--) {
		for (byte level = 0; level <= cube_size; level++) {
			for (byte x = 0; x <= cube_size; x++) {
				for (byte y = 0; y <= cube_size; y++) {
					cube->data[level * CUBE_LEVEL_SIZE + (CUBE_EDGE_SIZE - 1 - y) * CUBE_EDGE_SIZE + (CUBE_EDGE_SIZE - 1 - x)] =
						(((y % (cube_size - 1) == 0 || x % (cube_size - 1) == 0) && (level % (cube_size - 1) == 0))
						|| ((y % (cube_size - 1) == 0) && (x % (cube_size - 1) == 0) && level % cube_size != 0))
						&& x < (cube_size) && y < (cube_size) ? 1 : 0;
				}
			}
		}
		cube->ShowDataXTimes(5);
	}
}


Cómo se ve:



Y finalmente la serpiente

De las características de la implementación de la serpiente, vale la pena señalar que no hay restricciones en el campo y, por lo tanto, al dejar el cubo por un lado, usted aparece por el otro. Solo puedes perder si te topas con ti mismo (en verdad, no puedes ganar).
También vale la pena contar por separado sobre la administración:

en el caso de una implementación bidimensional de este juego, no hay problemas con la administración: cuatro botones y todo es obvio. En el caso de una implementación tridimensional, surgen varias opciones de control:

1.6 botones. Con esta opción, el botón tiene su propia dirección de movimiento: para los botones arriba y abajo, todo es obvio, y el resto de los botones se pueden "atar" a los puntos cardinales, cuando presiona el botón "izquierda", el vector de movimiento siempre cambia "oeste", etc. Con esta opción, surgen situaciones cuando la serpiente se mueve "este" y hacemos clic en "oeste". Porque la serpiente no puede girar 180 grados; debes manejar estos casos por separado.

2.4 botones (arriba abajo izquierda derecha). Las acciones de estos botones son similares a las de una implementación bidimensional, excepto que todos los cambios se toman en relación con la dirección actual del vector de movimiento. Permítanme explicarlo con un ejemplo: cuando nos movemos en el plano horizontal, presionando el botón "Arriba", vamos al plano vertical. Al movernos en un plano vertical presionando "Arriba", pasamos a movernos en un plano horizontal contra la dirección del eje X, para "Abajo", en la dirección del eje X, etc.

Por supuesto, ambas opciones tienen derecho a existir (sería interesante conocer otras opciones de control). Para nuestro proyecto, elegimos el segundo.

Código de dirección
void Snake::ApplyUp() {
	switch (direction) {
	case X:
	case Y:
		direction = Z;
		directionType = NORMAL;
		break;
	case Z:
		direction = X;
		directionType = INVERSE;
	}
}

void Snake::ApplyDown() {
	switch (direction) {
	case X:
	case Y:
		direction = Z;
		directionType = INVERSE;
		break;
	case Z:
		direction = X;
		directionType = NORMAL;
	}
}

void Snake::ApplyLeft() {
	switch (direction) {
	case X:
		direction = Y;
		directionType = directionType == NORMAL ? INVERSE : NORMAL;
		break;
	case Y:
		direction = X;
		directionType = directionType;
		break;
	
	case Z:
		direction = Y;
		directionType = NORMAL;
	}
}

void Snake::ApplyRight() {
	switch (direction) {
	case X:
		direction = Y;
		directionType = directionType;
		break;
	case Y:
		direction = X;
		directionType = directionType == NORMAL ? INVERSE : NORMAL;
		break;
	case Z:
		direction = Y;
		directionType = INVERSE;
	}
}

void Snake::ChangeDirection(KEY key) {
	switch(key) {
	case UP:
		ApplyUp();
		break;
	case LEFT:
		ApplyLeft();
		break;
	case RIGHT:
		ApplyRight();
		break;
	case DOWN:
		ApplyDown();
		break;
	}
}


El resultado del programa:





Enlaces al código fuente del firmware del cubo y la aplicación para el teléfono: firmware de la

aplicación


Resultado


Como resultado, obtuvimos una consola primitiva y un tipo de lámpara, con la posibilidad de iluminación dinámica. En el futuro planeamos desarrollar una placa de circuito impreso y mejorar el firmware. También es posible agregar módulos adicionales.

Source: https://habr.com/ru/post/es388369/


All Articles