Curs per a professors d’Introducció a LEGO® Mindstorms NXT i EV3

(versió 4.5)

 

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 aquesta unitat didàctica veurem en detall el funcionament del seguidor de línies o rastrejador simple de quatre passes amb dos sensors de llum o de color, veurem com sistematitzar el disseny del seu algoritme, analitzarem la similitud i diferència fonamental amb el rastrejador simple de 3 passes amb un sensor de llum o de color, veurem com podem fer que el robot prengui decisions a cada intersecció de línia de forma seqüencial, aprendrem a dissenyar diagrames de flux de dades per expressar gràficament el funcionament d’un programa, i finalment veurem com programar una màquina d’estats per aquest rastrejador i les avantatges que suposa respecte de la programació seqüencial.

                                                                                        

Unitat 9 exercici 1: Programació seqüencial del seguidor de línies o rastrejador simple de 4 passes amb dos sensors de llum o de color.

 

Podem començar preguntant als alumnes com creuen que caldria procedir des del punt de vista conceptual, com creuen que caldria dissenyar l’algoritme? Cal observar que els dos sensors de llum o de color estan disposats a cada banda de la línia negra que cal seguir, tal com mostren les següents imatges, on podem observar que afegir-los al robot és trivial.

 

 

 

Podem ajudar els alumnes fent un petit dibuix a la pissarra i preguntant:

  1. Què cal que faci el robot quan tots dos sensors detecten (o “veuen”) el color blanc? En fer el dibuix és obvi que el robot ha d’anar recte endavant.
  2. I quan el de l’esquerra detecta negre i el de la dreta blanc? Girar cap a l’esquerra.
  3. Quan el de la dreta detecta negre i el de l’esquerra blanc? Girar cap a la dreta.
  4. Finalment i abans de dibuixar la intersecció podem preguntar en quina situació els dos sensors del robot detectaran negre? La resposta és en una intersecció.

 

 

Una altra forma més sistemàtica, però menys gràfica, de trobar totes les combinacions possibles de les lectures dels dos sensors de llum o de color és confeccionar una taula de valors.

 

Valors del sensor de llum o de color

 

Sensor 1

(esquerra)

Sensor 2

(dreta)

Acció del robot

N = Negre

 

N

N

Intersecció, aturar el robot?

B = Blanc

 

N

B

Gir a l’esquerra

 

 

B

N

Gir a la dreta

 

 

B

B

Anar recte

 

 

(port 2)

(port 3)

 

 

Podem preguntar quantes opcions tindríem amb 3 sensors de llum o de color. La resposta és 8 que equival a 23. A nivell general tindríem XY, on X és el número de possibles lectures –en el nostre cas 2, és a dir, veritat si la lectura està per sota del llindar entre el blanc i el negre i fals si està per sobre– i on Y equival al número de sensors, en aquest exemple 3 sensors.

 

Seguidament cal preguntar com programar aquest rastrejador de línies? Podem ajudar els alumnes preguntant quantes opcions diferents tenim? La resposta és 4, per tant, necessitarem una bifurcació amb 4 branques. Com podem obtenir aquestes 4 branques? Doncs niant 3 bifurcacions. És important anar fent un dibuix a la pissarra del pseudo-codi per ajudar als alumnes a visualitzar l’algoritme i anar preguntant què cal dibuixar a mida que es fa el dibuix. Un punt important és que entenguin que la primera bifurcació ha d’anar associada al primer sensor de llum o de color i les dues altres al segon per tal d’obtenir els 4 casos possibles, tal com mostra la imatge següent.

 

 

Arribat aquest punt la programació és trivial, només cal implementar el pseudo-codi anterior. Recordem que la roda dreta està connectada al motor del port B i l’esquerra al del port C, i que el sensor de llum o de color de l’esquerra està associat al port 2 (cal desconnectar el sensor de so) i el de la dreta al port 3. També caldrà fer algunes proves per comprovar el llindar de llum o de color entre el color blanc del fons del tauler i el color negre de la línia de rastreig. En el programari Mindstorms NXT el valor per defecte de 50% del sensor de llum funciona en la majoria de casos i en el programari EV3 amb el sensor de color configurat per llegir la llum reflectida caldrà baixar-lo a 25%, per exemple. Finalment, també caldrà ajustar la potència dels motors per a que sigui inferior a 50% i fer que el robot tingui un comportament suau en seguir la línia, en el programari EV3 i amb els motors EV3 aquest valor ha de ser una mica inferior al de NXT.

 

Crear un nou programa, per exemple “u9ex1.rbt”, tal com mostra la imatge següent.

 

Seguidor de línies o rastrejador simple de 4 passes amb 2 sensors de llum (NXT)

 

Seguidor de línies o rastrejador simple de 4 passes amb 2 sensors de color (EV3)

 

Tal com hem comentat anteriorment, en ambdós programes podem veure que encara que els blocs motor estiguin un darrera l’altre –per arrancar-los o frenar-los tots dos a l’hora o per frenar-ne un i arrancar l’altre–, l’execució del programa és tan ràpida que és com si ho fessin a l’hora. En el cas del programari EV3, existeix el bloc “Moure Tanc” (o “Move Tank”) que ens permet controlar els 2 motors a l’hora amb un sol bloc. La imatge següent mostra com podem simplificar el programa anterior mitjançant aquest bloc.

 

Seguidor de línies o rastrejador simple de 4 passes amb 2 sensors de color

utilitzant el bloc “Moure Tanc” (EV3)

 

Suggeriment: En utilitzar el bloc “Mover Tanque” (o “Move Tank”) cal tenir cura en configurar els ports dels motors del bloc d’esquerra a dreta de la mateixa forma en que estan disposats els motors en el robot mirant cap endavant (“Port Motor Esquerra + Port Motor Dreta”). En el nostre exemple cal configurar els motors “C + B” (i no “B + C”) donat que el port C correspon al motor de l’esquerra i el B al de la dreta. També podem observar que per frenar un motor cal configurar la seva potència a 0.

 

Finalment, si el robot executa el programari, quin comportament tindrà el robot? La resposta és que seguirà la línia fins la primera intersecció i un cop allí s’aturarà i no sortirà del bucle, és a dir, el programa s’executarà indefinidament (fins que se li acabin les bateries o que l’aturem). Per demostrar això, podem aixecar el robot i posar-lo una mica més enllà de la intersecció, amb la qual cosa el robot tornarà a seguir la línia fins la propera intersecció, etc.

 

Seguidament podem recordar l’algoritme del seguidor de línies o rastrejador simple de 3 passes amb un sol sensor de llum o de color i demanar als alumnes quina és la diferència fonamental amb el rastrejador anterior de 4 passes amb 2 sensors de llum o de color?

 

Seguidor de línies o rastrejador simple de 3 passes amb un sensor de llum (NXT)

 

Seguidor de línies o rastrejador simple de 3 passes amb un sensor de color (EV3)

 

Tal com hem vist anteriorment, cal fer proves per ajustar dos llindars suficientment apartats (pel mateix sensor de llum en NXT o de color en EV3) per a que el robot pugui anar recte en les rectes i no perdi la línia en les corbes.

 

Cal observar que el comportament dels algoritmes anteriors per seguir la línia amb un o dos sensors de llum o de color és quasi idèntic (potser és una mica més precís en el rastrejador de dos sensors de llum o de color) donat que tots dos algoritmes fan 3 passes. En el cas del rastrejador d’un sol sensor de llum o de color, el robot gira cap a un costat o cap a l’altre i va recte quan la intensitat de la llum reflectida detectada pel sensor de llum o de color està a prop del llindar entre el blanc i el negre, és a dir, quan el sensor de llum o de color “veu gris”. En el cas del robot amb dos sensors de llum o de color, el robot va recte quan els dos sensors detecten blanc, és a dir, quan la línia negra està just al mig dels dos sensors de llum o de color.

 

Per tant, la diferència fonamental és que el robot amb dos sensors de llum o de color és capaç de detectar les interseccions de línia!

 

Tornant a l’algoritme del rastrejador de dos sensors de llum o de color, ara podem preguntar què cal fer quan el robot detecta una intersecció? Amb els coneixements actuals que tenen els alumnes la resposta correcta és sortir del bucle!, per tal de decidir què fer en cada intersecció, és a dir, seguir recte, parar o girar cap a un costat de la intersecció o cap a l’altre. Alguns alumnes ja veuen que una altra solució és anar comptant les interseccions, però això ho veurem més endavant...

 

Aleshores, la pregunta és: com podem sortir del bucle? De forma general, quan utilitzem un bucle el problema sempre és com sortir-ne d’ell... La resposta és utilitzant una variable. Per això cal convertir el bucle en un bucle lògic i utilitzar una variable lògica per controlar la sortida del bucle en trobar la intersecció de línia.

 

Seguidor de línies o rastrejador simple de 4 passes amb 2 sensors de llum

amb control de sortida del bucle en detectar a una intersecció de línia (NXT)

 

Seguidor de línies o rastrejador simple de 4 passes amb 2 sensors de color

amb control de sortida del bucle en detectar a una intersecció de línia (EV3)

 

Si ens fixem en els codis anteriors, la variable lògica s’inicialitza a fals, és a dir, s’escriu amb valor fals abans d’entrar dins el bucle, i només s’escriu a veritat o “True” quan els sensors de llum o de color detecten el color negre per tal de que el robot surti del bucle. També podem observar que és just a la sortida del bucle quan els motors s’aturen. Això es podria haver fet dins la mateixa bifurcació, però com veurem més endavant, fer-ho fora dóna més flexibilitat.

 

Cal observar que la inicialització de la variable abans d’entrar en el bucle estalvia haver d’inserir la variable 3 vegades més en cadascuna de les altres 3 branques de les bifurcacions, però amb valor fals. A més, facilita la lectura i comprensió del programa.

 

Una mica de teoria

 

Alguns llenguatges de programació requereixen inicialitzar explícitament les variables, però aquest no és el cas de Mindstorms NXT-G o de EV3. És a dir, una variable lògica s’inicialitza per defecte al valor fals, una variable numèrica al valor 0 i una variable de text a la cadena buida, és a dir “”.

 

Finalment, el programari EV3 compta amb un bloc que permet “interrompre” o sortir d’un bucle, “Interrompre Bucle” (o “Loop Interrupt”), la qual cosa estalvia utilitzar una variable, tal com mostra la imatge següent. Cal observar que el bloc “Interrompre Bucle” ha de tenir el mateix nom que el bucle que es vol interrompre. Per defecte, els bucles es van numerant a mida que es van afegint al programa i el seu número es pot canviar per qualsevol nom. En el nostre exemple el bucle s’anomena “01” igual que el seu bloc interrompre bucle.

 

Seguidor de línies o rastrejador simple de 4 passes amb 2 sensors de color

amb control de sortida del bucle mitjançant un bloc “Interrompre Bucle” (EV3)

 

Suggeriment: És una molt bona pràctica inicialitzar sempre les variables que s’utilitzen per fer explícit el seu valor i fer el codi molt més intel·ligible. En EV3, si s’utilitza un bloc per interrompre el bucle cal tenir cura en posar-li el mateix nom del bucle que es vol interrompre. En el cas de programes llargs o complexes és recomanable anomenar els bucles de forma descriptiva per entendre millor el codi quan utilitzem un bloc per interrompre els bucles.

 

Seguidament podem fer un petit circuit amb interseccions i podem demanar als alumnes que programin el robot per a que a la primera intersecció el robot segueixi recte, a la segona giri cap a l’esquerra, a la tercera giri cap a la dreta i a la quarta que s’aturi el robot. La solució és molt fàcil, només cal copiar el codi anterior i programar el que cal fer en cada intersecció, és a dir, just després de la sortida de cada bucle.

 

 

 

Després de la primera intersecció els programes anteriors utilitzen un bloc Move en NXT i un bloc Move Tank en EV3 per fer que el robot vagi endavant 70 graus, el suficient per saltar la línia negra. A la segona intersecció el robot fa un gir sobre punt, en aquest cas sobre la roda C, per girar cap a l’esquerra. Veiem que amb una roda parada, si l’altre fa un gir equivalent a una rotació de motor, donada la geometria del robot, aquest fa exactament un quart de volta, justament el que necessitem per continuar seguint la línia. A la tercera fa un gir sobre l’altra roda per girar cap a la dreta, i a la quarta intersecció el robot s’atura. En aquest punt veiem la utilitat de no posar els blocs motor per frenar el robot dins la branca de la bifurcació corresponent a la detecció de la intersecció, això ens permet estalviar codi i encadenar els moviments del robot de forma més suau i sense frenades.

 

Malgrat que aquesta solució funciona perfectament, quin és el seu inconvenient? Que el programa és molt llarg, dit d’una altra manera, que el codi corresponent al rastrejador es duplica quatre vegades, o tantes vegades com interseccions a negociar. Això fa que si hem de fer un canvi en el programa del rastrejador, l’haurem de repetir quatre vegades en aquest cas, i a més, el programari ha de compilar o traduir al llenguatge de la CPU del robot, quatre vegades el mateix codi, la qual cosa el fa poc eficient i ocupa molt espai innecessari en la memòria del robot.

 

El següent pas és crear un subprograma o bloc d’usuari “rastrejador2s” pel codi corresponent al rastrejador que es duplica quatre vegades en els dos exemples anteriors.

 

 

 

Ara el programa és molt més eficient i fàcil d’entendre, i el codi corresponent al rastrejador només es compila o tradueix al llenguatge del robot una sola vegada. A més, si hem de fer un canvi en el subprograma o bloc d’usuari, només ens cal fer-lo en el programa original i quan salvem el canvi, aquest es propaga a totes les instàncies o insercions del mateix dins el programa principal.

 

Finalment, podem dissenyar un circuit més llarg i fer proves per tal de que el robot vagi prenent decisions a cada intersecció de línia d’una forma seqüencial, és a dir, seguint el flux o seqüència del recorregut del robot.

 

Coneixements adquirits: Els alumnes han aprés a dissenyar algoritmes de forma gràfica, amb pseudo-codis i de forma sistemàtica mitjançant taules de valors per a cada sensor. També han comparat els diferents algoritmes dels seguidors de línies o rastrejadors amb un sol sensor de llum o de color i amb dos sensors de llum o de color, i han vist una estratègia seqüencial per programar el robot rastrejador amb dos sensors de llum o de color per tal de prendre decisions a cada intersecció de línia. A més, els alumnes han vist la utilitat i l’eficiència dels subprogrames o blocs d’usuari per compactar el codi i fer-lo més comprensible i eficient, i han aprés a utilitzar variables per passar informació entre diferents blocs o parts d’un programa, especialment per sortir dels bucles mitjançant un control lògic en NXT (o amb un bloc “Interrompre Bucle” en EV3).

 

Exercici incremental 9: Arribar al final de la gàbia utilitzant un rastrejador simple amb dos sensors de llum o de color i compactant el codi amb un bloc d’usuari.

 

Abans de començar, podem copiar l’exercici incremental 8 anterior i posar-li un nom diferent, per tal de mantenir una còpia. Seguidament només haurem de substituir el bloc d’usuari “RastrejadorP” amb el codi anterior del subprograma del rastrejador amb dos sensors de llum o de color “rastrejador2s”. De qualsevol manera, necessitem 6 instàncies del bloc d’usuari del rastrejador simple i entre cada instància necessitem girar cap a l’esquerra, saltar la línia del mig del tauler, girar cap a la dreta, girar cap a la dreta, tornar a saltar la línia del mig del tauler i parar.

 

La imatge següent mostra el circuit de l’exercici incremental per arribar al final de la gàbia, on les fletxes mostren les accions que haurà de fer el robot. En negre els recorreguts rectes on el robot haurà de rastrejar la línia i en vermell les accions que haurà de fer el robot en arribar a cada intersecció de línia.

 

 

Suggeriment: Per fer que el robot detecti correctament les interseccions, cal que aquestes tinguin forma de creu (“+”). Si les derivacions al mig del tauler tenen forma de “T” aleshores caldrà afegir una mica de cinta per generar una creu i facilitar que els sensors de llum o de color les reconeguin. Pot ser que no calgui fer-ho, la qual cosa dependrà de la geometria del robot (distància dels sensors a l’eix de gir de les rodes i distància entre rodes) i de la velocitat dels motors per seguir la línia.

 

Una mica de teoria

 

L’estil de programació anterior és perfectament correcte, on els blocs i les decisions es programen de forma seqüencial seguint un ordre específic, per exemple, seguint l’ordre en que el robot es troba les interseccions, seguint un ordre específic de lectura dels diferents sensors del robot, i finalment realitzant accions en funció d’una seqüència específica de decisions. En Mindstorms NXT-G o 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, és a dir, 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 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 tercer sensor ultrasònic per fer que el robot sortegi o esquivi un obstacle al mig del 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?

 

Podem millorar la programació seqüencial del rastrejador simple de 4 passes amb 2 sensors de llum o de color i fer-la més funcional, més compacta i fins i tot més comprensible? La resposta és sí, utilitzant una màquina d’estats.

 

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 preses de decisions i 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 permet cridar 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-G i en EV3 podem crear una màquina d’estats amb 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 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 d’una màquina d’estats (NXT)

 

Elements bàsics d’una màquina d’estats (EV3)

 

Unitat 9 exercici 2: Construcció d’una màquina d’estats pel seguidor de línies o rastrejador simple de 4 passes amb dos sensors de llum o de color.

 

Podem començar per preguntar als alumnes quants estats creuen que haurà de tenir la màquina d’estats del rastrejador simple de 4 passes amb dos sensors de llum o de color. És molt probable que diguin 4 estats, un per a cada cas o passa del seguidor de línies, que correspon a cadascuna de les accions, és a dir, anar recte, girar cap a un costat o cap a l’altre o sortir del programa en trobar una intersecció de línia.

 

El primer punt que hem de tenir en compte per crear una màquina d’estats és separar les decisions de les accions que ha de realitzar el programa. D’aquesta manera hem de separar la lectura dels sensors de les accions que haurà de realitzar el rastrejador a cada iteració del bucle. Per tant, un primer estat, que podria ser l’estat d’inicialització, correspondrà a la lectura dels dos sensors de llum o de color que determinarà quin serà el següent estat a executar. Aquest següent estat contindrà l’acció que haurà de fer el robot, és a dir, el codi de funcionalitat, i cridarà un altre cop a l’estat d’inicialització per tornar a llegir els sensors, és a dir, el codi de transició. L’estat corresponent a quan el robot troba una intersecció de línia permet sortir del bucle, és a dir, del programa, tal com es mostra a continuació.

 

Crear un nou programa, per exemple “u9ex2.rbt”, tal com mostra la imatge següent.

 

Màquina d’estats pel seguidor de línies o rastrejador simple

de 4 passes amb 2 sensors de llum, estat d’inicialització (NXT)

 

 

Cas “rastre gir dreta”

 

 

Cas “rastre gir esquerra”

 

 

Cas “rastre interseccio”

 

Cas “rastre recte”

 

Màquina d’estats pel seguidor de línies o rastrejador simple

de 4 passes amb 2 sensors de color, estat d’inicialització (EV3)

 

 

Cas “rastre gir dreta”

 

 

Cas “rastre gir esquerra”

 

 

Cas “rastre interseccio”

 

Cas “rastre recte”

 

El primer punt que podem observar en els dos programes anteriors és que l’estat d’inicialització –que és on el rastrejador llegeix els dos sensors de llum o de color i pren les decisions de la màquina d’estats– utilitza una variable de text per emmagatzemar els dos valors possibles, primer el de la lectura del primer sensor de llum o de color de l’esquerra (port 2), que serà “N” per negre o “B” per blanc, i després concatena la lectura del segon sensor de llum o de color de la dreta (port 3), també “N” o “B”. Per tant, el resultat és una cadena de dos caràcters que pot tenir els següents valors: “BB”, “BN”, “NB” o “NN” corresponents a les 4 combinacions possibles dels dos sensors de llum o de color. Aquests valors es podrien haver utilitzat pels estats de la màquina d’estats, però perquè no s’han utilitzat? Cal que els alumnes pensin una mica...

 

La resposta és: perquè corresponen al resultat de la lectura dels sensors (el codi de funcionalitat) i no a l’estat que realment ens interessa cridar en la màquina d’estats del programa (el codi de transició entre estats). És a dir, després d’obtenir cada combinació diferent dels sensors de llum o de color, en el nostre cas, “BB”, “BN”, “NB” i “NN”, cal seguidament cridar l’estat adequat, en el nostre cas, “rastre recte”, “rastre gir dreta”, “rastre gir esquerra” o “rastre interseccio” respectivament. Això es fa mitjançant una segona estructura de casos o bifurcació múltiple que, en el nostre exemple, reutilitza la mateixa variable de text anterior per emmagatzemar l’estat resultant per a cada cas. Aquest exemple és molt simple, però més endavant veurem la utilitat d’aquesta metodologia, que permet que el programa sigui molt més comprensible i auto explicatiu.

 

Coneixements adquirits: Els alumnes han aprés a dissenyar la primera màquina d’estats i a entendre com separar la presa de decisions del programa de les accions del mateix, a entendre la diferència entre el codi de funcionalitat i el codi de transició entre estats, i a entendre les diferències entre l’estil de programació seqüencial i la màquina d’estats.

 

El següent pas és com modificar la màquina d’estats anterior per fer que el robot sigui capaç de prendre les decisions adeqüades per negociar cada intersecció de línia del recorregut. Podem preguntar als alumnes com creuen que s’hauria de fer? La resposta és que la màquina d’estats hauria de ser capaç de comptar interseccions (resposta que probablement alguns alumnes hagin dit al principi de l’exercici anterior) i segons el número d’intersecció realitzar l’acció correcta, és a dir, seguir recte per saltar la línia, fer un gir cap a un costat o cap a l’altre, o frenar i sortir del programa.

 

En aquest punt cal tornar a preguntar als alumnes on cal posar el comptador d’interseccions i com programar-lo? És evident que el robot haurà de comptar les interseccions que va trobant al llarg del recorregut quan tots dos sensors detectin negre i caldrà afegir una variable numèrica per emmagatzemar aquest número. A nivell de programació, caldrà afegir un estat especial per comptar interseccions i decidir l’estat a cridar per a cadascuna d’elles, i 4 estats més per les 4 accions possibles, esmentades anteriorment, que haurà de realitzar el robot a cada intersecció (seguir recte per saltar la línia, fer un gir cap a un costat o cap a l’altre, o frenar i sortir del programa).

 

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. Abans fins i tot d’escriure un pseudo-codi, tal com s’ha mostrat anteriorment, es dissenya el que s’anomena un diagrama de flux de dades. 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 mitjançant un rectangle, les decisions amb un diamant i el flux de dades 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”.

 

Diagrama de flux de dades pel seguidor de línies o rastrejador simple

de 4 passes amb 2 sensors de llum o de color amb gestió d’interseccions

 

Com podem veure en el diagrama de flux de dades anterior, el rectangle superior “Init - LF2s read” llegeix les dades dels sensors de llum o de color. Seguidament, en funció de la lectura dels sensors, es prenen les decisions (representades per diamants) de quines accions cridar. Finalment es criden les accions adequades que es mostren en els rectangles inferiors. Després de cada acció es torna a cridar l’estat d’inicialització fins que el sistema detecta la última intersecció i surt del programa.

 

Màquina d’estats pel seguidor de línies o rastrejador simple de 4 passes amb 2

sensors de llum amb gestió d’interseccions, estat “rastre interseccio” (NXT)

 

 

Gir dreta

 

 

Gir esquerra

 

 

Salta línia

 

Sortir

 

Màquina d’estats pel seguidor de línies o rastrejador simple de 4 passes amb 2

sensors de color amb gestió d’interseccions, estat “rastre interseccio” (EV3)

 

 

Gir dreta

 

 

Gir esquerra

 

 

Salta línia

 

Sortir

 

En els programes anteriors, és molt important observar que el cas “rastre interseccio” compta les interseccions i per a cadascuna d’elles estableix el següent cas a executar per la màquina d’estats mitjançant la variable de text. És a dir, no executa cap acció, només pren la decisió. Això és molt important perquè en fer l’exercici incremental amb la màquina d’estats veurem que podem tenir varies interseccions on s’hagi de fer una mateixa acció i aquesta metodologia permet no duplicar mai el codi, separant sistemàticament les decisions de les accions.

 

Exercici incremental 10: Arribar al final de la gàbia utilitzant un rastrejador simple de quatre passes amb dos sensors de llum o de color programat mitjançant una màquina d’estats.

 

Abans de començar podem copiar l’exercici anterior “u9ex2.rbt” i posar-li un nom d’exercici incremental diferent. Seguidament, podem demanar als alumnes què cal canviar en aquest programa per realitzar aquest exercici incremental? La resposta és que només cal modificar l’estructura de casos que defineix l’estat que cal cridar per a cada número d’intersecció, que està dins l’estat “rastre interseccio” (1: gir esquerra, 2: salta línia, 3: gir dreta, 4: gir dreta, 5: salta línia i 6: sortir). Com podem veure, la modificació és trivial.

 

Coneixements adquirits: Els alumnes han començat a veure el gran avantatge en separar de forma sistemàtica la presa de decisions del programa de les accions en el disseny d’una màquina d’estats, la qual cosa permet no duplicar mai el codi i fer-lo molt més comprensible i auto explicatiu, més compacte, més eficient i molt més flexible a l’hora d’introduir canvis futurs. Un cop estan programats tots els estats que contenen totes les accions possibles del programa, només cal programar els estats de decisions i les transicions, que és on residirà la intel·ligència del programa. Els alumnes també han aprés a generar diagrames de flux de dades per representar el flux del programa de forma gràfica. Finalment, tot i que podem utilitzar una variable numèrica per anomenar cada estat, l’avantatge d’utilitzar una variable de text és que el programa és molt més comprensible, auto explicatiu i no necessita comentaris.

 

Finalment, podem afegir una mica més de complexitat i interès a la màquina d’estats anterior amb els dos exemples següents.

 

Unitat 9 exercici 3: Afegir la detecció d’un rectangle negre a una màquina d’estats pel seguidor de línies o rastrejador simple de 4 passes amb dos sensors de llum o de color.

 

El repte d’aquest exercici és crear un rectangle negre al mig del recorregut en una línia recta i fer que el robot sigui capaç de diferenciar aquest rectangle d’una intersecció. A més, podem fer que el robot digui la paraula “black” quan trobi el rectangle negre i faci un soroll diferent en cada intersecció per mostrar que el robot és capaç de reconèixer les interseccions i de diferenciar-les del rectangle negre.

 

Disposició d’un rectangle negre al mig del recorregut del robot

 

Què és el que cal modificar i afegir a la màquina d’estats del programa anterior per fer que el robot detecti el rectangle negre? La resposta és que quan el robot detecta la intersecció, cal afegir un codi que permeti diferenciar una intersecció del rectangle negre. El següent diagrama de flux de dades mostra el canvi que s’ha de fer al programa anterior per diferenciar el rectangle negre d’una intersecció de línia.

 

Diagrama de flux de dades pel seguidor de línies o rastrejador simple de 4 passes

amb 2 sensors de llum o de color amb gestió d’interseccions i detecció d’un rectangle negre

 

Ara cal programar el codi que permetrà al robot diferenciar una intersecció de línia del rectangle negre. Com ho podem fer? Podem començar per preguntar als alumnes què diferencia la línia negra del rectangle? Òbviament la diferència és el gruix! Per tant, què podem fer per a que el robot detecti aquest gruix? Si recordem els exercicis anteriors, especialment els de la unitat didàctica 3, veurem que una bona opció és fer que quan el robot detecti una intersecció, segueixi endavant en línia recta fins que un dels seus sensors de llum o de color detecti el color blanc. Si a més, el robot compta els graus de gir que fa un dels seus motors (tots dos giren igual) aleshores podrem veure que en les interseccions els graus de gir del motor són molt inferiors als que fa quan troba el rectangle negre.

 

Recordar crear un nou programa, per exemple “u9ex3.rbt”, copiant el programa anterior abans de començar a modificar el codi.

 

Màquina d’estats pel rastrejador simple de 4 passes amb 2 sensors de llum amb gestió

d’interseccions i detecció d’un rectangle negre, estat “rectangleOinterseccio” (NXT)

 

Màquina d’estats pel rastrejador simple de 4 passes amb 2 sensors de color amb gestió

d’interseccions i detecció d’un rectangle negre, estat “rectangleOinterseccio” (EV3)

 

Les imatges anteriors mostren l’estat “rectangleOinterseccio” que s’executa just després de que la màquina d’estats detecti una intersecció. Podem observar que el codi comença per inicialitzar el comptador de rotacions del motor B, arrenca tots dos motors i mitjançant un bucle espera a que un dels dos sensors de llum o de color detecti el color blanc, per finalment establir la variable d’estat a “rectangle” si els graus de gir del motor B són superiors a 70 o a “rastre interseccio” si són inferiors. Finalment, només cal canviar la variable de l’estat d’inicialització al valor “rectangleOinterseccio” pel cas “NN”, crear un segon estat dins la màquina d’estats que anomenem “rectangle” per tal de que el robot digui “black” i cridi l’estat d’inicialització, i afegir un altre bloc de so a l’estat “rastre interseccio” per tal de que el robot faci un so diferent al del rectangle per a cada intersecció de línia.

 

Unitat 9 exercici 4: Afegir la detecció d’un obstacle a una màquina d’estats pel seguidor de línies o rastrejador simple de 4 passes amb dos sensors de llum o de color.

 

Finalment, un últim repte pot consistir en afegir un obstacle al mig del recorregut i programar el robot per a que el detecti, el sortegi i segueixi el seu recorregut sense xocar.

 

Per resoldre aquest repte, cal que els alumnes se’n adonin de que el robot utilitzarà un tercer sensor, l’ultrasònic. Per tant, quins són els mínims canvis que cal fer al programa anterior per resoldre aquest repte i on s’han d’afegir? Caldrà modificar l’estat d’inicialització afegint un codi pel sensor ultrasònic. Així, quan el sensor ultrasònic detecti un obstacle, cridarà un nou estat “obstacle” de la màquina d’estats, per a que el robot sortegi l’obstacle, i si no el detecta cridarà un dels estats anteriors de la màquina d’estats.

 

Alternativament, podem crear un estat específic per la lectura del sensor ultrasònic i convertir-lo en l’estat d’inicialització, és a dir, cridar-lo abans de cridar l’estat de presa de decisions corresponent als sensors de llum o de color. Si aquest nou estat detecta un obstacle, crida l’estat “obstacle” per sortejar l’obstacle i si no el detecta, crida l’estat corresponent a la lectura i presa de decisions dels sensors de llum o de color.

 

Abans de començar a programar cal dissenyar un nou diagrama de flux de dades i es pot fer per a les dues estratègies de programació anteriors.

 

Diagrama de flux de dades pel seguidor de línies o rastrejador simple de 4 passes

amb 2 sensors de llum o de color amb gestió d’interseccions,

detecció d’un rectangle negre i detecció d’un obstacle (versió 1)

 

Diagrama de flux de dades pel seguidor de línies o rastrejador simple de 4 passes

amb 2 sensors de llum o de color amb gestió d’interseccions,

detecció d’un rectangle negre i detecció d’un obstacle (versió 2)

 

La diferència entre ambdues alternatives és subtil. La primera alternativa té l’avantatge de que el codi de presa de decisions està tot compactat en un sol estat. Però al mateix temps, aquesta és la seva desavantatge perquè fa el codi menys flexible a l’hora de poder realitzar futurs canvis, donat que barreja les lectures de diferents tipus de sensors (els dos sensors de llum o de color i el sensor ultrasònic)...

 

Abans de començar a programar, recordar crear un nou programa copiant l’anterior per modificar el seu codi. Donat que es faran dues versions del programa les podrem anomenar “u9ex41.rbt” i “u9ex42.rbt”.

 

Màquina d’estats pel rastrejador simple de 4 passes amb 2 sensors de llum amb gestió

d’interseccions, detecció d’un rectangle negre i detecció d’un obstacle, estat “Init”

(versió 1, NXT)

 

Màquina d’estats pel rastrejador simple de 4 passes amb 2 sensors de color amb gestió

d’interseccions, detecció d’un rectangle negre i detecció d’un obstacle, estat “Init”

(versió 1, EV3)

 

Com podem veure en les imatges anteriors, a nivell de programació només cal afegir a l’estat d’inicialització “Init” la lectura del sensor ultrasònic, mitjançant una bifurcació associada a aquest sensor amb un llindar de menys de 20 cm, i afegir un cas més a l’estructura de casos que conté, per quan el sensor ultrasònic detecta un obstacle (nou cas “U”), i posar el valor “obstacle” a la variable de la màquina d’estats. A nivell d’estil de programació, cal observar que la bifurcació associada al sensor ultrasònic s’ubica just després de la lectura dels sensors de llum o de color, la qual cosa permet només modificar la variable en el cas de detectar un obstacle i evita niar les bifurcacions, permetent mantenir el patró seqüencial de lectura de sensors, que és molt més fàcil d’entendre i de mantenir.

 

Finalment, cal afegir el nou estat o cas “obstacle” a la màquina d’estats per a que el robot pugui sortejar o esquivar l’obstacle i tornar a seguir la línia del recorregut. Aquest codi és molt senzill de programar, només cal fer que el robot giri cap a un costat, tiri endavant fins sobrepassar l’obstacle, torni a girar cap al costat invers i vagi endavant fins que trobi la línia de rastreig (es recomanable utilitzar els sensors de llum o de color per detectar-la i així arribar-hi amb precisió), per finalment redreçar el robot fent un petit gir invers a l’anterior just abans de tornar a seguir la línia de rastreig.

 

Disposició d’un obstacle al mig del recorregut del robot i estratègia per esquivar-lo

 

Màquina d’estats pel rastrejador simple de 4 passes amb 2 sensors de llum amb gestió

d’interseccions, detecció d’un rectangle negre i detecció d’un obstacle, estat “Init”

(versió 2, NXT)

 

Màquina d’estats pel rastrejador simple de 4 passes amb 2 sensors de color amb gestió

d’interseccions, detecció d’un rectangle negre i detecció d’un obstacle, estat “Init”

(versió 2, EV3)

 

Com podem veure en la imatge anterior, la diferència entre aquesta segona versió i la primera és que cal re-nombrar l’estat “Init” d’inicialització a “SL lectura” (lectura dels sensors de llum o de color) i afegir un nou estat “Init” a la màquina d’estats per posar-hi el codi de lectura del sensor ultrasònic. En aquest nou estat “Init” només cal posar la variable de la màquina d’estats amb el valor “obstacle” quan el sensor ultrasònic detecta un obstacle a menys de 20 cm (igual que en la versió anterior) i amb el valor “SL lectura” quan no detecta cap obstacle, per tal de que el robot pugui seguir la línia. Finalment, com en la versió anterior, també cal afegir el mateix nou cas “obstacle” a la màquina d’estats per a que el robot pugui sortejar o esquivar l’obstacle i tornar a seguir la línia del recorregut.

 

Quina és l’avantatge d’aquests dos mètodes de programació per esquivar o sortejar un obstacle? La principal avantatge és que l’obstacle es pot localitzar en qualsevol lloc del recorregut, la qual cosa seria més difícil de realitzar en una programació seqüencial. Cal tenir cura però del codi de programació per esquivar o sortejar l’obstacle i tornar a la línia de rastreig, especialment si hi han varis obstacles i si aquests es troben en una corba, o en una recta, o si existeixen parets en el recorregut que impedeixen sobrepassar l’obstacle per qualsevol costat, etc.

 

Es poden imaginar molts més reptes per complexificar la programació anterior i un bon exercici que es pot demanar als alumnes és que inventin el seu propi repte i l’afegeixin a l’exercici anterior, realitzant els canvis necessaris a la màquina d’estats...

 

Coneixements adquirits: Amb aquesta unitat didàctica els alumnes han pogut entendre amb bastant detall els diagrames de flux de dades, la utilitat de la programació de màquines d’estats i el seu gran avantatge respecte de la programació seqüencial a través d’exemples relativament senzills, però que inclouen preses de decisions utilitzant sensors, comptadors per acumular informació i variables per passar informació entre blocs i parts del programa. Aquesta unitat didàctica pot ser especialment útil per iniciar equips de joves que vulguin participar en competicions de robòtica educativa, com ara la prova de rescat de la RoboCup Junior.

 

 

 

Creative Commons License

Curs d'introducció a LEGO® Mindstorms NXT i EV3 by Josep Maria Fargas is licensed under a Creative Commons Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España License.

Permissions beyond the scope of this license may be available at www.bogatech.org.