Curs per a professors d’Introducció a LEGO® Mindstorms NXT i EV3
(versió 4.6)
La següent unitat didàctica explora les estratègies més importants, a l’hora d’escriure un programa informàtic en el software LEGO Mindstorms NXT i EV3, per controlar el seu flux de decisions, especialment entre sensors i actuadors. És molt útil sistematitzar els patrons de disseny estàndard creant un glossari de les solucions de programació més comuns per resoldre problemes ad hoc específics. Disposar d’una llista de necessitats i restriccions estalvia molt de temps i ajuda a entendre millor, analitzar i organitzar el codi de programació per obtenir la millor solució.
Aquesta unitat didàctica està inspirada en els manuals de curs LabVIEW Core 1 i Core 2.
Probablement la forma més senzilla de fer que un robot realitzi determinades accions és la de deixar caure els diferents blocs d’acció dins la interfície de programació, per exemple per controlar els motors, un després de l’altre, d’esquerra a dreta i just després del bloc “Inici”, d’acord amb la seqüència de les accions que volem que realitzi el robot. A mida que deixem caure els blocs dins la interfície de programació, aquests es connecten entre sí assegurant que les accions es produiran seqüencialment, i executant un bloc a la vegada i després de completar el bloc anterior, fins el final del programa. Això s’anomena la arquitectura del patró de disseny simple.
La Unitat 2 “Motors, desplaçaments i girs: el control precís de la distància recorreguda” mostra exemples de programació estrictament seqüencial.
Una mica de teoria
La seqüència de blocs de programació s’anomena “biga de seqüència” (“sequence beam” en anglès) i la interfície de programació NXT fa referència explícita a una biga de LEGO Technic, tal com mostra la imatge següent.
Biga de seqüència explícita en NXT
Per tal de fer explícita la biga de seqüència en EV3 cal només fer clic en el connector del botó dret de qualsevol bloc i el bloc situat a la seva dreta es mourà cap a la dreta fent visible la biga de seqüència. Una biga de seqüència és simplement un cable de dades (o data wire) que assegura que els blocs s’executin seqüencialment d’esquerra a dreta. Sense la biga de seqüència tots els blocs s’executaran a l’hora o sense determinar l’ordre d’execució.
Fent explícita la biga de seqüència en EV3
Generalment la majoria de programes es poden dissenyar seqüencialment, i això és molt pràctic perquè tendim a pensar de forma seqüencial, encara que sovint els events no succeeixen seqüencialment. Què passarà si algunes accions s’han de repetir? Què passarà si algunes accions s’han de realitzar però no sabem quan o el seu ordre d’execució? Què passarà si algunes accions s’han de realitzar sota condicions específiques diferents? Què passa si hem d’aturar el programa en una circumstància molt concreta?
Per exemple, imaginem-nos un robot que va recte però que ha de sortejar obstacles i fer un xiulet en trobar qualsevol línia i sobrepassar-la, fins que la línia sigui vermella on cal que s’aturi. No sabem si l’obstacle estarà abans o després de la intersecció i quants obstacles es trobarà el robot. Per tant, com podem programar el robot utilitzant estrictament un patró seqüencial? No podem, a menys que sapiguem exactament quants obstacles i línies conté el repte i en quin ordre estan disposats. Si només un obstacle o una línia es canvia el programa deixarà de funcionar. Cal utilitzar una arquitectura de patró de programació més complexa.
Quan cal executar una sèrie d’accions que es repeteixen en el temps seguint un patró específic, cal una estructura més complexa que el patró de disseny simple. Cal introduir un bucle en el que s’anomenada arquitectura del patró de disseny general. En l’arquitectura del patró de disseny general, el programa comença generalment amb algunes accions inicials, un bucle que conté el programa principal, i algunes accions de tancament abans del final del programa. Curiosament, moltes vegades el programa principal del bucle és només un simple programa seqüencial, però si necessitem executar tasques més complexes, el programa principal pot ser molt més complex que això. Les imatges següents mostren la arquitectura del patró de disseny general.
Arquitectura del patró de disseny general en NXT
Arquitectura del patró de disseny general en EV3
Amb el patró de disseny general podem repetir fàcilment moltes accions a cada iteració del bucle, inclús seqüencialment, o establint un ordre o prioritat encara que no sapiguem com succeiran en la realitat i durant l’execució del programa. Per exemple, en l’exemple anterior, podem assumir que, a cada iteració del bucle, el robot primer haurà de comprovar l’obstacle i si no hi ha cap obstacle, comprovar la línia i xiular si no és vermella i continuar, o aturar-se si és vermella i sortir del bucle. Totes aquestes tres accions s’executaran molt ràpidament i per tant, podem pensar-les de forma iterativa. El pensament iteratiu no és sempre obvi i intuïtiu i cal que els estudiants l’aprenguin. A més, quan varies accions es repeteixen indefinidament, la iteració es pot complicar amb la recursivitat. El pensament recursiu és una mica més complex que el pensament iteratiu. En el nostre cas tenim diverses condicions i la recursió ens permet passar sistemàticament per totes les condicions possibles i trobar la que cal executar per dur a terme les accions adequades.
En el nostre exemple podem escriure el codi que es mostra en l’esquema de programa següent.
Programació de bucle iterativa i recursiva en NXT
Programació de bucle iterativa i recursiva en EV3
Cal que els estudiants entenguin que el bucle s’executa tan ràpidament que les accions del programa principal –en la branca final de les bifurcacions (o “switches”) niuades– només s’executaran quan no es compleixin cap de les altres condicions en la mateixa iteració del bucle. A més, cal també tenir en compte que encara que en la majoria de casos canviar l’ordre seqüencial de les condicions recursives no afectarà el comportament del robot, aquest pot no ser sempre el cas.
Al final de la Unitat 3 “Sensors, condicions i bucles: la presa de decisions” apareix el primer exemple de programació de bucle amb el patró de disseny general. La Unitat 5 “Bifurcacions i bucles avançats: lògica de desplaçament i presa de decisions en funció d’una combinació de sensors” conté altres exemples de programació de bucle i introdueix el rastrejador simple de dues passes que al final es barreja amb la programació seqüencial. La Unitat 6 “A l’interior d’un rastrejador: registre de dades i experiments” conté exemples amb accions d’inicialització i finalització que il·lustren clarament aquests conceptes (inicialitzant i tancant variables i fitxers, i aturant els motors en sortir del bucle).
Què passarà si necessitem executar al mateix temps diferents accions repetides però a velocitats d’execució diferents? No és suficient desdoblar la biga de seqüència dins del mateix bucle perquè el bucle principal no es repetirà fins que finalitzi la seqüència desdoblada més llarga! La solució és executar bucles diferents en paral·lel.
Imaginem que en el nostre exemple, a més de totes les accions, volem que el robot bellugui al mateix temps una mà en funció d’un comportament específic. Clarament aquestes accions de la mà necessiten executar-se independentment i a una velocitat molt diferent a la del programa principal del robot. La única forma que ho podem aconseguir és executant al mateix temps dos bucles paral·lels, un pel programa principal i un altre per la mà. La arquitectura del patró de disseny de bucles paral·lels és una altra estratègia bàsica de programació que permet controlar simultàniament diferents tasques independents. Les imatges següents mostren els elements bàsics de l’arquitectura del patró de disseny de bucles paral·lels.
Arquitectura del patró de disseny de bucles paral·lels en NXT
Arquitectura del patró de disseny de bucles paral·lels en EV3
Però ara el problema és el següent: com podem controlar, coordinar i comunicar els diferents bucles del patró de disseny de bucles paral·lels? Podem utilitzar cables de dades? La resposta és de cap manera, perquè els cables de dades (o “data wires”) no permeten que els bucles s’executin en paral·lel. De fet, un bloc connectat a un cable de dades no s’executarà fins que el bloc connectat a l’esquerra d’aquest cable s’hagi executat. Aquesta és la raó per la qual utilitzem la biga de seqüència que és un cable de dades especial que assegura l’execució seqüencial dels blocs del programa. La resposta és: cal utilitzar variables.
Potser ja us heu adonat en l’exemple previ, que podríem necessitar coordinar el comportament de la mà amb les accions del bucle principal, o només aturar el bucle de la mà quan el robot troba la línia vermella. Com podem realitzar aquesta comunicació entre el bucle del programa principal, anomenat bucle mestre, i el nostre bucle de la mà, anomenat bucle esclau? Cal utilitzar una variable que el bucle principal establirà a Veritat (True) just abans de la seva sortida i que serà itrativament llegida pel bucle esclau causant la seva sortida quan sigui Veritat. Alternativament en EV3 podem utilitzar el Bloc Interrupció (Interrupt) que es cridarà pels dos bucles dins del bucle mestre per aturar el programa. En el nostre exemple, els blocs interrupció es cridaran quan es detecti la línia vermella dins del bucle mestre.
Arquitectura del patró de disseny mestre i esclau amb només condició de sortida en NXT
Arquitectura del patró de disseny mestre i esclau amb només condició de sortida en EV3
En el cas general, la arquitectura del patró de disseny mestre i esclau conté varis bucles paral·lels funcionant o executant tasques a velocitats diferents. Un bucle actúa com a mestre i la resta com a esclaus. El bucle mestre controla tots els bucles esclaus i es comunica amb ells mitjançant variables. És important que només un bucle mestre estableixi les variables per evitar contradiccions d’estat de les variables, anomenades condicions de carrera, que sovint poden ser difícils de debugar (o corregir) i de trobar dins del codi. Una condició de carrera pot ocórrer quan diferents parts del programa intenten establir les variables al mateix temps.
Arquitectura del patró de disseny mestre i esclau en NXT
Arquitectura del patró de disseny mestre i esclau en EV3
Potser us heu adonat que un problema de l’arquitectura del patró de disseny mestre i esclau és el fet que si la velocitat d’execució dels bucles esclaus és més lenta que la del bucle mestre alguns dels estats de la variable es poden perdre durant l’execució del programa. Per tant, en temps de disseny hem d’estar molt al tanto d’aquest problema.
Considerem l’exemple següent: imaginem-nos que volem construir un sensor de proximitat de cotxe per un robot. Hem d’implementar un xiulet en funció de la proximitat d’un obstacle de tal manera que quan més proper estigui l’obstacle més ràpidament soni el xiulet. Com podem programar aquesta funcionalitat? Clarament la repetició del xiulet ha de ser proporcional a la proximitat de l’obstacle. A més, mentre el robot executa el seu programa principal, la funció de proximitat del xiulet haurà d’executar-se en paral·lel i a la seva pròpia velocitat. Donat que el programa principal llegeix o bé un sensor ultrasònic o bé un d’infrarojos mesurant proximitat, la millor solució és establir una variable numèrica amb la distància, en el programa principal dins del bucle mestre, i llegir aquesta variable en el bucle de proximitat, el bucle esclau, tal com es mostra a continuació.
Implementació d’un sensor de proximitat d’obstacle en NXT
Implementació d’un sensor de proximitat d’obstacle en EV3
En aquest exemple, el programa principal llegeix la distància de l’obstacle amb un sensor ultrasònic o d’infrarojos de proximitat, per tant és molt senzill, més endavant l’afegirem al nostre exemple de robot anterior. La pregunta és: funcionarà aquest programa? La resposta és: aparentment sí i molt bé! Si analitzem els dos bucles què podem dir respecte de la seva velocitat d’execució? Encara que la lectura d’un sensor necessita un cert temps, com en el bucle mestre d’aquest exemple, tocar un so i esperar a repetir-lo, en el bucle esclau, son probablement molt més llargs d’executar. Per tant, perquè sembla que el programa funcioni tan bé? Encara que el bucle esclau perdi alguns dels valors de distància establerts pel bucle mestre, perquè probablement s’executi més lentament, en qualsevol cas els xiulets semblen ser bastant proporcionals a la distància de l’obstacle. En aquest cas, no és crucial que la velocitat d’execució del bucle esclau sigui més lenta que la del mestre perquè el bucle esclau eventualment es posarà al dia, excepte si el moviment de l’obstacle o del robot no son linials, o son massa ràpids.
Intentem ara integrar la funció anterior de xiulet en el nostre exemple del robot principal, tal com es mostra seguidament.
Implementació d’un sensor de proximitat dins l’exemple principal del robot en NXT
Implementació d’un sensor de proximitat dins l’exemple principal del robot en EV3
Com es pot veure en el codi anterior, aquesta vegada el bucle mestre pot trigar més temps en executar-se que el bucle esclau, especialment quan s’executin les branques dels bucles “Sort obstacle” i “Line beep and continue”. Probablement la branca del programa principal “Main program actions” sigui més ràpida d’executar que la resta, i potser fins i tot més ràpida que el bucle esclau, si només arrenca un motor i conté un algoritme de seguiment o rastreig de línia.
Què passarà amb el xiulet de proximitat quan el robot trobi un obstacle i la distància sigui lo suficientment petita com per arrencar la branca “Sort obstacle”? Durant quan de temps sonarà el xiulet? Donat que la variable s’establirà a una distància entre el llindar per sortejar l’obstacle i el de fer sonar el xiulet, el xiulet sonarà proporcionalment a aquesta distància fins superar l’obstacle, la qual cosa vol dir que sonarà fins que hagi finalitzat l’execució de la seva branca del bucle mestre i la següent iteració del bucle comenci de nou. Si volem evitar el xiulet, perquè el robot ja sap que ha de sortejar l’obstacle, què podem fer? La resposta és, just abans de sortejar l’obstacle, cal establir la variable a un nombre més gran, tal com es fa a l’inici del programa, per evitar un xiulet inicial resultat d’un valor per defecte de “0” de la variable numèrica, si no el definim a l’inici.
La Unitat 10 “Encendre o no encendre la llum: com utilitzar la làmpada històrica en EV3” té exemples molt interessants de com utilitzar el patró de disseny mestre i esclau i adreça molt específicament el problema de com sincronitzar el parpelleig de les làmpades sincronitzant els bucles de cada làmpada.
La Unitat 12 “Com conmutar un motor on/off amb un sensor de contacte” mostra altres exemples de com utilitzar el patró de disseny mestre i esclau.
Tal com hem vist en l’estil de programació seqüencial, els blocs amb decisions i accions es programen seqüencialment i seguint un ordre específic, per exemple, seguint l’ordre en que el robot es troba les interseccions de línia, seguint un ordre de lectura específic dels sensors del robot, i finalment realitzant accions en funció d’una seqüència específica de decisions. Hem vist que en Mindstorms NXT i en EV3 la biga o cable de seqüència estableix l’ordre d’execució dels blocs del programa. La programació seqüencial és un dels estils de programació més comuns i sovint més evidents, perquè si el programa no és molt complex, es pot fer sense planificació, però no sempre és l’estil més eficient, més flexible o més comprensible a llarg termini.
Per exemple:
- Què passa si hem de canviar l’ordre de les interseccions o l’ordre de la seqüència?
- Què passa si hem de repetir varies vegades un o varis components de la seqüència, per exemple, repetir varis girs cap a un costat, o saltar varies línies de colors diferents del recorregut?
- Què passa si hem d’executar una part de la seqüència només quan es compleix una condició determinada, per exemple, si hem d’afegir un sensor ultrasònic en un costat per fer que el robot trïi el costat adequat de l’obstacle per sortejar-lo o esquivar-lo, o seguir una paret quan no hi línia de recorregut?
- Què passa si volem aturar immediatament l’execució del programa quan es compleix una condició específica i no volem esperar a finalitzar la resta de la seqüència?
Com podem millorar la programació seqüencial per fer-la més funcional, més compacta i fins i tot més comprensible? La resposta és: utilitzant l’arquitectura del patró de disseny de màquina d’estats.
Una mica de teoria
El model de programació de la màquina d’estats és un model molt comú i útil que permet implementar qualsevol algoritme relativament complex que es pugui representar mitjançant un diagrama de flux de dades amb els seus processos de presa de decisions i les seves accions resultants.
Una màquina d’estats (o màquina d’estats finits) es basa en una sèrie d’estats amb una funció de transició que indica quin serà el següent estat a realitzar. Cada estat conté una acció a realitzar i un codi de transició que crida el següent estat. Sovint els programes o aplicacions requereixen un estat d’inicialització, seguit d’un estat predeterminat –on per exemple, es poden llegir els sensors per prendre decisions i cridar els altres estats o realitzar diferents accions– i finalment, pot tenir un estat de tancament per realitzar accions de neteja abans de finalitzar el programa.
En Mindstorms NXT i en EV3 podem crear el patró de disseny de màquina d’estats com a modificació del patró de disseny general afegint un estructura de casos al seu bucle i utilitzant una variable. En NXT o EV3 el patró de disseny de màquina d’estats té un bucle, una estructura de casos o bifurcació múltiple –on cada cas representa un estat–, una variable per emmagatzemar la informació de transició entre estats a cada iteració del bucle, un codi de funcionalitat per a cada estat i un codi de transició que permet determinar el següent estat del programa. Per sortir del bucle, en NXT cal utilitzar un bucle lògic i una segona variable lògica, inicialitzada a Fals, que només es posarà a valor Veritat o “True” en l’estat de finalització per sortir del programa. En EV3 el bucle pot ser il·limitat i només cal afegir el bloc Interrompre Bucle (“Loop Interrupt”) en l’estat de finalització. Finalment, podem definir el cas per defecte de la màquina d’estats al cas d’inicialització. En l’exemple següent l’estructura de la màquina d’estats té 4 estats representats per les 4 pestanyes de l’estructura de casos: “Inicialització”, “Estat 1”, “Estat 2” i “Finalització”.
Elements bàsics del patró de disseny de màquina d’estats en NXT
Elements bàsics del patró de disseny de màquina d’estats en EV3
Com podem implementar les transicions d’una màquina d’estats? Hi ha tres tipus diferents de control de transicions:
· El més senzill és la transició de cas individual, que pot ser útil com a transició per defecte, per exemple. El contingut més simple d’aquest codi és una variable apuntant a les accions per defecte o configuració.
· El següent control de transició és la transició entre dos estats. El contingut d’aquesta transició és un codi de funcionalitat basat en una simple bifurcació o “switch”. El control de transició entre dos estats és útil si només tenim dos casos possibles, però és difícil d’adaptar a canvis futurs i limita l’escalablitat del codi.
· El tercer control de transició és la transició entre dos o més estats. La solució més adequada és utilitzar una bifurcació múltiple o estructura de casos. Un avantatge de l’estructura de casos és que autodocumenta el codi fent-lo molt llegible. Cada cas correspon a un valor de la variable de la maquina d’estats. També és molt escalable i, mentre creix l’aplicació, és molt senzill afegir transicions a un estat específic afegint més casos a aquest estat de l’estructura de casos. Un inconvenient de l’estructura de casos és que no es pot veure tot el codi de la funcionalitat de transició de cop, tal com veurem en els propers exemples.
Si tornem a l’exemple del nostre robot, com podem reescriure el codi utilitzant el patró de disseny de la màquina d’estats? Abans d’escriure el codi del programa, dibuixem primer el Diagrama de Flux de Dades del nostre exemple. Normalment, dibuixar el diagrama de flux de dades d’un programa abans de començar la seva codificació és molt útil perquè ajuda a entendre el problema i estalvia molt temps de disseny del programa i de correcció d’errors o de “debugar”.
Una mica de teoria
Normalment quan es programa no es comença directament escrivint el codi, cal una mínima planificació, especialment si el programa és una mica complex. Un diagrama de flux de dades (DFD) és una representació gràfica del flux de dades a través d’un sistema d’informació, que també es pot utilitzar per la visualització del processament de dades. En el nostre cas el podem utilitzar per visualitzar i diferenciar gràficament les parts del programa que llegeixen dades, les parts on es prenen les decisions a partir de la lectura de les dades, les parts que realitzen les accions segons cada decisió i el flux de dades del programa que connecta totes les parts anteriors. Si un diagrama de flux de dades està ben fet la programació posterior es simplifica molt.
Els diagrames de flux de dades es poden representar de varies formes i amb més o menys detall. En el nostre cas, representarem les accions –i/o sub-programes, que es poden també representar amb sub-DFDs– mitjançant un rectangle, les decisions amb un diamant i el flux de dades entre decisions i accions amb una fletxa. Cada cop que es pren una decisió informarem en la fletxa que surt del diamant si la decisió correspon a un “sí” o a un “no”.
La imatge següent mostra el diagrama de flux de dades del nostre exemple de robot.
Diagrama de flux de dades del nostre exemple de robot
Les següents imatges mostren el programa del nostre exemple de robot utilitzant el patró de disseny de màquina d’estats amb un control de transició amb bifurcació múltiple.
Cas “ReadSensors” del programa de l’exemple del robot utilitzant el patró de disseny
de màquina d’estats amb un control de transició amb bifurcació múltiple en NXT
Resta de casos del programa de l’exemple de robot utilitzant el patró de disseny de màquina d’estats en EV3
Cas “ReadSensors” del programa de l’exemple del robot utilitzant el patró de disseny
de màquina d’estats amb un control de transició amb bifurcació múltiple en EV3
Resta de casos del programa de l’exemple de robot utilitzant el patró de disseny de màquina d’estats en EV3
La primera cosa important a veure en el codi d’exemple anterior és que el primer cas “ReadSensors” encapsula totes les decisions del programa de la màquina d’estats, i que està programat de forma seqüencial niant tres bifurcacions. Això és molt útil perquè podem entendre fàcilment el flux de decisions. Les bifurcacions associades als sensors representen el codi de funcionalitat i les variables el codi de transició. Cal veure com cada variable apunta a un cas d’”acció” diferent. La resta de casos representen les diferents accions de la màquina d’estats. En aquests casos, el codi de funcionalitat està omès (està només representat per un text) i el codi de transició està representat per una variable que apunta a “ReadSensors” en tots els casos, excepte en el cas “Exit”.
Suggeriment: Com a bona pràctica de programació, cal no barrejar mai decisions amb accions en un mateix estat, cal utilizar diferents estats per separar-los. Això és especialment útil quan diferents decisions desencadenen mateixes accions perquè evita la repetició de codi.
Hi ha alguna limitació en el codi anterior? Si volem modificar el programa afegint més transicions o si volem canviar l’ordre de decisions, donat que el cas de presa de decisions “ReadSensors” està programat seqüencialment, haurem de modificar-lo afegint més branques de bifurcació o haurem de canviar-lo completament per alterar la prioritat de decisions, tal com hem apuntat anteriorment. Està clar que també haurem d’afegir les corresponents accions a la màquina d’estats. Hi ha alguna estratègia per tal de minimitzar els canvis a l’hora d’afegir funcionalitats? La solució és dividir el cas de presa de decisions en funció de totes les decisions a prendre, tal com es mostra a continuació.
Alternativa més flexible del programa d’exemple del robot utilitzant el patró de disseny
de màquina d’estats amb control de transició amb bifurcacions en NXT
Alternativa més flexible del programa d’exemple del robot utilitzant el patró de disseny
de màquina d’estats amb control de transició amb bifurcacions en EV3
Tal com mostra aquesta alternativa, que utilitza la transició entre dos estats com a estratègia de control de transició del patró de disseny de màquina d’estats pel nostre exemple, es creen tres casos que contenen una bifurcació, una per a cada decisió de sensor. Els casos d’acció són idèntics als anteriors, excepte pel que fa les variables que es modifiquen en conseqüència (de fet criden el cas “IsObstacle” en comptes de “ReadSensors”). Encara que aquest programa és potser una mica més complex d’entendre, és però molt més flexible. Per exemple, només cal canviar les variables per canviar l’ordre de prioritat de decisions, o si cal afegir més transicions o funcionalitats, només s’han d’afegir les decisions i les accions corresponents sense haver de modificar la resta del codi.
Un exemple simple de transició entre més de dos casos pot ser l’estructura de casos del sensor de color amb més de dos colors. Cada cas contindrà la variable apuntant a la transició específica per aquest cas. En una situació més general, el codi de funcionalitat retornarà un valor que estarà connectat a una estructura de casos. Com exemple, podeu veure l’estat d’inicialització, o també l’estat de gestió d’interseccions, de la màquina d’estats pel seguidor de línies o rastrejador de la Unitat 9 “De la programació seqüencial a la màquina d’estat: el cas del rastrejador simple de quatre passes amb dos sensors de llum o de color”. En aquest exemple el codi de transició té la variable connectada a una estructura de quatre casos en ambdós estats.
Finalment, podem barrejar totes les arquitectures dels patrons de disseny per satisfer millor les nostres necessitats de programació. El poder d’aquest glosari és permetre la simplificació i estructuració del procés de disseny de la programació ajudant a detectar les funcionalitats que necessita el programa abans de començar a codificar-lo.
Un problema del patró de disseny de màquina d’estats és que cal evitar establir dos estats al mateix temps, el que també s’anomena condició de carrera, per evitar perdre l’execució d’alguns estats encapsulats per la variable, per exemple, quan es barreja aquest patró amb el bucle paral·lel o el patró de disseny mestre i esclau. Evitar estats pot generar errors molt difícils de debugar o corregir perquè poden ser molt difícils de reproduir.
Coneixements adquirits: Amb aquesta unitat didàctica els alumnes aprendran a programar de formes més sofisticades reconeixent i sistematitzant les necessitats dels seus programes. També aprendran a dibuixar diagrames de flux de dades per planificar abans de codificar, i a barrejar les diferents tècniques i arquitectures dels patrons de disseny per tal d’escriure millors programes, més simples, més compactes, fàcils de debugar o corregir i més eficients.
Podeu també trobar aquesta unitat didàctica a la pàgina web de legoengineering.com.