Archivi categoria: i miei allievi

PCTO A.S. 2020 – 2021 – SumoBot – lezione 4

Come probabilmente avrete avuto modo di verificare gestendo i due servomotori a rotazione continua, pur provenendo dal medesimo costruttore e impostando le medesime configurazione di velocità, hanno un comportamento non sempre identico. Ricordo che si tratta di apparati economici che devono rispondere a specifiche esigenze didattiche, ma in ogni caso è possibile effettuare alcune regolazioni che ne possono migliorare le prestazioni.
Un’altra funzionalità utile è quella dello start/stop del robot che potrebbe servire per evitare immediati movimenti non appena trasferiamo il codice sul robot.

In questa lezione vi dettaglio gli sketch di esempio, lasciando a voi modifiche e miglioramenti.

Regolazione dei motori

Per poter valutare la velocità e l’angolo di rotazione da impostare all’interno dello sketch è possibile attivare la funzione di calibrazione collegando a GND il pin 3, in questo modo sarà possibile dalla Serial Monitor verificare quali sono i giusti valori per:

  • velocità di rotazione;
  • durata della rotazione;
  • motore/i da impostare

e quindi ciò consentirà di impostare i parametri corretti per le funzioni:

  • orarioRobot()
  • antiorarioRobot()

Pertanto da serial monitor potremo comprendere come far compiere una rotazione di 90° in un senso, oppure come far avanzare di una certa quantità di centimetri il robot e molto altro, tenendo però bene a mente che tutto ciò dipenderà fortemente dalla carica della batteria.

La scelta del pin3 è puramente casuale se ritenete potete scegliere un altro pin digitale.

Esempio 1

1/*
2   Prof. Maffucci Michele
3   SumoRobot
4   Data: 26.01.2021
5 
6   Sketch 03: rotazione oraria e antioraria continua
7              con funzioni parametrizzate
8 
9              Per valutare la velocità e l'angolo di rotazione è possibile
10              attivare la funzione di calibrazione collegando a GND il pin 3,
11              in questo modo sarà possibile dalla Serial Monitor verificare
12              quali sono i giusti valori per:
13              - velocità di rotazione;
14              - durata della rotazione;
15              - motore/i da impostare
16 
17              Ciò consentirà di impostare i parametri corretti per le funzioni:
18 
19              - orarioRobot()
20              - antiorarioRobot()
21 
22   Note:
23            L'orientamento dei motori è fatto
24            guardano il robot anteriormente
25 
26            180: max velocità in senso antiorario
27            90 : servomotori fermi
28            0  : max velocità in senso orario
29 
30*/
31 
32// inclusione della libreria servo.h per il controllo dei servomotori
33#include <Servo.h>
34 
35// Creazione oggetti servo
36Servo motoreDX;  // Inizializzazione del servomotore destro
37Servo motoreSX;  // Inizializzazione del servomotore sinistro
38 
39byte pinDx = 4;     // Inizializza del pin 4 a cui è connesso il pin segnale del servo destro
40byte pinSx = 5;     // Inizializza del pin 5 a cui è connesso il pin segnale del servo sinistro
41 
42// Per Calibrazione
43 
44// per stampare una sola volta il messaggio sulla Serial Monitor
45bool abilitaMessaggio = 0;
46 
47// per attivare la calibrazione impostare startCalibrazione a 0
48bool startCalibrazione = 1;
49 
50// Pin di calibrazione se a LOW abilita modalità calibrazione
51byte pinCal = 3;
52 
53void setup() {
54 
55  // inizializzazione della seriale
56  Serial.begin(9600);
57 
58  // attach() consente di definire a quale pin viene connesso il servomotore
59  // e lo collega all'oggetto che gestisce il servomotore
60 
61  motoreDX.attach(pinDx); // pinDx collegato al motore destro
62  motoreSX.attach(pinSx); // pinSx collegato al motore sinistro
63 
64  pinMode(pinCal, INPUT);
65}
66 
67void loop() {
68 
69  // se sul pinCal è LOW è possibile impostare i motori
70  if (digitalRead(pinCal) == LOW) {
71    calibrazione();
72  }
73  else
74  {
75    orarioRobot(30, 250);      // Rotazione in senso orario del robot
76    stopRobot(3000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
77    antiorarioRobot(150, 250); // Rotazione in senso antiorario del robot
78    stopRobot(3000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
79  }
80}
81 
82// Funzione da utilizzare una sola volta per impostare
83// i tempi necessari per effettuare uno specifico angolo
84// di rotazione e la velocità di rotazione desiderata
85 
86void calibrazione() {
87 
88  // consente di visualizzare sulla Serial Monitor
89  // una sola stampa delle stringa
90  if (abilitaMessaggio == 0) {
91    // ritardo che evita la doppia stampa del messaggio
92    delay(200);
93    Serial.println("Calibrazione tempo rotazione");
94    Serial.println("velocità (0-180), durata(ms), motore(1: DX, 2: SX, 3: SX+DX)");
95    Serial.println();
96    abilitaMessaggio = 1;
97  }
98 
99  // Controlla se è disponibile almeno un carattere sulla seriale
100  // La Serial.available() restituisce
101  // 1 se presente un cattere,
102  // 0 se non è presente un carattere
103 
104  if (Serial.available()) {        // Viene controllato se è disponibile un carattere
105 
106    // per maggior informazioni sull'uso di parseInt() consultare il link:
108 
109    // inserimento da tastiera su Serial Monitor dei parametri di controllo
110    // separati da spazio o virgola
111    int velocita = Serial.parseInt();
112    int durata   = Serial.parseInt();
113    int motore   = Serial.parseInt();
114 
115    // funzione per il movimento dei servomotori con i parametri
116    // inseriti sulla serial monitor.
117    calMotoreRobot(velocita, durata, motore);
118  }
119}
120 
121// funzione movimento servomotori per impostazione
122// velocità, durata, motore/i
123 
124void calMotoreRobot(int calVel, int calDurata, int nMotore) {
125  if (nMotore == 1) { // motore DX
126    motoreDX.write(calVel);
127    delay(calDurata);
128    motoreDX.write(90);   // Ferma il motore DX
129    motoreSX.write(90);   // Ferma il motore SX
130    Serial.println("Fine calibrazione motore DX");
131    Serial.println();
132  }
133  if (nMotore == 2) { // motore SX
134    motoreSX.write(calVel);
135    delay(calDurata);
136    motoreDX.write(90);   // Ferma il motore DX
137    motoreSX.write(90);   // Ferma il motore SX
138    Serial.println("Fine calibrazione motore SX");
139    Serial.println();
140  }
141  if (nMotore == 3) { // motore SX+DX
142    motoreDX.write(calVel);  // Rotazione oraria del motore DX
143    motoreSX.write(calVel);  // Rotazione antioraria del motore SX
144    delay(calDurata);
145    motoreDX.write(90);   // Ferma il motore DX
146    motoreSX.write(90);   // Ferma il motore SX
147    Serial.println("Fine calibrazione motore DX e SX");
148    Serial.println();
149  }
150}
151 
152// rotazione del robot in senso antiorario
153// velMaxOraria: velocità massima in senso antiorario
154// durata: durata della rotazione
155 
156void antiorarioRobot(int velMaxAntioraria, int durata) {
157  motoreDX.write(velMaxAntioraria);  // Rotazione oraria del motore DX
158  motoreSX.write(velMaxAntioraria);  // Rotazione antioraria del motore SX
159  delay(durata);                     // durata: durata della rotazione
160}
161 
162// rotazione del robot in senso orario
163// velMaxOraria: velocità massima in senso orario
164// durata: durata della rotazione
165 
166void orarioRobot(int velMaxOraria, int durata) {
167  motoreDX.write(velMaxOraria);    // Rotazione antioraria del motore DX
168  motoreSX.write(velMaxOraria);    // Rotazione oraria del motore SX
169  delay(durata);                   // durata: durata della rotazione
170}
171 
172// stop del robot
173// ferma: durata dello stop del robot
174 
175void stopRobot(int ferma) {
176  motoreDX.write(90);   // Ferma il motore DX
177  motoreSX.write(90);   // Ferma il motore SX
178  delay(ferma);         // Durata dello stop
179}

La calibrazione viene attivata se la condizione ad inizio loop è vera:

1...
2// se sul pinCal è LOW è possibile impostare i motori
3  if (digitalRead(pinCal) == LOW) {
4    calibrazione();
5  }
6  else
7  {
8    orarioRobot(30, 250);      // Rotazione in senso orario del robot
9    stopRobot(3000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
10    antiorarioRobot(150, 250); // Rotazione in senso antiorario del robot
11    stopRobot(3000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
12  }
13}
14...

Se la condizione dell’if risulta vera viene attivata la calibrazione:

1...
2// se sul pinCal è LOW è possibile impostare i motori
3  if (digitalRead(pinCal) == LOW) {
4    calibrazione();
5  }
6  else
7  {
8    orarioRobot(30, 250);      // Rotazione in senso orario del robot
9    stopRobot(3000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
10    antiorarioRobot(150, 250); // Rotazione in senso antiorario del robot
11    stopRobot(3000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
12  }
13}
14...

In tal caso viene chiamata la funzione calibrazione:

1...
2void calibrazione() {
3 
4  // consente di visualizzare sulla Serial Monitor
5  // una sola stampa delle stringa
6  if (abilitaMessaggio == 0) {
7    // ritardo che evita la doppia stampa del messaggio
8    delay(200);
9    Serial.println("Calibrazione tempo rotazione");
10    Serial.println("velocità (0-180), durata(ms), motore(1: DX, 2: SX, 3: SX+DX)");
11    Serial.println();
12    abilitaMessaggio = 1;
13  }
14 
15  // Controlla se è disponibile almeno un carattere sulla seriale
16  // La Serial.available() restituisce
17  // 1 se presente un cattere,
18  // 0 se non è presente un carattere
19 
20  if (Serial.available()) {        // Viene controllato se è disponibile un carattere
21 
22    // per maggior informazioni sull'uso di parseInt() consultare il link:
24 
25    // inserimento da tastiera su Serial Monitor dei parametri di controllo
26    // separati da spazio o virgola
27    int velocita = Serial.parseInt();
28    int durata   = Serial.parseInt();
29    int motore   = Serial.parseInt();
30 
31    // funzione per il movimento dei servomotori con i parametri
32    // inseriti sulla serial monitor.
33    calMotoreRobot(velocita, durata, motore);
34  }
35}
36...

La prima parte della funzione calibrazione() esegue una sola volta la stampa sulla Serial Monitor dell’help che spiega come inserire i dati:

velocità (0-180), durata(ms), motore(1: DX, 2: SX, 3: SX+DX)

che sono tutti valori interi separati da virgola.

Nella parte restante del codice della funzione viene verificato con il metodo available() se sono presenti sulla seriale caratteri. Serial.available() restituisce TRUE se sono presenti caratteri e il corpo dell’if verrà eseguito. I valori inseriti vengono letti utilizzando la funzione parseInt() di cui trovate spiegazione approfondita con esercizi seguendo il link.

1...
2if (Serial.available()) {        // Viene controllato se è disponibile un carattere
3 
4    // per maggior informazioni sull'uso di parseInt() consultare il link:
6 
7    // inserimento da tastiera su Serial Monitor dei parametri di controllo
8    // separati da spazio o virgola
9    int velocita = Serial.parseInt();
10    int durata   = Serial.parseInt();
11    int motore   = Serial.parseInt();
12 
13    // funzione per il movimento dei servomotori con i parametri
14    // inseriti sulla serial monitor.
15    calMotoreRobot(velocita, durata, motore);
16  }
17...

Non appena premiamo invio sulla tastiera, questi valori vegono acquisiti e passati alla funzione calMotoreRobot()

1...
2calMotoreRobot(velocita, durata, motore);
3...

Tra i parametri che vengono passati alla funzione calMotoreRobot() è presente l’indicazione di quale/i motore/i devono essere controllati, questo parametro può assumere i valori: 1, 2, 3 e questi valori vengono utilizzati per selezionare, tramite i blocchi if corrispondenti, quale azione è da compiere. Nei commenti i dettagli di funzionamento.

1...
2void calMotoreRobot(int calVel, int calDurata, int nMotore) {
3  if (nMotore == 1) { // motore DX
4    motoreDX.write(calVel);
5    delay(calDurata);
6    motoreDX.write(90);   // Ferma il motore DX
7    motoreSX.write(90);   // Ferma il motore SX
8    Serial.println("Fine calibrazione motore DX");
9    Serial.println();
10  }
11  if (nMotore == 2) { // motore SX
12    motoreSX.write(calVel);
13    delay(calDurata);
14    motoreDX.write(90);   // Ferma il motore DX
15    motoreSX.write(90);   // Ferma il motore SX
16    Serial.println("Fine calibrazione motore SX");
17    Serial.println();
18  }
19  if (nMotore == 3) { // motore SX+DX
20    motoreDX.write(calVel);  // Rotazione oraria del motore DX
21    motoreSX.write(calVel);  // Rotazione antioraria del motore SX
22    delay(calDurata);
23    motoreDX.write(90);   // Ferma il motore DX
24    motoreSX.write(90);   // Ferma il motore SX
25    Serial.println("Fine calibrazione motore DX e SX");
26    Serial.println();
27  }
28}
29...

La parte restante dello sketch riguarda funzioni già analizzate spiegate nelle lezioni precedenti.

Start/stop del robot

Questa semplice funzionalità viene ottenuta nel medesimo modo della calibrazione, utilizziamo il pin2 cortocircuitato a massa per evitare l’avvio del robot, secondo questa regola:

  • Pin 2 a GND: robot fermo
  • Pin 2 a Vcc: robot start

Questo lo sketch generale:

1/*
2   Prof. Maffucci Michele
3   SumoRobot
4   Data: 26.01.2021
5 
6   Sketch 04: rotazione oraria e antioraria continua
7              con funzioni parametrizzate con Start e Stop sistema.
8 
9              Per evitare in avvio immediato del robot si realizza un
10              un interruttore di start/stop utilizzando il pin 2:
11               
12              - Pin 2 a GND: robot fermo
13              - Pin 2 a Vcc: robot start
14   Note:
15            L'orientamento dei motori è fatto
16            guardano il robot anteriormente
17 
18            180: max velocità in senso antiorario
19            90 : servomotori fermi
20            0  : max velocità in senso orario
21 
22            Per avviare il robot collegare a GND il pin 2
23 
24*/
25 
26// inclusione della libreria servo.h per il controllo dei servomotori
27#include <Servo.h>
28 
29// Creazione oggetti servo
30Servo motoreDX;  // Inizializzazione del servomotore destro
31Servo motoreSX;  // Inizializzazione del servomotore sinistro
32 
33byte pinDx = 4;     // Inizializza del pin 4 a cui è connesso il pin segnale del servo destro
34byte pinSx = 5;     // Inizializza del pin 5 a cui è connesso il pin segnale del servo sinistro
35byte pinStart = 2;  // Pin di avvio, se a LOW Start sistema
36 
37void setup() {
38 
39  // inizializzazione della seriale
40  Serial.begin(9600);
41 
42  // attach() consente di definire a quale pin viene connesso il servomotore
43  // e lo collega all'oggetto che gestisce il servomotore
44 
45  motoreDX.attach(pinDx); // pinDx collegato al motore destro
46  motoreSX.attach(pinSx); // pinSx collegato al motore sinistro
47 
48  pinMode(pinStart, INPUT); // pin per avviare il sistema
49}
50 
51void loop() {
52 
53  // se pinStart a LOW il sistema è in stop
54  if (digitalRead(pinStart) == LOW) {
55    stopRobot(1);
56  }
57 
58  // se pinStart è diverso da LOW si avvia la sequenza
59  else
60  {
61    orarioRobot(70, 500);      // Rotazione in senso orario del robot
62    stopRobot(1000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
63    antiorarioRobot(130, 500); // Rotazione in senso antiorario del robot
64    stopRobot(1000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
65 
66  }
67}
68 
69// rotazione del robot in senso antiorario
70// velMaxOraria: velocità massima in senso antiorario
71// durata: durata della rotazione
72 
73void antiorarioRobot(int velMaxAntioraria, int durata) {
74  motoreDX.write(velMaxAntioraria);  // Rotazione antioraria del motore DX
75  motoreSX.write(velMaxAntioraria);  // Rotazione antioraria del motore SX
76  delay(durata);                     // durata: durata della rotazione
77}
78 
79// rotazione del robot in senso orario
80// velMaxOraria: velocità massima in senso orario
81// durata: durata della rotazione
82 
83void orarioRobot(int velMaxOraria, int durata) {
84  motoreDX.write(velMaxOraria);    // Rotazione oraria del motore DX
85  motoreSX.write(velMaxOraria);    // Rotazione oraria del motore SX
86  delay(durata);                   // durata: durata della rotazione
87}
88 
89// stop del robot
90// ferma: durata dello stop del robot
91 
92void stopRobot(int ferma) {
93  motoreDX.write(90);   // Ferma il motore DX
94  motoreSX.write(90);   // Ferma il motore SX
95  delay(ferma);         // Durata dello stop
96}

Come si può notare lo start/stop è regolato dalla parte di codice:

1...
2// se pinStart a LOW il sistema è in stop
3  if (digitalRead(pinStart) == LOW) {
4    stopRobot(1);
5  }
6 
7  // se pinStart è diverso da LOW si avvia la sequenza
8  else
9  {
10    orarioRobot(70, 500);      // Rotazione in senso orario del robot
11    stopRobot(1000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
12    antiorarioRobot(130, 500); // Rotazione in senso antiorario del robot
13    stopRobot(1000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
14 
15  }
16}
17...

Se il pin è collegato a GND, quindi al LOW il robot è in stop, infatti viene chiamata la funzione stopRobot(1);

Nella prossima lezione vedremo come integrare le due funzionalità:

  • calibrazione
  • start/stop

Buon Making a tutti 🙂

Lezione 2 – Arduino GamePad – LCD1602 Keypad Shield della Keyestudio

Pubblico la seconda lezione per il gruppo di lavoro della mia classe terza Automazione che sta operando con lo shield LCD1602 Keypad Shield della Keyestudio, suggerendo alcuni sketch che potranno poi essere riutilizzati e modificati opportunamente per realizzare alcune dinamiche di gioco.
Per chi volesse cimentarsi in queste sperimentazioni ricordo che non è essenziale possedere LCD1602 Keypad Shield della Keyestudio, il tutto può essere ottenuto anche mediante un normale display, a questo dovrete aggiungere i 6 pulsanti che potranno essere connessi o al pin A0, secondo la rete resistiva che potete riprodurre guardando gli schemi elettrici della shield oppure gestendo il tutto collegando i pulsanti a dei pin digitali.

Esempio 01

Il primo degli sketch, molto semplice, permette di far rimbalzare avanti e indietro un carattere. Per questo esempio sono state utilizzate le funzioni: scrollDisplayRight() e scrollDisplayLeft() ciascuna inclusa in un ciclo for, il primo muove il carattere “*” verso destra di 16 posizioni, tante quante sono le colonne del display ed il secondo muoverà il carattere da sinistra verso destra.

1/*
2   Prof. Michele Maffucci
3   Utilizzo dell'LCD Keypad Shield della Keystudio
4   Data: 14.03.2021
5 
6   Movimento ripetuto di un carattere, avanti e indietro su una riga
7*/
8 
9// inclusione della libreria LiquidCrystal.h
10#include <LiquidCrystal.h>
11 
12// inizializza la libreria con i numeri dei pin dell'interfaccia
13LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
14 
15// Velocità con cui viene stampato il carattere 
16int velocita = 200;
17 
18void setup() {
19  // impostazione del numero di colonne e righe del display
20  lcd.begin(16, 2);
21 
22  // Inizializzazione della Serial Monitor
23  Serial.begin(9600);
24 
25  // Carattere stampato nella prima colonna e prima riga (0,0)
26  lcd.print("*");
27}
28 
29void loop() {
30   
31  // Movimento verso destra del carattere
32  for (int contatorePosizioneColonna = 0; contatorePosizioneColonna < 16; contatorePosizioneColonna++) {
33    // Spostamento di una posizione verso destra
34    lcd.scrollDisplayRight();
35    // Attesa di un'istante per percepire il movimento del carattere
36    delay(velocita);
37  }
38 
39  // Movimento verso sinistra del carattere
40  for (int contatorePosizioneColonna = 0; contatorePosizioneColonna < 16; contatorePosizioneColonna++) {
41    // Spostamento di una posizione verso sinistra
42    lcd.scrollDisplayLeft();
43    // Attesa di un'istante per percepire il movimento del carattere
44    delay(velocita);
45  }
46}

Esercizio 1

Realizzare le medesime funzionalità dell’esempio 1, quando il carattere giunge nell’ultima colonna a destra, scende nella riga sottostante e ripercorre il tragitto verso sinistra, giunto alla prima colonna a sinistra risale sulla prima riga e si sposta nuovamente verso destra. Far ripetere in loop questa sequenza.

Esempio 02

Nell’esempio che segue vengono utilizzati i pulsanti RIGHT e LEFT del display per spostare verso destra o verso sinistra di un passo il carattere “*”.
L’identificazione del pulsante premuto avviene controllando il valore numerico restituito dall’analogRead() così come spiegato nella lezione 1.

Le due istruzioni if hanno come condizione il controllo del valore analogico, che indicherà il pulsante premuto il tutto è posto in AND con la posizione attuale (la colonna) del carattere, colonna memorizzata nella variabile “contatorePosizioneColonna” che nello spostamento verso destra dovrà essere incrementata e nello spostamento verso sinistra dovrà essere decrementata.

1/*
2   Prof. Michele Maffucci
3   Utilizzo dell'LCD Keypad Shield della Keystudio
4   Data: 14.03.2021
5 
6   Controllo dello spostamento di un carattere destra/sinistra
7   mediante i pulsanti: RIGHT e LEFT sul display
8*/
9 
10// inclusione della libreria LiquidCrystal.h
11#include <LiquidCrystal.h>
12 
13// inizializza la libreria con i numeri dei pin dell'interfaccia
14LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
15 
16// Colonna in cui si trova il carattere
17int contatorePosizioneColonna = 0;
18 
19// Valore restituito dall'analogRead su A0
20int val;
21 
22void setup() {
23  // impostazione del numero di colonne e righe del display
24  lcd.begin(16, 2);
25 
26  // Carattere stampato nella prima colonna e prima riga (0,0)
27  lcd.print("*");
28}
29 
30void loop() {
31 
32  // Memorizza in val il valore presente su A0
33  // per identificare il pulsante che viene premuto.
34  int val = analogRead(A0);
35 
36  // Premendo il pulsante RIGHT sul display, il carattere si sposta di una posizione
37  // a destra fino a quando non si raggiunge l'ultima colonna a destra.
38  // Premendo ancora il pulsante RIGHT non si ha l'avanzamento del carattere.
39  if ((val >= 0 && val <= 50) && contatorePosizioneColonna < 15) {
40    lcd.scrollDisplayRight();
41    delay(200);
42    contatorePosizioneColonna++;
43  }
44 
45  // Premendo il pulsante LEFT sul display, il carattere si sposta di una posizione
46  // a sinistra fino a quando non si raggiunge l'ultima colonna a sinistra.
47  // Premendo ancora il pulsante LEFT non si ha l'avanzamento del carattere.
48  if ((val >= 300 && val <= 500) && contatorePosizioneColonna > 0) {
49    lcd.scrollDisplayLeft();
50    delay(200);
51    contatorePosizioneColonna--;
52  }
53}

Esercizio 2

Realizzare le stesse funzionalità dell’esempio 2 ed aggiungere la possibilità di selezionare il carattere da movimentare, mediante un menù iniziale in cui potrà essere fatta la selezione secondo lo schema di seguito indicato:

Pulsante SELECT: @
Pulsante DOWN : X
Pulsante UP : #

La selezione del carattere avviene una sola volta all’avvio del programma.

Esercizio 3

Eseguire le stesse funzionalità dell’esercizio 3 con la possibilità di visualizzare il menù di scelta carattere in qualsiasi momento, così da permettere la selezione del carattere da movimentare. Scegliere liberamente il pulsante da premere per visualizzare il menù.

Esempio 3

Nell’esempio che segue si mostra come movimentare da destra a sinistra due caratteri: da destra a sinistra “>” e da sinistra verso destra “<“. In questo esempio viene utilizzata il metodo setCursor() che permette di posizionare ad una colonna e riga specifica il cursore.

1/*
2   Prof. Michele Maffucci
3   Utilizzo dell'LCD Keypad Shield della Keystudio
4   Data: 14.03.2021
5 
6   Movimento ripetuto avanti e indietro:
7   - movimento verso destra stampa del carattere: >
8   - movimento verso sinistra stampa del carattere: <
9    
10*/
11 
12// inclusione della libreria LiquidCrystal.h
13#include <LiquidCrystal.h>
14 
15// Velocità con cui viene stampato il carattere 
16int velocita = 200;
17 
18// inizializza la libreria con i numeri dei pin dell'interfaccia
19LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
20 
21void setup() {
22  // impostazione del numero di colonne e righe del display
23  lcd.begin(16, 2);
24 
25  // Inizializzazione della Serial Monitor
26  Serial.begin(9600);
27}
28 
29void loop() {
30   
31  // Movimento verso destra del carattere
32  for (int contatorePosizioneColonna = 0; contatorePosizioneColonna < 16; contatorePosizioneColonna++) {
33    // Cancella il display
34    lcd.clear();
35    // Spostamento di una posizione verso destra del cursore
36    lcd.setCursor(contatorePosizioneColonna, 0);
37    // Stampa del carattere: >
38    lcd.print(">");
39    // Attesa di un'istante per percepire il movimento del carattere
40    delay(velocita);
41  }
42 
43  // Movimento verso sinistra del carattere
44  for (int contatorePosizioneColonna = 16; contatorePosizioneColonna > 0; contatorePosizioneColonna--) {
45    // Cancella il display
46    lcd.clear();
47    // Spostamento di una posizione verso sinistra del cursore
48    lcd.setCursor(contatorePosizioneColonna, 0);
49    // Stampa del carattere: >
50    lcd.print("<");
51    // Attesa di un'istante per percepire il movimento del carattere
52    delay(velocita);
53  }
54}

Esercizio 4

All’interno del ciclo for, prima di posizionare e stampare il carattere, viene cancellato il display con il metodo clear(), sapresti indicare il motivo di questa scelta? Ci sono altri modi per ottenere il medesimo comportamento (movimento)?

Buon Coding a tutti.

Arduino – Trovare il valore più grande in un array

Durante queste settimane inevitabilmente le attività di PCTO vengono svolte in parte in presenza ed in parte in remoto. Le lezioni in remoto vengono ovviamente utilizzate per risolvere dubbi e spiegare qualcosa di nuovo che possa essere di aiuto ai ragazzi. Ultimamente alcuni mie studenti di classe 3′ sono impegnati chi nella realizzazione di serre idroponiche e chi nel simulare il funzionamento di un’incubatrice neonatale, in entrambe le situazioni bisogna rilavare grandezze fisiche, come ad esempio la temperatura. Spesso è necessario leggere dai sensori in un determinato intervallo di tempo una sequenza di valori che dovranno essere memorizzati in un array e successivamente elaborati.

Come detto sopra, è spesso utile memorizzare una sequenza di numeri, ad esempio una sequenza di letture di temperatura, all’interno di un array e poi dalla lista estrarre il valore che ci interessa, ad esempio: la massima temperatura, la minima temperatura, la media, ecc…

Per fare questa operazione il metodo più semplice ed intuitivo consiste nello leggere la sequenza dei valori per cercare il più grande.

Ma come costruire un algoritmo per fare questa operazione?

Riprendo un esempio che facevo tempo fa ai ragazzi declinato da alcune spiegazioni di un vecchio libro di informatica su cui studiai io 🙂

Immaginate la seguente situazione:

il mio collega con cui lavoro in compresenza, che chiamerò Prof. Rossi, mi detta la lista dei voti assegnati ad uno di voi, non mi dice in anticipo quanti voti mi detterà, me li detta ed io devo costruire un algoritmo che mi permetterà di dire al collega qual è il voto più altro nel momento in cui mi dirà:

“basta non ci sono più voti!”,

istantaneamente, senza rileggere tutta la lista devo fornire questa informazione al collega.

Partiamo!

  • Il primo voto che mi viene dettato è “3.5”, allora lo scriverò su un foglio di carta;
  • il secondo voto è 6.75 che è più grande di 3 quindi potrebbe essere questo il massimo dei voti, cancello 3.5 e scrivo sulla pagina il 6.75;
  • subito dopo mi viene detto: “5.5” che è più piccolo di 6.75 quindi non potrà essere questo il voto più alto, lasceremo scritto sul foglio 6.75;
  • mi viene detto: “9” ed essendo più grande di 6.75 lo indico sul mio foglio, cancellando il 6.75;
  • il voto successivo è 7.25, che è inferiore al 9 e non lo riporto sul foglio;
  • il voto successivo è 8.75, che è inferiore al 9 e non lo riporto sul foglio;
  • Il Prof. Rossi mi avvisa che ha finito di dettarmi i voti ed io dirò immmediatamente che il voto massimo è 9;

Come possiamo tradurre in C questo algoritmo?

Realizziamo un Array in cui inserire la sequenza dei 6 voti:

sequenzaVoti[] = {3.5, 6.75, 5.5, 9, 7.25, 8.75};

Il passo successivo sarà quello di definire un contenitore (una variabile) in cui di volta in volta andremo a memorizzare il numero più grande che abbiamo trovato.

Definisco quindi “votoMassimo” la variabile che contiene il voto massimo temporaneo (quello che nell’esempio mi veniva dettato dal Prof. Rossi)

float votoMassimo = 0;

Sarà necessario utilizzare un ciclo for per leggere uno alla volta i voti della lista.

Il ciclo parte con indice 0 arrivando fino alla fine dell’array, cioè con indice pari a n-1 (n: dimensione dell’array), quindi l’array è costituito da n oggetti e l’indice che identifica la posizione va da 0 a n-1.

In C è possibile calcolare automaticamente la dimensione dell’array con la funzione: sizeof di cui trovate tutte le informazioni sul references di Arduino

sizeof(sequenzaVoti)/sizeof(float))

mi darà la dimensione n dell’array.

Approfondiamo quanto detto.

sizeof permette di ottenere la dimensione in byte di una variabile di qualsiasi tipo (int, float, byte, char, ecc…) o del numero di byte che occupa un array.

Attenzione però per definire un array possiamo farlo in due modi:

modo 1, indicando la dimensione tra parentesi quadre
float sequenzaVoti[6]

modo 2, enumerando gli elementi, nel nostro caso i voti, ovvero l’elenco degli oggetti
float sequenzaVoti[] = {3.5, 6.75, 5.5, 9, 7.25, 8.75};

Per sapere la dimensione in byte dell’array useremo sizeof() che restituirà la dimensione dell’array in byte.

Quindi l’operatore sizeof(sequenzaVoti) non restituirà il numero di celle dell’array, ma la sua dimensioni in byte, pertanto:

sizeof(sequenzaVoti)

restituirà come valore: 24 perchè l’array sequenzaVoti[] è costituita da 6 numeri reali (con la virgola), ciascuno di esso rappresentato da quattro byte pertanto il numero totale di byte dell’array è 6×4=24.

Per calcolare la dimensione dell’array, partendo dalla dimensione in byte ricavata da sizeof(), possiamo operare in questo modo:

1for (int i = 0; i < (sizeof(sequenzaVoti)/sizeof(float)); i++) {
2//codice…
3}

Per trovare il voto massimo bisogna verificare ad ogni ciclo del for se il valore attuale (sequenzaVoti[i]) risulta maggiore del valore che abbiamo memorizzato all’interno della variabile votoMassimo, per fare questo controllo utilizzeremo l’istruzione if:

1if (sequenzaVoti[i] > votoMassimo) {
2   // salviamo il valore massimo attuale...
3}

Se la condizione dell’if è verificata, bisogna sovrascriviamo il valore di “votoMassimo” con quello trovato della sequenza dei voti che stiamo leggendo.

votoMassimo = sequenzaVoti[i];

Detto ciò costruiamo lo sketch che, data una lista di 6 voti memorizzati in un array, stampa sulla serial monitor

Il voto massimo è:…

al posto dei puntini dovete stampare il voto massimo tra quelli scritti nell’array.
La lista dei voti, per ora, viene inserita nel codice, non dovrà essere scritta da computer sulla serial monitor.

Potete far eseguire tutto il codice di estrazione del voto massimo nel setup() con il loop() vuoto.

Per completezza con quanto spiegato, aggiungo alla stampa del voto massimo la stampa della dimensione massima dell’array sequenzaVoti[]

Il listato completo sarà:

1/*
2 * Prof. Michele Maffucci
3 * data 15.03.2021
4 *
5 * Trovare il valore più grande in un array
6 *
7 */
8 
9// sequenza di 6 voti di uno studente
10float sequenzaVoti[] = {3.5, 6.75, 5.5, 9, 7.25, 8.75};
11 
12void setup() {
13  Serial.begin(9600);
14 
15  // la variabile con il numero massimo:
16 
17  int votoMassimo = 0;
18 
19  for (int i = 0; i < (sizeof(sequenzaVoti) / sizeof(float)); i++) {
20    if (sequenzaVoti[i] > votoMassimo) {
21      // se il voto corrente è maggiore di quello
22      // salvato dentro votoMassimo allora lo copio 
23      votoMassimo = sequenzaVoti[i];
24    }
25  }
26  Serial.print("Il voto massimo è: ");
27  Serial.println(votoMassimo);
28  Serial.print("Dimensione in byte dell'array ");
29  Serial.println(sizeof(sequenzaVoti)); 
30}
31 
32void loop() {}

Esercizio 1
Realizzare uno sketch che accetta l’imputo dei voti (float) da tastiera e restituisce il voto massimo.

Esercizio 2
Realizzare uno sketch che accetta l’imputo dei voti (float) da tastiera e restituisce la media dei voti.

Buon Coding a tutti 🙂

Supporto per PIR HC-SR501

Per la realizzazione della lezione sull’uso del PIR HC-SR501 pubblicato alcuni giorni fa, per lavorare agevolmente con il sensore ho creato un semplice supporto che poi ho stampato in più copie per le sperimentazioni di laboratorio di Sistemi a scuola. Non appena ho pubblicato il post ho ricevuto alcune mail da parte di colleghi e studenti che mi hanno chiesto i sorgenti grafici del supporto.
Potete prelevare i file per la stampa 3D direttamente dalla mia pagina su Thingiverse: PIR HC-SR501 support

Buon makimg a tutti. 🙂

PCTO A.S. 2020 – 2021 – SumoBot – lezione 3

In questa lezione mostrerò uno sketch di esempio in cui la velocità, il senso di rotazione e la durata di rotazione vengono passati come parametri alle funzioni che controllano il movimento del robot. Ovviamente potrete modificare e migliorare l’esempio proposto.
Si tenga in conto che questo tipo di controllo, sia per la bassa qualità dei servomotori utilizzati, e sia per la scelta del tipo di motore, non consente una regolazione precisa, ma in ogni caso ci permette di raggiungere gli obiettivi esposti nella lezione 1.

Lo schema di collegamento a cui farò riferimento sarà quello utilizzato nella lezione precedente, che indico di seguito.

L’inizializzazione dei servomotori viene eseguita nella stessa modalità come illustrato nella lezione 2.

Le funzioni principali di orientamento del robot permettono di controllare con discreta precisione:

  • la velocità di rotazione;
  • il senso di rotazione;
  • il tempo di rotazione;

Le funzioni di controllo sono:

1antiorarioRobot()
2orarioRobot()
3stopRobot()

Le tre funzioni al loro interno utilizzano il metodo write() sugli oggetti motoreDx e motoreSx.

Le funzioni prevedono due parametri di ingresso: velocità e durata della rotazione.
Con l’impostazione della velocità impostiamo anche il senso di rotazione. Nel caso di rotazione antioraria il valore dovrà essere compreso tra 90 e 180 ed il valore scelto stabilirà anche la velocità di rotazione.

La funzione antiorarioRobot() accetta due parametri di ingresso:

  • velMaxAntioraria, massima velocità oraria
  • durata, indica la durata della rotazione in millisecondi

in questo caso i valori inseriti per la velocità dovranno essere compresi tra 0 e 90:

1void antiorarioRobot(int velMaxAntioraria, int durata) {
2  motoreDX.write(velMaxAntioraria);  // Rotazione antioraria del motore DX
3  motoreSX.write(velMaxAntioraria);  // Rotazione antioraria del motore SX
4  delay(durata);                     // durata: durata della rotazione
5}

La funzione orarioRobot() funzionerà in modo simile:

1void orarioRobot(int velMaxOraria, int durata) {
2  motoreDX.write(velMaxOraria);    // Rotazione oraria del motore DX
3  motoreSX.write(velMaxOraria);    // Rotazione oraria del motore SX
4  delay(durata);                   // durata: durata della rotazione
5}

Come esercizio invito gli studenti a realizzare un’unica funzione di comando che ingloba le due precedenti in grado di realizzare qualsiasi tipo di movimento.

La funzione stopRobot() accetta come unico parametro la durata dello stop.

1void stopRobot(int ferma) {
2  motoreDX.write(90);   // Ferma il motore DX
3  motoreSX.write(90);   // Ferma il motore SX
4  delay(ferma);         // Durata dello stop
5}

Lo sketch completo è il seguente:

1/*
2 * Prof. Maffucci Michele
3 * SumoRobot
4 * Data: 26.01.2021
5 *
6 * Sketch 02: rotazione oraria e antioraria continua
7 *            con funzioni parametrizzate
8 *
9 * Note:
10 *          L'orientamento dei motori è fatto
11 *          guardano il robot anteriormente
12 *      
13 *          180: max velocità in senso antiorario
14 *          90 : servomotori fermi
15 *          0  : max velocità in senso orario
16 *           
17 */
18 
19// inclusione della libreria servo.h per il controllo dei servomotori
20#include <Servo.h>
21 
22// Creazione oggetti servo
23Servo motoreDX;  // Inizializzazione del servomotore destro
24Servo motoreSX;  // Inizializzazione del servomotore sinistro
25 
26byte pinDx = 4;     // Inizializza del pin 4 a cui è connesso il pin segnale del servo destro
27byte pinSx = 5;     // Inizializza del pin 5 a cui è connesso il pin segnale del servo sinistro
28 
29void setup() {
30 
31  // attach() consente di definire a quale pin viene connesso il servomotore
32  // e lo collega all'oggetto che gestisce il servomotore
33   
34  motoreDX.attach(pinDx); // pinDx collegato al motore destro
35  motoreSX.attach(pinSx); // pinSx collegato al motore sinistro
36}
37 
38void loop() {
39  orarioRobot(30, 250);      // Rotazione in senso orario del robot
40  stopRobot(3000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
41  antiorarioRobot(150, 250); // Rotazione in senso antiorario del robot
42  stopRobot(3000);           // Stop rotazione per un tempo fissato (vedere variabile ferma)
43}
44 
45// rotazione del robot in senso antiorario
46// velMaxOraria: velocità massima in senso antiorario
47// durata: durata della rotazione
48 
49void antiorarioRobot(int velMaxAntioraria, int durata) {
50  motoreDX.write(velMaxAntioraria);  // Rotazione antioraria del motore DX
51  motoreSX.write(velMaxAntioraria);  // Rotazione antioraria del motore SX
52  delay(durata);                     // durata: durata della rotazione
53}
54 
55// rotazione del robot in senso orario
56// velMaxOraria: velocità massima in senso orario
57// durata: durata della rotazione
58 
59void orarioRobot(int velMaxOraria, int durata) {
60  motoreDX.write(velMaxOraria);    // Rotazione oraria del motore DX
61  motoreSX.write(velMaxOraria);    // Rotazione oraria del motore SX
62  delay(durata);                   // durata: durata della rotazione
63}
64 
65// stop del robot
66// ferma: durata dello stop del robot
67 
68void stopRobot(int ferma) {
69  motoreDX.write(90);   // Ferma il motore DX
70  motoreSX.write(90);   // Ferma il motore SX
71  delay(ferma);         // Durata dello stop
72}

I tempi indicati inseriti nelle funzioni all’interno del loop potranno essere modificati secondo necessità.

Esercizio 01
Elenca le cause che provocano errori nel far ruotare precisamente di un determinato angolo scelto il robot.

Esercizio 02
Utilizzando un filo di connessione e modificando lo sketch precedente siete in grado di realizzare n sistema di START/STOP del robot.

Buon Coding a tutti 🙂