El aspecto más novedoso de nuestro robot, además del hecho de ser acometido por alumnado de Secundaria, es que se va a programar en lenguaje NXT 2.1 Programming (o en EV3 Programming en el prototipo para EV3). Se trata de un lenguaje asociado a eventos donde los comandos son bloques que se insertan en un circuito (que imita las barras Technics de Lego) de manera que se asemejen a la típica representación gráfica de los algoritmos. Los prototipos de los que partimos y lo demás que se ven en internet están programados en NXC, que es una versión del lenguaje de alto nivel C adaptada para programar el "brick" del Mindstorm. Es impensable enseñar a programar en C al alumnado de ESO en 24 horas de Andalucía Profundiza; y es más impensable que al alumnado le dé tiempo además a escribir el programa que resuelva el cubo: los códigos fuente utilizados en los prototipos originales tenían una extensión de 20 folios. No obstante, el programa en lenguaje Mindstorm sí tiene una dificultad y extensión apropiadas para el alumnado de Secundaria. Es frecuente que el alumnado de 4º de ESO haya trabajado con estos robotos en el área de Tecnología.
Quizá haya llegado el momento de hablar del "brick" de Lego Mindstorm. Se trata de un dispositivo electrónico digital que se puede programar desde el ordenador vía cable USB para, luego, funcionar independientemente. El ladrillo (o "brick") tiene cuatro puertos de entrada (1, 2, 3 y 4) a los que conectar los sensores del robot (de contacto, de sonido, de ultrasonido, de luz, de color, de temperatura, de infrarrojos...) y de tres puertos de salida (A, B y C, más un cuarto puerto D en el EV3) a los que se conectan los servomotores. El ladrillo incluye también varias teclas para su manejo y una pantalla y un altavoz para mandar información al exterior de acuerdo al programa en ejecución. En la foto que sigue se muestra a la izquierda el ladrillo EV3 (más moderno) y a la derecha el ladrillo NXT.
El primer paso en nuestra programación es conocer el bloque "motor". Permite manejar los tres servomotores que se encargan de mover el brazo volteador/bloqueador, rotar la bandeja giratoria y acercar/alejar la articulación del triple sensor de color. Los alumnos aprendieron cómo distinguirlos a partir del puerto al que están enchufados en el "brick" Mindstorm NXT. Y cómo hacerlos girar en un sentido u otro, con un ángulo de giro determinado y con una velocidad deseada. También era importante saber cómo hacerlos girar durante un tiempo o dándoles un giro sin frenazo final (con flotación).
Así, el bloque motor mostrado en la figura haría girar al motor que está en el puerto B 360º en sentido horario (según se mire), con una velocidad del 75% de la máxima y frenando al final del recorrido (ver la configuración del bloque en la parte inferior de la pantalla).
Comprobaron también en sus prototipos qué motores eran los que se encargaban de cada elemento funcional y de cómo tenían que configurar el bloque del servomotor correspondiente para girar la bandeja 90º a la derecha (motor A), acercar el triple sensor de colores a la esquina delantera superior derecha del cubo (motor B) o para bloquear la capa superior del cubo mientras se hacía girar la inferior hacia la izquierda (motor C).
A continuación aprendieron a manejar el sensor de color. Los que lo conocían de haber trabajado en la paleta común (bloques básicos del lenguaje Mindstorm) sabían que los bloques sensor (de color naranja) se podían utilizar a modo de barrera o espera: una acción se mantenía en el tiempo hasta que uno de los sensores recibían una información del exterior que permitían pasar al siguiente bloque en la secuencia. Pero los que nos interesan son los bloques sensor (de color amarillo) de la paleta completa (bloques avanzados del lenguaje Mindstorm). Éstos devuelven un valor numérico o lógico que puede ser útil para decidir la acción a tomar.
El sensor de color puede hacer muchas cosas, pero una de ellas es devolver un valor numérico dependiendo del color que esté leyendo. A continuación, las concordancias número-color del sensor:
Negro
Azul
Verde
Amarillo
Rojo
Blanco
Para ello hay que llevar un hilo (cuando es de datos numéricos, este hilo es de color amarillo) a la entrada de la bifurcación que se muestra. Las bifurcaciones suelen ser dobles: son el equivalente del comando "If...then...else" de cualquier lenguaje de programación. Estas bifurcaciones ofrecen dos "caminos" u opciones en función un dato o resultado recabado por el programa. Pero, si le conectamos un hilo de datos numérico, puede abandonar la vista plana y adoptar tantos "caminos" como queramos. Para ello, asignamos un valor numérico a cada "camino", del 1 al 6 en el ejemplo que se muestra a continuación, y dentro de ellos (a los que accedemos mediante la pestañita que se ve en la bifurcación) colocar la secuencia de bloques que queremos que ejecute en función del color que haya leído.
En el ejemplo arriba mostrado, si el lector de colores (que está conectado al puerto 1) detecta un color verde, mandará un valor numérico "3" a la bifurcación que ejecutará la secuencia 3 (se ve la solapa seleccionada un poco más clara). Dentro de esta secuencia, emitirá un sonido, mostrará algo en la pantalla del ladrillo Mindstorm (el mensaje "verde" sería muy apropiado) y no hará nada más hasta pasados 5 segundos.
Otra bloque fundamental es el "bucle": en general, la ejecución de cualquier programa informático se basa en bifurcaciones y bucles. Estos últimos son repeticiones de una secuencia de bloques que se producen hasta que se cumple una condición. Así pues, necesitan de un valor lógico para salir de él.
En el ejemplo arriba mostrado, el sensor de color (que está conectado al puerto 3) hace una lectura y manda el valor numérico obtenido a ser comparado con un valor definido en una constante (la maleta con el candado). Si el valor y la constante son iguales, se sale del bucle y aparece un dibujo en la pantalla del ladrillo. Si no lo son, se repite la lectura una vez por segundo (bloque espera o "retardo" con el dibujo del temporizador y el reloj de arena) hasta que valor y constante coinciden. Fijémonos en que el hilo de datos es de color verde al transmitir datos lógicos (1-0, verdadero-falso, sí-no, ...). No obstante, hay un fallo en el programa mostrado: la comparación debería haberse configurado para la opción "A igual a B" en vez de "A menor que B".
La paleta personalizada reúne los bloques que hemos bajado de internet y, lo más interesante, bloques que hemos creado nosotros combinando otros bloques de la paleta. Es el equivalente de las "macros" o "rutinas" y "subrutinas" de otros lenguajes. Esta paleta es fundamental en nuestro proyecto. Permite que el programa en desarrollo no alcance un tamaño descomunal que haga lento y lleno de errores su manejo. Por otro lado, que haya rutinas a las que recurramos constantemente y no tengamos que programarlas bloque a bloque es muy útil: sobre todo porque, si hay que corregir algo en estas rutinas, al hacerlo dentro del bloque personalizado ya vale para todas las veces que este bloque personalizado aparezca. Como veremos más adelante, todo nuestro programa se basa en bloques personalizados.
En la imagen superior se ve la paleta personalizada desplegada y parte del programa (22jun) que resuelve el cubo. Observamos también cómo este programa se basa casi exclusivamente en bloques de creación propia.
Ha llegado el momento de acceder al programa creado para este prototipo. Debe estar trufado de errores; pero no se trata tanto de bajarlo y ejecutarlo como de verlo y ver cómo se ha acometido esta programación simultáneamente a lo aprendido en este blog. Se puede descargar en este enlace.
Un vez descomprimido el fichero Rubik Infante copiamos y pegamos el fichero 22jun.rbt en la carpeta
Mis documentos / LEGO Creations / MINDSTORM Projects / Profiles / Predeterminado
Y los demás ficheros correspondientes a bloques de creación propia en
Mis documentos / LEGO Creations / MINDSTORM Projects / Profiles / Predeterminado / Blocks /Mis bloques
Partimos del supuesto de que tenemos el programa NXT 2.1 Programming, claro. Si no, no tenemos la aplicación necesaria en nuestro ordenador.
Hay muchos otros bloques interesantes, pero ya hablaremos de ellos a medida que vayan apareciendo en próximas entradas.
Ya dijimos en el punto anterior que, si convertimos rutinas frecuentes en bloques de creación propia, podremos acudir a ellos cada vez que las necesitemos sin necesidad de escribir la secuencia cada vez que aparezca. Otra enorme ventaja añadida es que reduce espectacularmente el tamaño del programa compilado: esto es fundamental en el ladrillo NXT donde la memoria para programas es de apenas unos 70 KB; el ladrillo EV3 no está tan limitado.
Empezamos a crear nuestros primeros bloques (se explica como crearlos en el tutorial que incluye el NXT 2.1 Programmin. Se accede a este tutorial con la barra Technics naranja que ve en la pantalla del programa arriba a la derecha). Combinando lo aprendido en el manejo de los servomotores, empezamos a crear unas secuencias básicas que inmediatamente convertimos en bloques de la paleta personalizada accesibles dentro de "Mis bloques". Aparecen, si abrimos el programa "22jun" , con nombres que aparecerán en lo sucesivo en cursiva, al igual que los nombres de variables. Estos bloques básicos son:
girar bandeja 90º a izquierda (Mesaizquierda)
girar bandeja 90º a derecha (Mesaderecha)
bloquear (Blokeo): sujetar la capa superior del cubo para poder rotar sólo la capa inferior.
desbloquear (Desblokeo): dejar de sujetar la capa superior del cubo, devolviendo el brazo v/b a la posición de reposo.
voltear (Volteo): volcar el cubo entero 90º a la izquierda con la ayuda del brazo v/b. Importante: si trabajamos con el prototipo Tilted Twister, como quiera que voltea hacia la derecha (si mantenemos el convenio de mirar frontalmente el prototipo con el brazo v/b a la izquierda y los sensores de color a la derecha), habría que rediseñar toda la propuesta de los 12 bloques (B, B', F, F', etc) que se explica más abajo.
A estos añadimos los bloques
girar capa inferior 90º a la izquierda (planoinfizq)
girar capa inferior 90º a la derecha (planoinfder)
Estos dos bloques deberían programarse a partir de una combinación como la que sigue:
planoinfizq = Blokeo + Mesaizquierda+ Desblokeo
Pero, debido a la necesaria holgura de la bandeja respecto del cubo, la cara superior no se terminaba de quedar escuadrada con la capa inferior. Entonces, se optó por lo siguiente:
planoinfizq = Blokeo + girar bandeja a la izquierda 105º + Desblokeo +girar bandeja a la derecha 15º
Y lo mismo para planoinfder. Este escuadre no siempre se obtiene al 100%. Cuando el desfase de ángulo entre la cara superior e inferior alcanza un mínimo, suele provocar disfunciones en el movimiento de volteo siguiente que obligan a hacer correcciones manualmente. En la última entrada del blog aportaremos ideas para corregir o minimizar los problemas detectados.
A continuación creamos otros 12 bloques que son los movimientos básicos para resolver nuestro cubo de Rubik de 2x2x2. Estos bloques son U, U', D, D', R, R', L, L', F, F', B y B'. En el dibujo adjunto se muestran 6 de estos movimientos. Los movimientos con la "comilla" son los mismos, pero en sentido contrario, esto es, en sentido antihorario si se mira la cara afectada frontalmente.
Estos movimientos se pueden programar y guardar como bloques personalizados como sigue:
D = planoinfder D' =planoinfizq L = Volteo + plainfder + Volteo + Volteo + Volteo
Estos tres últimos volteos sirven para dejar el cubo con la orientación que tenía inicialmente; veremos, cuando sigamos generando secuencias, que es fundamental dejar siempre el cubo con la orientación que tenía inicialmente para que las secuencias basadas en los 12 movimientos no pierdan el sentido. L' = Volteo + planoinfizq + Volteo + Volteo + Volteo U = Volteo + Volteo + planoinfder + Volteo + Volteo U' = Voleot + Volteo + planoinfizq + Volteo+ Volteo R = Volteo + Volteo + Volteo + planoinfder + Volteo R' = Volteo + Volteo + Volteo + planoinfizq + Volteo F = planoinfder + R + planoinfizq F' = planoinfder + R'+ planoinfizq B = planoinfizq +R + planoinfder B' = planoinfizq +R' + planoinfder
Éste podría ser un buen momento para programar y ejecutar la secuencia siguiente con el prototipo y un cubo completado y comprobar si hemos hecho bien toda la programación de la sesión.
En este programa de prueba sería deseable que entre un movimiento y otro hubiera una pausa de 5 segundos y un pitido y/o un mensaje en pantalla que nos diera tiempo a asegurarnos de que se ha terminado correctamente cada movimiento básico.
Y ahora acometemos otro par de bloques personalizados: son Secuencia A y Secuencia B. Para comprender de qué hablamos, hay que adelantar que la resolución del cubo la basamos en tres etapas que se detallarán en próximas entradas: la primera es la resolución de la cara blanca (superior); la segunda es completar la cara amarilla (inferior) con sus cuatro vértices sin ordenar; y la tercera es la ordenación de esta cara amarilla. Pues bien, la secuencia A es la que permite, repitiéndola varias veces dependiendo del caso, hacer la segunda etapa. Y la secuencia B es la que permite resolver la tercera etapa, repitiéndola varias veces dependiendo del caso.
Secuencia A = R' + U' + F' + U + F + R Secuencia B = L + F'+ L + B + B + L' + F + L + B + B + L + L
No serán los últimos bloques que creemos. Ya iremos describiéndolos a medida que aparezcan en las siguientes entradas.
Si nos remitimos, años atrás, a nuestros primeros intentos de resolver el cubo de Rubik de 3x3x3, recordaremos que sólo éramos capaces de resolver una cara. Ésta se completaba ordenada de manera intuitiva, pero éramos incapaces de seguir haciendo las otras caras sin desmontar la primera.
Aquí empezaremos igual: con una primera cara que será la blanca. El problema es que, si bien la resolución manual de la primera cara era sencilla y al alcance de cualquiera, la programación informática de la resolución de esta primera cara resulta muy tediosa y, en varias ocasiones, necesitada de cierto esfuerzo mental. Es el tópico de que tareas intuitivas para el humano resultan tremendamente complicadas de programar para la máquina.
Volviendo a la resolución de la cara blanca, el procedimiento en líneas generales será el siguiente: vamos a estudiar las ocho esquina de acuerdo a una secuencia y, si tienen un vértice blanco, colocarlo en su lugar correspondiente. En lo sucesivo nos referiremos a esquinas cuando nos refiramos a una de las ocho esquinas del cubo atendiendo a su posición en el cubo y vértices cuando nos refiramos a una de estas esquinas como pieza movible con tres caras de colores.
Podemos simplificar el proceso si partimos de una esquina o vértice del cubo como referencia. Escogemos como comienzo de partida de la resolución la esquina blanca- roja-azul, a la que nos referiremos en lo sucesivo como Esquina 1. El orden en que se mencionan los colores es importante: la primera cara es la superior de ese vértice, la segunda la frontal y la tercera es la derecha. Recordemos que la esquina del cubo que el lector triple de colores lee es la delantera-superior-derecha. El programa arranca y aparece un mensaje en pantalla que nos pide que pongamos el cubo en la bandeja con la esquina Bl-Ro-Az al alcance del lector triple de colores. Este comprueba que es la esquina deseada y con la orientación deseada y aparece un mensaje de "gracias" en la pantalla. Si no colocamos el cubo o lo colocamos con otra esquina en su lugar o con la esquina correcta con una orientación incorrecta (Az-Bl- Ro o Ro-Az-Bl), volverá a pedirnos que coloquemos el cubo correctamente hasta que lo hagamos.
De todo esto se encarga el bloque personalizado Esquina1 que está al comienzo del programa.
Si abrimos el bloque Esquina1, vemos que en el interior de un bucle condicionado se encuentran:
varios bloques "pantalla": muestran el mensaje pidiendo que pongan el cubo con la esquina Bl-Ro-Az al alcance del lector triple de colores (como el mensaje es largo, hacen falta varios renglones para exponerlo: de ahí la necesidad de varios bloques configurados para no borrar lo que ya había en la pantalla).
un retardo de 5 segundos: para dar tiempo a poner el cubo en la bandeja manualmente.
el bloque personalizado Leeresquina: si abrimos este bloque, vemos lo que se muestra en la imagen siguiente: se acciona el brazo del lector
triple de colores, éste lee los tres colores de la esquina, asignando los
valores numéricos de los colores a las variables ColorArriba, Colorfrontal y Colorderecho (las variables aparecen como bloques con el símbolo de un maletín) y retira el brazo.
el bloque personalizado Proddiv: básicamente multiplica 60 (el maletín con el candado suele representar constantes) por las variables ColorArriba y por Colorfrontal y el resultado lo divide por la variable Colorderecho. El valor obtenido se la asigna a la variable Proddiv (del mismo nombre que este bloque personalizado).
Volviendo al bloque Esquina 1, se compara el valor de la variable Proddiv con la constante 900 (bloque que muestra un maletín con un candado), para ver si son iguales . Esta comparación genera un valor lógico que, si es positivo permite salir del bucle condicionado, y, si no, lo obliga a repetirse. Si sale del bucle, aparecerá en pantalla un mensaje de "Gracias" por haber puesto correctamente el cubo en la bandeja giratoria.
A continuación, la bandeja con el cubo gira 90 º a la derecha (Mesaderecha) para ofrecerle al triple sensor de colores la que llamaremos Esquina 2. Esta esquina es la que, si estuviera el cubo formado, ofrecería al triple sensor los colores blanco, verde y rojo.
Si abrimos este bloque Esquina2, vemos que aparece en pantalla el mensaje Esquina 2 (el programa está lleno de "chivatos" que nos indican por dónde va la ejecución del mismo, qué valor arrojan la lectura de los sensores, el valor de las variables, etc. Frecuentemente, vienen acompañados de retardos para que dé tiempo a leer estos mensajes en la pantalla del ladrillo e incluso por pitidos).
Dentro de un bucle que se repite tres veces (más adelante explicaremos por qué) se ejecuta el bloque Leeresquina y un nuevo bucle personalizado que se llama Hay Blanco.
Básicamente, en este bucle Hay Blanco se compara el valor de las variables Colorarriba, ColorFrontal y Colorderecha con la constante 6 (el correspondiente al color blanco). Se generan tres variables lógicas Okey1, Okey2 y Okey3 que, caso de dar afirmativo en la comparación, serán iguales a 1. A continuación generamos la variable lógica Hayblanco que será igual a la suma lógica de Okey1, Okey2 y Okey3. Dicho de otra manera, si una de las caras de la esquina 2 es blanca, Hayblanco será igual a 1, siendo ésta 0 en caso contrario.
Esta variable Hayblanco es la que decide la bifurcación siguiente: si en la esquina 2 hay un vértice con una cara blanca, procederemos a colocarlo en su sitio y orientación correcta mediante la combinación correspondiente de movimientos básicos B, B', F, F', etc. Pero si no hay una cara blanca en el vértice, lo ignoraremos. Por eso en la parte de abajo de la bifurcación no hay nada. No obstante, podríamos colocar un bloque pantalla con el mensaje "No hay blanco".
Para identificar ese vértice con una cara blanca con vistas a colocarlo en su posición y orientación correcta de la cara blanca del cubo, utilizamos el valor Proddiv. En la tabla siguiente se muestran los valores que arrojarían esos tres vértices posibles con las tres orientaciones posibles (las combinaciones blanco-rojo-azul no aparecen pues suponemos que ese vértice está ya situado en su posición correcta de la esquina 1).
Pues bien, estos 9 valores deciden el camino a seguir en la bifurcación múltiple gracias al cable de datos numéricos amarillo que conecta con la variable Proddiv. Para ello, configuramos el bloque bifurcación asignando a las posibilidades 1, 2, 3, 4, 5, 6, 7, 8 y 9 los valores numéricos 20, 30, 120, 150, 180, 216, 600, 720 y 1080 respectivamente.
El de la imagen superior tiene 10 posibilidades porque, cuando lo hice, no sabía bien programar el bucle y parecía que había que dejar una posiblidad primera "por defecto" (que asocié al valor 1) por si alguno de los otros casos no se cumplía. En todo caso y como se ve en el dibujo, si la esquina que está en el lugar de la esquina 2 es la azul (arriba)-negra (frontal)-blanca (derecha), Proddiv valdrá 20 y se ejecutará la secuencia 20 (la segunda en la imagen), esto es, F', F', D', D', F, F, L', D, L.
¿Cómo crear la secuencia de movimientos básicos que pongan un vértice con una cara blanca en su esquina correcta dejando el cubo con la orientación que tenían inicialmente y sin cambiar otras esquinas de la cara blanca que ya estuvieran colocadas en su sitio? Pues... puede llegar a ser todo un ejercicio mental.
Un método que yo usé consistía en tener dos cubos de Rubik de 2x2x2: uno estaba completamente resuelto y orientado de manera que ofreciera el vértice en estudio en su esquina correcta teniendo en cuenta la orientación que tiene el cubo cuando el sensor (en este caso la esquina 2); y el otro cubo con el vértice en la posición y orientación en la que encuentra el sensor. Se trata de llevar esta esquina del segundo cubo a la posición y orientación que debe tener en el primer cubo. Eso sí: primero, sin sacar de su sitio otros vértices que ya hubiéramos colocado en su sitio (de momento sólo la esquina 1); y, segundo, dejando el cubo en su bandeja con la orientación que tenía en el momento en que el lector triple de colores la estudió.
En este ejemplo que para llevar la esquina verde-blanca-negra a su sitio...
...basta con un movimiento R
Estas secuencia de movimientos que pueblan las bifurcaciones múltiples las diseñó el alumnado: a cada uno se le asignó una esquina (siete esquinas, descontando la primera) y debía diseñar nueve secuencias (tres vértices con tres orientaciones posibles mostradas como cada una de las combinaciones de colores de la tabla de colores de arriba).
En algunos casos bastaba con un movimiento (para colocar la verde-negra-blanca con valor Proddiv=30 en su sitio, basta con girar la cara frontal hacia la izquierda: F'), en otros hacían falta bastantes movimientos y en algunos otros casos no hacía falta hacer nada: la esquina estudiada estaba ya en su posición y orientación correctas y, sólo por dejar constancia, mostraba un mensaje en pantalla de que el vértice encontrado en la esquina 2 (blanca-verde-roja con valor Proddiv=216) ya estaba correctamente posicionado y orientado.
Tras esto lo lógico sería pasar a estudiar la siguiente esquina. Pero, cuando ensayamos el prototipo observamos que tras colocar un vértice en su sitio, a veces, otro vértice con una cara blanca ocupaba la esquina que aquella había abandonado. Entonces, y por no complicar la programación, metimos la secuencia Leeresquina-Proddiv-bifurcaciónmúltiple dentro de un bucle que se repetía tres veces. Probablemente habría sido más inteligente volver a leer los colores del vértice y condicionar la salida de este bucle a la suma lógica "no tiene blanco"OR"esquina ya colocada en su sitio". Pero había prisa en el momento en que detectamos el fallo y lo dejamos así. Por otra parte, repetir la secuencia tres veces venía bien en caso de que hubiera un fallo en la lectura de los colores del vértice.
Tras esto, volvemos a girar la bandeja con el cubo 90º a la derecha (Mesaderecha) para ofrecerle al lector triple de colores la esquina 3. Esta esquina es la que, caso de estar el cubo completado, ofrecería los colores blanco-negro-verde. Le aplicamos el mismo tratamiento que a la esquina 2, pero teniendo en cuenta que las 9 secuencias son completamente diferentes que las aplicadas en la esquina anterior (8 en realidad, si descontamos la posibilidad de que el vértice bl-ne-ve esté ya en la esquina 3) y que necesitan de un diseño propio. De todo esto se encarga el bloque Esquinita31 (a veces hay que cambiar un bloque por otro igual con un nombre diferente: esto ocurre al encontrar fallos de compilado que no obedecen a un motivo evidente).
Dos bloques personalizados que nos pueden ayudar son Giresqhor y Giresqant. Éstos giran un vértice con una cara blanca en sentido horario y antihorario respectivamente sin afectar a otros vértices de la cara blanca superior. Giresqhor = F + D + D + F' + R' + D + D + R Giresqant = R' + D' + D' + R + F + D + D + F'
Pueden ser útiles si, por ejemplo, en esta esquina 3 nos encontramos con las lectura verde-blanco-negro(Proddiv = 1080: habría que girar el vértice en sentido horario) o negro-verde-blanco (Proddiv = 30: habría que girar el vértice en sentido antihorario).
A continuación volvemos a girar la bandeja con el cubo 90 a la derecha para ofrecerle al lector triple de colores la esquina 4. Esta esquina es la que, caso de estar el cubo completo, ofrecería los colores blanco-azul-negro. Le aplicamos lo ya dicho para la esquina 3. De esto se encarga el bloque personalizado esquina4.
Acto seguido, damos dos volteos al cubo para ofrecerle al lector triple de colores la esquina 5. Esta esquina es la que, caso de estar el cubo resuelto, ofrecería los colores amarillo-azul-rojo (de hecho, si el cubo estuviera resuelto, lo que veríamos sería la cara amarilla completada). Le aplicamos a la esquina 5 lo ya dicho para la esquina 3, con la salvedad de que hay que diseñar 9 secuencias de movimientos: ningún vértice con una cara blanca estaría en su sitio en la esquina 5. El bloque encargado de esto es esquinita51.
Nuevo giro de la bandeja 90º a derechas para ofrecerle al lector de triple de colores la esquina 6 que, caso de estar el cubo resuelto, ofrecería los colores amarillo-negro-azul. Le aplicamos lo ya dicho para la esquina 5. El bloque encargado de esto es Esqunita6.
Nuevamente el bloque Mesaderecha para ofrecer al sensor de color la esquina 7 que, caso de estar el cubo resuelto, ofrecería los colores amarillo-verde-negro. Le aplicamos lo ya dicho para la esquina 5 con la salvedad de que ya no es necesario repetir la secuencia tres veces: con dos ya tiene suficiente. El bloque Esquina7 se encarga de resolver la esquina.
Y un último giro de la bandeja a la derecha para ofrecerle al sensor la esquina 8, la que, caso de estar el cubo resuelto, ofrecería los colores amarillo-rojo-verde. Le aplicamos lo ya dicho para la esquina 7: ahora no sería necesario repetir la secuencia. No obstante, preferimos pecar de prudecia y la ejecutamos dos veces. Esto corresponde al bloque Esquinita8.
En total, es necesario diseñar 60 secuencias para las esquinas: 3 x 8 para las tres esquinas superiores y 4 x 9 para las cuatro esquinas inferiores. Probablemente haya errores en el diseño de varias de estas secuencias: de hecho aparecieron varios durante los ensayos que no he corregido: ha sido un trabajo que se ha repartido entre mucha gente y es fácil que se cuelen fallos. No es demasiado grave porque, en muchos casos, un vértice que se ha recolocado en una esquina errónea es finalmente colocada bien cuando le tocó el turno de procesar esta nueva esquina. Se aceptan correcciones en los comentarios de esta entrada.
Quizá sería mejor diseñar las 60 secuencias de la manera sistemática que nos propone el autor de esta página web. Básicamente se trata de poner el vértice con cara blanca en la cara inferior, concretamente bajo la esquina de debe ocupar, y, dependiendo de la orientación de este vértice, ejecutar una de tres secuencias posibles. No olvidemos que hay que reorientar después el cubo como estaba en el momento de identificar la esquina.
En este vídeo vemos cómo forma la cara blanca completamente ordenada (y si no se llega a caer el teléfono móvil, habríamos visto también cómo resolvía el cubo entero)
Ahora tenemos el cubo con la cara blanca completada boca abajo y con la cara amarilla hacia arriba para completarla. Pero de eso ya hablaremos en la siguiente entrada.
No obstante, antes hablaremos de como les fue al resto de prototipos: es evidente que todo lo mostrado se está usando para la versión For Mindstorm NXT 2.1 Education Base Set.
Sólo teníamos tres sensores de color para Mindstorm NXT y se usaron en el prototipo anterior. En el prototipo For Mindstorm NXT Home Edition pensaba utilizar sensores de luz que pudiesen medir niveles de gris. Así, a partir de unos valores prefijados con algo de tolerancia (estos sensores tienen su propia fuente de luz y no deberían depender demasiado de las condiciones de luz exterior), estos sensores identificarían los colores a partir de sus equivalentes en niveles de grises de 0 a 100. O, otra posibilidad, introducir una rutina inicial que asignara equivalencias colores-niveles de gris a partir del un vértice con tres colores y otro vértice con los otros tres colores, probando también las variaciones de los niveles de gris dependiendo de si se encuentran en la superficie superior, frontal o derecha y así, generar los valores máximos y mínimo de gris que asignaríamos a cada color.
Lamentablemente, a partir de la sesión 5, era evidente que el tiempo se nos echaba encima y que no había margen para estudiar las posibilidades antes comentadas. Este prototipo se desmontó y el grupo de trabajo se integró, a partir de la sesión 6 en otros grupos de trabajo.
El prototipo Tilted Twister, debido a lo bien que funcionaba (fallos en volteos aparte), estuvo un mes y medio sin tocarse más que para exhibirlo en ferias científicas y tecnológicas. Para cuando éstas terminaron, y debido al elevado margen de error en los movimientos de volteo y al poco tiempo fuera del programa (recreos y tardes de otros días lectivos) de que disponían los alumnos a estas alturas de curso para adaptarlo mecánicamente e informáticamente, se decidió desmontarlo a finales de mayo. La necesidad de hacerlo funcionar a partir de niveles de grises también pesó en su contra. Fue una lástima porque la sencillez del prototipo, y particularmente del mecanismo del sensor de color, lo hacían idóneo para la adaptación al 2x2x2. De todas formas, su grupo de trabajo llevaba ya tiempo integrado en otros grupos.
Tras completar la cara blanca, tenemos la cara amarilla incompleta hacia arriba. Es el momento de empezar la segunda etapa consistente en completar esta cara, pero sin que sus vértices estén ordenados. Todo esto, por supuesto, sin deshacer la cara blanca que tanto esfuerzo le ha costado a nuestro robot montar (y a nosotros programar).
Para ello fijémonos en la siguiente imagen:
Esta tabla nos muestra los ocho posibles casos que nos podemos encontrar cuando empecemos a estudiar la cara amarilla. Si la F nos señala la cara frontal del cubo, los cuatro cuadrados de cada dibujo nos muestran las cuatro caras superiores de los cuatro vértices: estas caras pueden ser la amarilla... O no serlo: en este caso se mostrarán de color gris y las "solapas" amarillas nos mostrarán la situación de la cara amarilla que se ofrecerían, llegado al momento, a los sensores que leen las caras frontal y derecha. Quede claro que el vértice que se ve abajo a la derecha en cada dibujo es el que se ofrece al sensor triple de colores.
Si consideremos que en cada vértice la cara amarilla puede estar en tres caras diferentes y que hay cuatro vértices, las combinaciones serían 3 elevado a cuatro, esto es... ¡81 combinaciones diferentes!. En realidad no son tantas: muchas no son mecánicamente posibles * (por ejemplo, en los ocho casos arriba mostrados ninguno tiene tres caras amarillas hacia arriba). Eso elimina muchas posibilidades dejándolas sólo en 27 casos reales. Por otra parte, estos 27 casos posibles, si los giramos en sentido horario 90º, 180º, o 270º, coinciden unos con otros: en realidad, a efectos de resolución, sólo son dignos de consideración los 8 casos mostrados.
Recordamos que se ha dicho aquí que la secuencia A es la que completa la cara amarilla aunque con los vértices desordenados. Dependiendo de cual de los ocho casos nos encontremos aplicaremos la secuencia A un número de veces diferentes. O no la aplicaremos, si nos encontráramos con el caso 8. En realidad, al aplicar la secuencia A vamos pasando de uno de los ochos casos a otro hasta completar un recorrido que debe terminar en el caso 8 como se muestra a continuación.
Dicho de otra manera, cada flecha roja en el esquema de abajo es una aplicación de la secuencia A. Pero, como veremos posteriormente, la cosa no es tan simple.
Veamos cómo se programa esto en el robot. Lo primero es crear una variable de nombre sumatrinaria: se trata del valor equivalente decimal que tendría un número en base 3 de cuatro dígitos. Para los que no entiendan esto útimo, nos referimos a un número de cuatro cifras donde cada una de estas cifras sólo pueden adoptar los valores 2, 1 y 0. Como ejemplos valdrían 2102 , 0112 , 1021, 2222 ó 0000. El valor decimal equivalente lo obtenemos si sumamos el resultado de multiplicar el primer dígito por 27 (3 al cubo), el segundo dígito multiplicado por 9 (3 al cuadrado), el tercer dígito por 3 (3 elevado a uno) y el cuarto dígito por 1 (3 elevado a cero). Así, el equivalente decimal de 2102 sería 2x27 + 1x9 + 0x3 + 2x1 = 65. La cifra más alta (2222) ofrecería un valor equivalente decimal de 80 y la más baja (0000) equivaldría a 0.
Empezamos asignándole a sumatrinaria el valor 0: constante 0 (maletín con candado) = variable sumatrinaria (maletín).
A continuación aparece el bloque personalizado suma 27. Si lo abrimos vemos en su interior:
Son los ya conocidos bloques personalizados Mesaderecha, Leeresquina y uno nuevo 0o1o2. Si abrimos este último vemos
En este bloque si, tras la lectura del sensor triple de colores, el color amarillo (valor 4) apareciera en la cara superior del vértice, la variable 210 valdría cero. Si aparece en la cara frontal, 210 valdrá 1. Y si el amarillo aparece en la cara derecha, 210 valdrá 2.
A continuación, multiplicamos 210 por 27 y se lo sumamos a sumatrinaria.
Si volvemos al programa principal 22jun, el siguiente bloque personalizado es Suma 9: es idéntico a suma 27 con la diferencia de que el valor de la variable 210 se multiplica por 9 antes de sumarse a sumatrinaria. Lo mismo podemos decir de Suma 3: la varialbe 210 se multiplica por 3 y se suma a sumatrinaria.
Por último, los bloques Mesaderecha, Leeresquina, 0o1o2 y Suma 1 (me olvidé de agruparlos en un solo bloque) nos aportan el último sumando para el cálculo de la variable sumatrinaria. Este me permitirá distinguir en cuál de los 8 casos se encuentra la cara amarilla del cubo.
Tras un nuevo bloque Mesaderecha, llegamos a un nuevo bloque personalizado: PresecA. Si lo abrimos, vemos...
Así, dependiendo del valor de sumatrinaria ejecutaremos una de 27 secuencias posibles. En la secuencia mostrada en la imagen superior, como resultado de que sumatrinaria valga 13, aparecerá un mensaje en pantalla indicando "Caso 3", le adjudicará a la nueva variable CasosecA el valor 3 y girará la bandeja dos veces hacia la izquierda.
Si hemos entendido lo que hemos hecho (y si no lo hemos entendido, no importa: se explica a continuación), podemos pensar que sería útil publicar aquí una tabla con los 27 valores posibles de sumatrinara, las equivalencias con los 8 casos posibles y los giros que hay que darle al cubo en consecuencia para que coincidan. Pero creo que es algo que se le puede pedir al alumnado. Por ejemplo:
el caso 1 se puede presentar de cuatro maneras distintas si, además, giramos su dibujo 90º, 180º ó 270º en sentido horario.
el caso 2 sólo puede presentarse de dos maneras: como se ve en la tabla primera o girado 90º.
el caso 8 sólo puede presentarse de una manera: no importa cómo lo giremos.
Si sacamos las 27 maneras en que pueden presentarse en total los 8 casos, podremos calcular los números correspondientes en base 3 y sus equivalentes decimales, además de los giros de bandeja necesarios para que se coloque como se ve en la tabla inicial, lo que tenemos es un bonito ejercicio para que lo hagan los alumnos.
Ahora es cuando explicamos lo que ha hecho el programa: tras el primer giro de la bandeja, esta cara superior de la esquina en estudio (la que se encuentra abajo a la derecha cada dibujo) con el color amarillo hacia arriba en el espacio: el primer sumando de sumatrinaria valdrá 0x27
A continuación, tras girar el cubo a la derecha, se ha encontrado que la cara amarilla está en la cara frontal. El segundo sumando valdrá 1x9
Tras volver a gira el cubo hacia la derecha, se ha encontrado que la cara amarilla se muestra en la cara frontal: el tercer sumando valdrá 1x3
Y tras el cuarto giro a la derecha,nuevamente la cara amarilla se encuentra en la cara frontal: el cuarto sumando valdrá 1x1.
Sumatrinaria valdrá 0+9+3+1 = 13 y volvemos a girarlo a la derecha dejándolo en la posición inicial.
En consecuencia, identificamos el caso como el 3 de los ocho casos posibles (variable CasesecA = 3) y lo reorientamos girándolo dos veces a la izquierda para que se quede con la orientacion mostrada en la primera tabla primera donde veíamos los ocho casos posibles de la cara amarilla.
En resumen, tras encargarse el bloque PrepsecA de identificar el caso y de girar el cubo para que la cara amarilla incompleta quede orientada como aparece en la tabla primera de esta entrada, el cubo está listo para aplicarle la secuencia A el número de veces que sea necesario. De esto se encarga el bloque personalizado SecAyMesaIq que viene a continuación. Si lo abrimos...
... vemos que si la variable CasosecA vale 3, le aplicamos una secuencia A. Tras los cual obtenemos un caso 6, pero girado 90º a la derecha:...
... Habrá que girarlo 90º a la izquierda para tener el aspecto de la tabla primera.
Si aplicamos una nueva secuencia A, mostrará un caso 4...
...que necesitará también ser girado a la izquierda para ofrecer el ángulo que tiene en la primera tabla
A continuación, tras otra secuencia A llegamos a un caso 7 también girado a la derecha:
Es necesario pues, otro giro a la izquierda.
Tras una última secuencia A, llegamos al caso 8: hemos completado la cara amarilla, pero con los vértices desordenados.
Por eso decíamos que la cosa no es tan simple como se muestra en este gráfico.
Hay que clarificar cuando es necesario aplicar estos giros a la izquierda entre un caso y otro para reorientar la cara amarilla de acuerdo a la tabla primera. Son sólo tres casos:
en la transición de 3 a 6
en la transición de 6 a 4
en la transición de 4 a 7
Así, éstas son las tareas necesarias dependiendo del caso que nos encontremos
Caso 1: Secuencia A + Secuencia A
Caso 2: Secuencia A + Secuencia A + Secuencia A
Caso 3: Secuencia A+ Mesaizquierda + Secuencia A + Mesaizquierda + Secuencia A + Mesaizquierd + Secuencia A
Caso 4: Secuencia A + Mesaizquierda + Secuencia A
Caso 5: Secuencia A + Secuencia A + Mesaizquierda + Secuencia A + Mesaizquierda + Secuencia A
Caso 6: Secuencia A + Mesa Izquierda + Secuencia A + Mesa Izquierda + Secuencia A
Caso 7: Secuencia A
Caso 8: mensaje en pantalla "Secuencia A innecesaria".
Lo que la secuencia A hace realmente es
- no afectar a la cara contraria
- intercambiar la posicion de las piezas situadas en la 1ª y 3ª esquina, dándole un giro en sentido antihorario a la que ocupará la esquina 1ª
- intercambiar la posición de las piezas situadas en la 2ª y 4ª esquina, dándole un giro en sentido horario a la que ocupará la esquina 4ª.
Ya tenemos el cubo con la cara superior blanca completada y ordenada y la cara opuesta amarilla completada sin ordenar. En la siguiente sesión veremos cómo ordenar esta cara y como cuadrar las dos caras para tener el cubo completamente resuelto.
*Salvo que desmontemos el cubo y lo montemos en una configuración imposible a caso hecho.