Archivi categoria: arduino

Arduino: strutturare il codice in blocchi funzionali

Molto spesso durante le prime fasi di realizzazione di uno sketch Arduino si tende a non strutturare il proprio programma in blocchi funzionali separati, tutto il codice viene inserito all’interno del loop(). Questo tipo di approccio, soprattutto se siamo in presenza di un codice molto lungo, rende difficoltosa la lettura del programma da parte di altre persone e non permette una facile comprensione del funzionamento o l’identificazione di possibili errori.

Ho parlato in passato come strutturare il codice in blocchi funzionali nel post:
Arduino – lezione 07: lavorare con gruppi di valori e funzioni esterne, ma in quella lezione utilizzavo istruzioni che in questa fase dell’anno scolastico non sono ancora conosciute da alcuni allievi soprattutto del 3′ anno, che iniziano ad utilizzare Arduino, pertanto la presente lezione dovrebbe chiarire in modo più semplice l’argomento.

Le funzioni vengono utilizzate per organizzare le azioni eseguite dal vostro programma. Ogni funzione può essere identificata da un’azione specifica richiamata dal programma principale loop(), oppure richiamate da altre funzioni sempre all’interno del nostro sketch.

Senza saperlo quando avete iniziato a programmare con Arduino avete utilizzato delle funzioni: loop() e setup() le due funzioni sempre presenti in ogni sketch.

Per creare una funzione bisogna:

  • definire il tipo di valore restituito dalla funzione;
  • assegnare un nome alla funzione;
  • e opzionalmente impostare una serie di parametri che la funzione riceverà quando viene chiamata (si dice anche invocata).

Creiamo una semplice funzione che permette di fare lampeggiare un LED, non possiede parametri e non restituisce nessun valore.
Assegnare alla funzione il tipo void vuol dire che non restituisce nulla e non inserire nulla tra le parentesi tonde indica che la funzione non accetta nessun parametro.

Esempio 1

// Prof. Michele Maffucci
// Es.01 - Usare le funzioni
// Data: 15.11.2020

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  lampeggia();
}

// blink LED una volta
void lampeggia()
{
  digitalWrite(LED_BUILTIN, HIGH); // accende il LED
  delay(1000); // pausa di 1 secondo
  digitalWrite(LED_BUILTIN, LOW); // spegne il LED
  delay(1000); // pausa di 1 secondo
}

Ogni volta che il loop() chiama (invoca) la funzione esterna lampeggia() viene effettuato il blink del LED sulla scheda.

Esempio 2

Realizziamo ora un secondo esempio in cui la funzione “lampeggia” accetta come parametro un valore intero che definisce il delay da impostare all’interno del funzione.

// Prof. Michele Maffucci
// Es.02 - Usare le funzioni
// Data: 15.11.2020

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // chiamiamo la funzione lampeggia passando il valore
  // specificato all'interno delle parentesi tonde
  lampeggia(250);
}

// blink LED una volta
// per far si che la funzione accetti un parametro in input
// bisogna dichiarare il tipo del parametro in ingresso
// nella funzione lampeggia: int pausa

void lampeggia(int pausa)
{
  digitalWrite(LED_BUILTIN, HIGH); // accende il LED
  delay(pausa); // pausa: valore inserito nella variabile "pausa"
  digitalWrite(LED_BUILTIN, LOW); // spegne il LED
  delay(pausa); // pausa: valore inserito nella variabile "pausa"
}

Esempio 3

Realizziamo ora un terzo sketch in cui i parametri di ingresso per la funzione lampeggia() sono due, uno che definisce il tempo di accensione del LED ed uno che definisce il tempo di spegnimento del LED:

// Prof. Michele Maffucci
// Es.03 - Usare le funzioni
// Data: 15.11.2020

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // chiamiamo la funzione lampeggia passando il valore
  // specificato all'interno delle parentesi tonde
  lampeggia(250, 1000);
}

// blink LED una volta
// per far si che la funzione accetti duen parametri in input
// bisogna dichiarare il tipo per ogni parametro in ingresso
// nella funzione lampeggia: int pausaOn e int pausaOff

void lampeggia(int pausaOn, int pausaOff)
{
  digitalWrite(LED_BUILTIN, HIGH); // accende il LED
  delay(pausaOn); // delay LED ON
  digitalWrite(LED_BUILTIN, LOW); // spegne il LED
  delay(pausaOff); // delay LED OFF
}

Esempio 4

Definiamo ora una funzione che ha 3 parametri di ingresso: il tempo in cui il LED rimane acceso, il tempo in cui il LED rimane spento e il numero di volte (cicli) che deve ripetersi il lampeggio, al termine del numero di cicli il LED non lampeggerà più. Come specificato nei commenti la variabile chiave verrà utilizzata per eseguire una volta sola la chiamata della funzione lampeggio:

// Prof. Michele Maffucci
// Es.04 - Usare le funzioni
// Data: 15.11.2020

// chiave e la variabile che consente l'esecuzione della
// chiamata della funzione lampegga una sola volta
int chiave = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // chiamiamo la funzione lampeggia passando il valore
  // specificato all'interno delle parentesi tonde
  if (chiave == 0) {
    chiave = 1;
    lampeggia(250, 1000, 5);
  }
}

// blink LED una volta
// per far si che la funzione accetti tre parametri in input
// bisogna dichiarare il tipo per ogni parametro in ingresso
// nella funzione lampeggia: int pausaOn, int pausaOff, int contatore
// la variabile contatore definisce il numero di cicli di lampeggio

void lampeggia(int pausaOn, int pausaOff, int contatore)
{
  for (int i = 0; i < contatore; i++) {
    digitalWrite(LED_BUILTIN, HIGH); // accende il LED
    delay(pausaOn); // delay LED ON
    digitalWrite(LED_BUILTIN, LOW); // spegne il LED
    delay(pausaOff); // delay LED OFF
  }
}

All’interno dello sketch precedente la funzione lampeggio utilizza un ciclo for per ripetere, per il numero di volte specificato dalla variabile contatore, il codice di accensione e spegnimento (corpo del for).

Esempio 5

Per completezza e per richiamare il modo con cui utilizzare l’istruzione while, di seguito trovate lo sketch che realizza la medesima funzionalità dello sketch precedente in cui il ciclo for viene sostituito da un while:

// Prof. Michele Maffucci
// Es.05 - Usare le funzioni
// Data: 15.11.2020

// chiave e la variabile che consente l'esecuzione della
// chiamata della funzione lampegga una sola volta
int chiave = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // chiamiamo la funzione lampeggia passando il valore
  // specificato all'interno delle parentesi tonde
  if (chiave == 0) {
    chiave = 1;
    lampeggia(250, 1000, 5);
  }
}

// blink LED una volta
// per far si che la funzione accetti tre parametri in input
// bisogna dichiarare il tipo per ogni parametro in ingresso
// nella funzione lampeggia: int pausaOn, int pausaOff, int contatore
// la variabile contatore definisce il numero di cicli di lampeggio

void lampeggia(int pausaOn, int pausaOff, int contatore)
{
  while (contatore > 0) {
     digitalWrite(LED_BUILTIN, HIGH); // accende il LED
    delay(pausaOn); // delay LED ON
    digitalWrite(LED_BUILTIN, LOW); // spegne il LED
    delay(pausaOff); // delay LED OFF
    contatore = contatore - 1; // decremento del contatore
  }
}

Esempio 6

Nello sketch che segue realizziamo una funzione che accetta un parametro e restituisce un valore. Il parametro che viene passato alla funzione definisce la durata dei tempi di accensione e spegnimento del LED (in millisecondi). La funzione continua a far lampeggiare un LED fino a quando non viene premuto un pulsante. Il valore restituito dalla funzione è il numero di lampeggi effettuati, questo valore verrà stampato sulla Serial Monitor:

// Prof. Michele Maffucci
// Es.06 - Usare le funzioni
// Data: 15.11.2020

const int pinPulsante = 8; // pin a cui colleghiamo il pulsante

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(pinPulsante, INPUT);
  Serial.begin(9600);
}

void loop() {
  Serial.println("Premere il pulsante per interrompere il lampeggio");
  int contatore = lampeggia(500); // lampeggio del LED: 500 ms ON e 500 ms OFF
  Serial.print("Il numero di volte in cui il LED ha lampeggiato è stato di: ");
  Serial.println(contatore);
  while (digitalRead(pinPulsante) == HIGH)
  {
    // non viene fatto nulla fino a quando non rilascio il pulsante
  }
}

// la funzione fa lampeggiare il LED per un periodo specificato (int periodo)
// e restituisce il numero di volte in cui il LED ha lampeggiato

int lampeggia(int periodo)
{
  int contatoreLampeggio = 0;

  while (digitalRead(pinPulsante) == LOW)
    // ripetere finché non viene premuto il pulsante
    // cicla fino a quando il pulsante non viene premuto
  {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(periodo);
    digitalWrite(LED_BUILTIN, LOW);
    delay(periodo);
    contatoreLampeggio = contatoreLampeggio + 1; // incrementa il contatore
  }
  // in questo punto vuol dire che pinPulsante è HIGH
  // ciò vuol dire che il pulsante è premuto

  // contatoreLampeggio è il valore che viene restituito alla funzione chiamante
  return contatoreLampeggio;
}

Il tipo di dato che precede in nome della funzione:

int lampeggia()

indica il tipo di dato restituito dalla funzione. Ricordarsi che nella funzione chiamante, nel nostro caso il loop(), quando chiamiamo la funzione questa deve terminare con un punto e virgola:

int contatore = lampeggia(500);

Errori comuni che vengono commessi nella chiamata di funzioni

Rimando a queste due brevi note che mostrano alcuni errori tipici:

Buon Making a tutti 🙂

Esercizi per i miei studenti

Esercizio 1

Realizzare un circuito costituito da 4 pulsanti e 4 led, connessi ad Arduino.

  • Alla pressione del pulsante P1 il LED1 effettua il blink con un tempo di 200 ms
  • Alla pressione del pulsante P2 il LED2 effettua il blink con un tempo di 400 ms
  • Alla pressione del pulsante P3 il LED3 effettua il blink con un tempo di 600 ms
  • Alla pressione del pulsante P4 il LED4 effettua il blink con un tempo di 800 ms

Fare in modo tale che ci sia una funzione esterna, chiamata dal loop(), che effettui il blink dei led.

Esercizio 2

Aggiungere all’esercizio 1 un pulsante che se premuto accende in sequenza ripetuta i 4 led. L’accensione in sequenza deve avvenire chiamando una funzione esterna al loop().

Arduino: tipi di dati – ripasso

Noto che durante le sperimentazioni condotte dagli allievi, l’uso dei tipi di dati provoca alcune incertezze, pertanto ho pensato di aggiungere a quanto già pubblicato in passato, una tabella riepilogativa da prendere come riferimento durante le eseritazioni aggiungendo inoltre qualche precisazione. Noto che nella dichiarazione di variabili la scelta più comune del tipo di dato utilizzato è l’int (intero), però molto spesso può essere non necessario o addirittura può aggiungere imprecisioni o errori.

Sebbene il tipo di dati int (abbreviazione di intero) sia la scelta più comune per valori numerici incontrati nelle applicazioni Arduino, è possibile utilizzare le tabelle che segue per determinare il tipo di dati più opportuno, che si adatta all’intervallo di valori previsto dal vostro programma. La tabella mostra i tipi di dati per le schede a 8 bit come Arduino UNO R3.

Tipo di dato

Byte

Intervallo

Uso

int 2 –32768 a 32767 Rappresenta valori interi positivi e negativi.
unsigned int 2 0 a 65535 Rappresenta solo valori interi positivi.
long 4 –2147483648 a 2147483647 Rappresenta un intervallo di interi negativi e positivi molto più estesa rispetto agli int.
unsigned long 4 0 a 4294967295 Rappresenta solo valori interi positivi con intervallo più ampio degli unsigned int.
float 4 3.4028235E+38 a –3.4028235E+38 Rappresenta numeri con la virgola, da utilizzare per rappresentare e approssimare valori che giungono dal mondo reale.
double 4 Come i float In Arduino, double ha lo stesso utilizzo e significato di float, un sinonimo (ciò non è vero per schede a 32 bit).
bool 1 TRUE (1) o FALSE (0) Rappresenta valori veri o falsi.
char 1 –128 a 127 Rappresenta un singolo carattere. Può anche rappresentare un intero con segno compreso tra –128 e 127.
byte 1 0 a 255 Simile al tipo char, ma per valori senza segno.
String Rappresenta una sequenza di caratteri tipicamente utilizzata per contenere il una stringa di testo.
void Utilizzato solo nelle dichiarazioni di funzione in cui non viene restituito alcun valore.

In generale, come potete vedere anche negli sketch di esempio presenti nell’IDE di Arduino, gran parte delle variabli utilizzate è di tipo int, inoltre se non è richiesta la massima efficienza della memoria di Arduino l’uso di int non è un errore, ma ovviamente il tipo int può essere utilizzato solo se i valori che state gestendo non superano l’intervallo degli int e non è necessario lavorare con numeri decimali.

Certamente molto spesso è necessario utilizzare un tipo di dato specifico per la propria applicazione, ciò accade quando ad esempio utilizziamo specifiche funzioni di libreria che restituiscono valori che non appartengono all’intervallo del tipo int.

A scopo di esempio considerate la funzione millis che restituisce il numero di millisecondi trascorsi dall’avvio del programma.

unsigned long ora;

void setup() {
  // inizializzazione della erial Monitor
  Serial.begin(9600);
}
void loop() {
  Serial.print("Ora: ");
  ora = millis();

  Serial.println(ora); // stampa l'ora (in millisecondi) dall'avvio dello sketch
  delay(1000);         // attesa di un secono, viene utilizzato per non stampare
                       // velocemente una grande quantità di valori sulla Serial Monitor
}

Il tipo di valore restituito, come indicato nel reference, è un unsigned long valori compresi tra 0 e 4294967295.

Se usate un tipo int su una scheda a 8 bit per memorizzare un valore restituito da millis() non riceverete un messaggio di errore dal compilatore, ma verranno restituiti valori numerici sbagliati perché un int non è abbastanza grande da contenere il valore massimo di un unsigned long. Se provate a cambiare tipo nello sketch indicato sopra vedrete che dopo aver raggiunto il valore 32.767, il conteggio passerà a -32768.

Se invece provate a sostituire un long, –2147483648 a 2147483647 con un
unsigned int (intero senza segno) 0 a 65535, tornerete a zero dopo aver superato il massimo massimo (65535).

Alcune precisazioni

  • Durante le vostre sperimentazioni avrete bisogno a volte di valori con segno e a volte no, ecco perché sono stati resi disponibili tipi di dati con segno (signed) e senza segno (unsigned). I valori senza segno sono sempre positivi;
  • tutti i tipi che NON recano davanti la parola: unsigned possono assumere valori negativi e positivi;
  • una variabile senza segno (unsigned) può memorizzare il doppio dei valori numerici di una variabile con segno (signed);
  • nella notazione è esplicitato sempre quando la variabile è di tipo unsigned perché in questo modo viene reso evdente che quella variabile non assume valori negativi.

Dalla tabella si può notare che i tipi bool (booleani) hanno due possibili valori: vero o falso. Questo tipo di dato viene utilizzato in genere per memorizzare valori che rappresentano una condizione ON/OFF oppure in altro modo SI/NO.

Potresete vedere tipi booleani utilizzati al posto delle costanti HIGH e LOW utilizzati all’interno ad esempio di una digitalWrite() per impostare l’uscita di un pin digitale, qundi le scritture:

digitalWrite(pinLed,HIGH);
e
digitalWrite(pinLed,1);

digitalWrite(pinLed,LOW);
e
digitalWrite(pinLed,0);

Indicano la stessa cosa.

La stessa cosa accade per una digitalRead() nel caso in cui noi si debba leggere lo stato di un pin digitale. Potete qundi utilizzare true o false al posto di HIGH e LOW o ancora 1 o 0.

Esercizi per i miei studenti

Esercizio 1
Partendo dall’esempio indicato in questa lezione sulla stampa del valore restituito dalla funzione millis(), realizzare un programma che restituisca i valori di millis() memorizzati in tre variabili di tipo diverso:

unsigned long ora1;
int ora2;
unsigned int ora3;

stampare il valore delle tre variabili sulla Serial Monitor per dimostrare quanto affermato in questa lezione.

Esercizio 2
Realizzare le stese funzionalità dell’esercizio precedete aggiungendo un pulsante che se premuto azzera le tre variabili e fa ripartire (partendo da zero) la stampa sulla Serial Monitor.

Esercizio 3
Realizzare le stesse funzionalità dell’eserizio 2 aggiungendo 3 LED, ciascuno indicherà per un tempo di accensione di 10 secondi il superamento del limite del range del tipo di variabile a cui si riferisce es.:

LED1 -> ora1
LED2 -> ora2
LED3 -> ora3

Buon Making a tutti 🙂

Arduino: utilizzo del metodo parseInt() per la conversione di un stringa di testo che rappresenta un numero in un numero

Nel primo esercizio della lezione: Arduino: Stepper 28BYJ-48 – AccelStepper library veniva chiesto di impostare i parametri di azionamento del motore passo paso da Serial Monitor, questa operazione può essere svolta usando la classe toInt(), ma in modo più efficace e semplice possiamo usare la classe parseInt(). In questa breve lezione un esempio di controllo del lampeggio di un LED da Serial Monitor mediante l’uso di parseInt().

È possibile ricevere numeri con più di una cifra utilizzando i metodi parseInt e parseFloat che semplificano l’estrazione di valori numerici da seriale. (Funziona anche con Ethernet e altri oggetti derivati dalla classe Stream)

Serial.parseInt() e Serial.parseFloat() leggono i caratteri seriali e restituiscono la loro rappresentazione numerica.

I caratteri non numerici prima del numero vengono ignorati e il numero termina con il primo carattere che non è una cifra numerica (o “.” Se si utilizza parseFloat). Se non ci sono caratteri numerici nell’input, le funzioni restituiscono 0, quindi bisogna controllare i valori zero e gestirli in modo appropriato.

Nel dettaglio

  • I caratteri iniziali che non sono cifre o sono numeri negativi vengono ignorati;
  • L’analisi si interrompe quando non sono stati letti caratteri per un valore di tempo di timeout che può essere configurato oppure viene letta una non cifra;
  • Se non sono state lette cifre valide quando si verifica il timeout (vedere Serial.setTimeout ()), viene restituito 0; Serial.parseInt () eredita dalla classe Stream.

Se avete la Serial Monitor configurata per inviare una nuova riga o un ritorno a capo (o entrambi) quando fate clic su invia, parseInt o parseFloat proveranno ad interpretare il return come numero, ma poiché il ritorno a capo non è un numero il valore restituito da parseInt o parseFloat sarà zero.

Nell’esempio che segue un invio imposta blinkRitardo a zero il che implica che il LED non lampeggia.

// Prof. Maffucci Michele
// 10.11.2020
// Impostazione del delay del Blink da tastiera

int lampeggioRitardo = 0;
int chiave = 0;
void setup()
{
  Serial.begin(9600); // inizializzazione della serial monitor
  pinMode(LED_BUILTIN, OUTPUT); // imposta il pin come output
}
void loop()
{
  // ritardo per evitare una doppia scrittura
  // della prima stampa a monitor
  delay(1000);

  // consente di visualizzare sulla Serial Monitor
  // una sola stampa delle stringa
  if (chiave == 0) {
    Serial.print("Inserisci il ritardo in millisecondi: ");
    chiave = 1;
  }

  // Controlla se è disponibile almeno un carattere sulla seriale
  // La Serial.available() restituisce
  // 1 se presente un cattere,
  // 0 se non è presente un carattere
  
  if (Serial.available())
  {
    int r = Serial.parseInt(); // in r viene memorizzato il valore inserito in numero
    if (r != 0) {
      lampeggioRitardo = r;
      Serial.println(lampeggioRitardo);

      // abilita alla stampa di una nuova stringa:
      // "Inserisci il ritardo in millisecondi: "
      chiave = 0;
    }
  }
  lampeggio(); // funzione che fa lampeggiare il LED su Arduino
}

// il LED lampeggia con i tempi di
// accensione e spegnimento determinati da lampeggioRitardo
void lampeggio()
{
  digitalWrite(LED_BUILTIN, HIGH);
  delay(lampeggioRitardo); // il delay dipende dal valore in lampeggioRitardo
  digitalWrite(LED_BUILTIN, LOW);
  delay(lampeggioRitardo);
}

Esercizio 1
Dato un LED RGB connesso ad Arduino, realizzare un selettore che da Serial Monitor consente di controllare l’accensione e lo spegnimento del rosso, del verde e del blu

Esercizio 2
Svolgere l’esercizio 1 della lezione Stepper 28BYJ-48 – AccelStepper library usando la parseInt()

Arduino: Stepper 28BYJ-48 – AccelStepper library

La libreria Stepper Arduino è ottima per controllare un solo stepper, ma quando si desidera controllare velocità e accelerazione dello stepper oppure è necessario controllare contemporaneamente più stepper bisogna utilizzare la libreria AccelStepper.

In questo breve tutorial vedremo come controllare velocità e accelerazione ed in una successiva lezione controlleremo più stepper.

AccelStepper aggiunge le seguenti funzionalità:

  • accelerazione e decelerazione;
  • supporta il mezzo passo;
  • controllo di più stepper simultaneamente e simultaneamente si possono far fare passi indipendenti su ogni stepper.

AccelStepper non è inclusa nell’IDE di Arduino, bisognerà installarla.

Installazione della libreria

Per installare la libreria, andare in Sketch > Include Library > Manage Libraries…

Nel campo di ricerca inserire “AccelStepper”. Selezionare la prima voce che compare e procedere con l’installazione

Lo schema elettrico di collegamento è il medesimo visto nella lezione precedente, potete utilizzare entrambi gli schemi proposti, con alimentazione presa direttamente da Arduino o con alimentazione esterna che vi consiglio.

Codice Arduino

Di seguito lo sketch di esempio “Bounce”, che permette l’accelerazione del motore passo-passo in una direzione per decelerare e poi fermarsi. Trovate lo sketch “Bounce” tra gli esempi a corredo della libreria, su questo programma ho apportato alcune modifiche inserendo i commenti che ne spiegano il funzionamento.

// Bounce
// Prof. Maffucci Michele
//
// Una sola rotazione in accelerazione da 0 a 2048 e viceversa

// inclusione della libreria AccelStepper
#include <AccelStepper.h>

// definizione di una costante
// funzionamento:
// in fullstep  impostare 4
// in halfstemp impostare 8
#define FULLSTEP 4

// creazione dell'istanza della classe mioStepper
/*
   IN1 -> 8
   IN2 -> 9
   IN3 -> 10
   IN4 -> 11
*/
AccelStepper mioStepper(FULLSTEP, 8, 10, 9, 11);

void setup() {

  // impostare la velocità massima,
  // accelerazione,
  // velocità iniziale
  // numero di passi da compiere

  mioStepper.setMaxSpeed(1000);
  mioStepper.setAcceleration(50);
  mioStepper.setSpeed(100);
  mioStepper.moveTo(2048);
}

void loop()
{

  // distanceToGo restituisce il numero di passi compiuti.
  // Se distanceToGo raggiunge lo zero, cioè numero di passi è uguale a zero
  // inverte il senso di rotazione assegnando un valore negativo al numero di passi
  // da compiere.

  if (mioStepper.distanceToGo() == 0)
    mioStepper.moveTo(-mioStepper.currentPosition());

  // se non è stato raggiunto il valore zero, muove lo stepper di un passo
  mioStepper.run();
}

Per maggiori informazioni vi rimando alla pagina di riferimento della libreria

Esercizi per i miei studenti

Esercizio 1
Realizzare uno sketch che da serial monitor permetta all’avvio di Arduino l’impostazione di:

  • velocità massima;
  • accelerazione;
  • velocità iniziale;
  • numero di passi da compiere;

Con l’inserimento dell’ultimo parametro ed il successivo invio si avvia lo stepper.

Esercizio 2
Eseguire le stesse funzionalità dell’esercizio precedente, ma l’avvio dello Stepper avviene solamente alla pressione di un pulsante.

Esercizio 3
Aggiungere all’esercizio precedente un pulsante di stop che permetta di interrompe in qualsiasi momento la rotazione dello stepper.

Modificare un motore passo passo 28BYJ-48 da unipolare a bipolare

Scrivo questo breve tutorial perché in questi giorni sto progettando i prototipi delle attività didattiche che spero potranno essere realizzati dai miei studenti nel mese di febbraio prossimo durante le attività di PCTO. Tra le future attività la realizzazione di più bracci robot da controllare con Arduino e PLC Siemens. Il braccio robot che sto realizzando è costituito da 3 motori passo passo 28BYJ-48 ed un servomotore. La scelta del 28BYJ-48 rispetto ai più potenti NEMA 17 risiede semplicemente nei costi di realizzazione per me e i miei studenti che vorranno replicare il progetto.

Poiché ho l’esigenza di aumentare il numero di grammi al centimetro che possono essere spostati/sollevati dal braccio ho convertito il passo passo 28BYJ-48 da unipolare a bipolare.

Questo motore passo passo è molto piccolo ma ha una potenza sufficiente per realizzare diverse sperimentazioni. Nello scorso anno scolastico, sempre durante le attività di PCTO, alcuni miei studenti hanno sviluppato l’automazione di un’ascensore la cui struttura portante era da me stata realizzata e tagliata a laser, mente i ragazzi si sono occupati dell’assemblaggio delle parti e della programmazione.

Il 28BYJ-48, come detto nel mio precedente post, è disponibile in due versione, con alimentazione a 5V e a 12V, le due versioni sono identiche, differiscono ovviamente per l’impedenza interna. In questo breve tutorial userò la versione a 12V, ma la procedura è la medesima per la versione a 5V.

Il motore passo passo possiede un riduttore incorporato da 1/64 ciò implica un passo molto piccolo del motore 0,087890625 gradi per passo. Il riduttore ha però un aspetto negativo, ne riduce la velocità di rotazione, ma possiamo sopportare questa sua lentezza considerando il fatto che il prezzo dei questo motore è estremamente contenuto, la versione a 5V può essere acquistata online a non più di 2,5 € e quindi per piccole sperimentazioni è più che sufficiente.

In funzione della modo con cui viene pilotato questo passo passo può raggiungere i 300 gcm in half step, per raggiunge i 380 gcm quando si passa a full step.

Gli stepper bipolari sono più efficienti di quelli unipolari in essi viene alimentata una sola bobina per volta (1/2 una bobina per essere precisi) mentre per i bipolare entrambe le bobine sono alimentate, quindi si ottiene una coppia maggiore.

L’immagine di seguito mostra ciò che accade in un passo passo bipolare.

Sono presenti due avvolgimenti anziché quattro rispetto ad uno stepper unipolare. Entrambi gli avvolgimenti possono essere attivi in qualsiasi momento ma la polarità viene commutata su quattro fasi, ciò vuol dire che questo motore ha solo quattro fili anziché 5 (o 6 o 8).

Per convertire un 28BYJ-48 da unipolare a bipolare bisogna interrompere la connessione indicata in rosso nell’immagine, quella contrassegnata con 2 + 3 + 6 + 7. La configurazione diventerebbe come quella rappresentata nell’immagine di sinistra.

Per effettuare questa conversione è sufficiente un cutter ed un cacciavite. Come indicato nell’immagine che segue, utilizzate il cacciavite per sollevare il cappuccio azzurro che protegge un piccolo circuito elettronico in cui noterete 11 punti di saldatura, questo circuito non fa altro che collegare le varie bobine del passo passo.

Interrompete la pista centrale come indicato nell’immagine in questo modo renderemo il passo passo bipolare.
Questa modifica potrà farvi raggiungere gli 800 gcm che è almeno il doppio rispetto all’unipolare in full step (380 gcm) e quasi 3 volte di più per un unipolare half step (300 gcm).

A questo punto avremo bisogno di un driver che consenta il pilotaggio del motore, per questo potreste utilizzare L293D oppure un ULN2003 o ancora un A4988.

Fate riferimento agli articoli passati.

Non dimenticare di regolare al minimo la corrente del vostro driver A4988 / DRV8825, in quanto per questi motori non è possibile fornire più di 100 mA per fase, se superate questo valore potreste distruggere il motore.

Buon Making a tutti. 🙂