PRAM, il tuo Primo Robot Autonomo Mobile – Parte 4

Nel precedente articolo “PRAM, il tuo Primo Robot Autonomo Mobile – Parte 3” abbiamo realizzato e installato la scheda di controllo di PRAM, eseguito tutte le fasi propedeutiche alla programmazione della scheda di sviluppo uChip, infine, abbiamo creato e salvato lo sketch del codice per il funzionamento di PRAM. In questa quarta ed ultima parte del progetto, descriveremo gli aspetti più rilevanti del codice e lo caricheremo nella scheda di sviluppo uChip, eseguiremo le tarature e il collaudo funzionale del prototipo e, finalmente, vedremo PRAM all'opera.

Introduzione

In questo articolo tratteremo la parte più interessante della “creazione” del robot autonomo mobile PRAM: daremo a PRAM una vita artificiale. PRAM si comporterà come una falena alla ricerca della luce; se la luce è troppo intensa si allontanerà da essa (evitamento della luce), oppure se l'intensità della luce è scarsa, allora la falena PRAM inizierà ad esplorare la stanza alla ricerca di luce e userà i suoi sensori (gli switch paraurti e il sensore di distanza HC-SR04) per evitare gli ostacoli. L'approccio classico all'Intelligenza Artificiale consiste nell'utilizzare la modellazione del mondo, pianificare l'azione ed eseguire questi piani. Questo tipo di metodo è adatto solo per ambienti strettamente controllati, come nel caso di applicazioni con il braccio robotico utilizzato nell'industria dell'assemblaggio di linee automobilistiche. Per i robot mobili autonomi la modellazione del mondo è diventata molto complessa ed è quasi impossibile mettere tutto l'ambiente imprevedibile e dinamico all'interno di questo modello. Come potremmo pianificare un’azione di evitamento di un ostacolo se viene spostato imprevedibilmente dalla sua originaria posizione?

Fino alla fine degli anni ’80, questo metodo classico era ancora l'approccio dominante al robot mobile autonomo; con una complessa equazione matematica per modellare il mondo, il robot mobile diventa inaffidabile perché la sua reazione all'ambiente sarà molto lenta, inoltre, questo metodo di sicuro non saremmo in grado di eseguirlo con semplici microcontrollori. La soluzione è utilizzare l'approccio bottom-up (invece dell'approccio top-down utilizzato nell'Intelligenza Artificiale classica). Questo metodo è solitamente chiamato "Intelligenza Artificiale basata sul comportamento", in quanto la teoria asserisce che prima si realizza il programma di comportamento primitivo di base del robot, come l'evitamento degli ostacoli, poi si aggiunge via via un comportamento sempre più avanzato su di esso. Ad esempio, evitare la luce, seguire la luce, esplorare l’ambiente, etc. A ciascuno di questi comportamenti viene assegnata una priorità fissa per assumere il controllo degli attuatori del robot. Al comportamento più importante viene data una priorità più alta, come il comportamento di evitamento degli ostacoli. La combinazione di tutti questi comportamenti produrrà la risposta desiderata all'ambiente del robot.

L’assegnazione delle priorità

Al fine di rendere il programma più strutturato e facile da modificare nel caso di inserimento di nuovi comportamenti in futuro, viene implementato l’algoritmo selettore di priorità fissa che consente a ciascuno dei comportamenti di avere il proprio controllo assoluto della guida e della velocità di PRAM. Come mostrato dallo schema di Figura 1, il funzionamento di PRAM si basa su cinque comportamenti ai quali viene assegnato un livello di priorità fisso a partire dal comportamento a priorità più alta (evitamento degli ostacoli con switch paraurti: livello 1) fino alla più bassa priorità (esplorazione: livello 5). Il selettore di priorità è il metodo dell'algoritmo che garantisce che un solo comportamento alla volta possa prendere il controllo dei motori di PRAM; questo selettore di priorità funziona come un commutatore che collega l'azione del comportamento direttamente al controllo dei motori. Ad esempio, se l'inseguitore di luce rileva la luce nello stesso momento in cui uno switch paraurti colpisce un ostacolo, il selettore di priorità assicurerà che l'evitamento dell'ostacolo venga servito per primo, poiché ha una priorità maggiore rispetto al comportamento dell'inseguitore di luce.

Figura 1: Selettore di priorità dei comportamenti di PRAM

Di seguito riportiamo le parti di codice relative alle funzioni dei cinque comportamenti di PRAM e al selettore di priorità.
Nella funzione void loop viene inizialmente eseguita la lettura dei sensori:

/* Start Read All the ADC input here */
// The PWM Motor Speed Control
speed=analogRead(A1); // read the input pin D1/A1.

// Bumped Sensor
bump_sensor=analogRead(A6);

// The LDR Sensor
ldr_left=analogRead(A5); // read the input pin D4/A4
ldr_right=analogRead(A4); // read the input pin D5/A5

// PRAM Steering Speed
PRAM_speed(speed*halt_status);
digitalWrite(uC3,0); // Turn Off PRAM Head Light

Dopo aver letto il valore di tutti i sensori, il programma continua chiamando le funzioni di comportamento per il relativo controllo dei motori, dalla funzione di evitamento ostacoli a priorità più alta PRAM_BumpAvoidance() , fino alla funzione di esplorazione PRAM_Exploring() a più bassa priorità:

// Bump Avoidance Behavior
PRAM_BumpAvoidance(bump_sensor);

//avoid_frontImpact(distance);
PRAM_UltrasonicAvoidance(distance);

// Light Avoidance Behavior
PRAM_LightAvoidance(ldr_left,ldr_right);

// Light Follower Behavior
PRAM_LightFollower(ldr_left,ldr_right);

// Exploring Behavior
PRAM_Exploring(ldr_left,ldr_right);

Occorre evidenziare che ogni funzione di comportamento utilizza il valore rilevato dal rispettivo sensore per inizializzare il generatore di numeri casuali mediante la funzione srand(valore del sensore) a cui si riferisce la funzione random_number() per generare un numero casuale e usarlo come valore di ritardo nella variabile relativa all’azione di guida di PRAM steer_delay[][]=random_number() che determina la durata di accensione dei motori di PRAM; questo ritardo influirà sul comportamento di guida di PRAM.

Il programma termina con la funzione di selezione delle priorità PRAM_PrioritySelector(halt_status) che stabilisce il comportamento prioritario di PRAM. Terminata l’azione di comportamento selezionata dal selettore, la funzione PRAM_Reset() resetta tutte le variabili delle cinque funzioni di comportamento.

Riportiamo di seguito il listato completo del codice pram_1.0.ino: [...]

ATTENZIONE: quello che hai appena letto è solo un estratto, l'Articolo Tecnico completo è composto da ben 3121 parole ed è riservato agli ABBONATI. Con l'Abbonamento avrai anche accesso a tutti gli altri Articoli Tecnici che potrai leggere in formato PDF per un anno. ABBONATI ORA, è semplice e sicuro.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend