Come ottenere più valori da una funzione in Arduino: variabili globali, riferimenti e struct – lezione 1/2

Durante la correzione delle esercitazioni di laboratorio mi accorgo spesso che il passaggio dei valori alle funzioni è un punto che genera parecchia confusione. Per questo ho deciso di preparare una breve lezione di ripasso, per chiarire i concetti fondamentali e aiutare a scegliere l’approccio più corretto nello sviluppo degli sketch.

Uno dei problemi molto comuni quando si programma in C/C++ su Arduino è: come ottenere più di un valore da una funzione?

In molti casi vorremmo che una funzione ci restituisse, ad esempio, due risultati (come nello scambio di due numeri), ma il linguaggio prevede che una funzione possa avere un solo valore di ritorno con l’istruzione return. Questo non significa che siamo bloccati: esistono più strategie corrette per gestire più risultati in modo chiaro e sicuro.

Partiremo da una soluzione semplice e intuitiva, basata su variabili globali, utile per capire il concetto ma generalmente sconsigliata nei programmi reali perché può creare effetti collaterali difficili da controllare. Passeremo poi a un approccio molto più robusto: il passaggio per riferimento, che permette a una funzione di modificare direttamente le variabili del chiamante senza ricorrere a globali. Infine vedremo l’uso dell’istruzione struct, cioè “contenitori” di più campi, che consentono di raggruppare dati correlati e di restituirli come un unico oggetto.

L’obiettivo non è solo far funzionare gli esempi, ma capire cosa succede davvero in memoria quando una funzione riceve parametri “per valore” (copie) oppure “per riferimento” (accesso diretto all’originale) e perché la scelta del metodo influisce su leggibilità, manutenzione e affidabilità del codice. Al termine della lezione saprete riconoscere quale tecnica usare a seconda del problema e scrivere funzioni più pulite, modulari e facili da riutilizzare.

Vedremo poi nella prossima lezione una quarta variante molto diffusa nel mondo embedded.

01. Versione “semplice” (ma sconsigliata): usare variabili globali

Esempio 01: scambio di valori

La funzione non “restituisce” due valori: modifica direttamente due variabili definite fuori da loop().

/*
  Prof. Maffucci Michele
  13.02.26
  Scambio di due valori usando variabili globali.
*/

int valoreA;
int valoreB;

void scambiaGlobali() {
  int temporaneo = valoreA;
  valoreA = valoreB;
  valoreB = temporaneo;
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  valoreA = random(10);
  valoreB = random(10);

  Serial.print("Valori prima dello scambio (A, B): ");
  Serial.print(valoreA);
  Serial.print(", ");
  Serial.println(valoreB);

  scambiaGlobali();

  Serial.print("Valori dopo lo scambio (A, B):  ");
  Serial.print(valoreA);
  Serial.print(", ");
  Serial.println(valoreB);

  Serial.println();
  delay(1000);
}

Esempio 02: la funzione restituisce minimo e massimo aggiornando variabili globali.

Sulla serial monitor vengono mostrati ogni 5 secondi: la serie di 20 numeri generati, il minimo della serie, il massimo della serie.

/*
  Prof. Maffucci Michele
  13.02.26
  Calcola minimo e massimo su una serie di campioni usando variabili globali.
*/

int minimoCampione;
int massimoCampione;

void calcolaMinMaxGlobali(int numeroCampioni) {
  minimoCampione = 9999;
  massimoCampione = -9999;

  Serial.print("Campioni: ");

  for (int i = 0; i < numeroCampioni; i++) {
    int campione = random(0, 101); // 0..100

    // Stampa i campioni separati da virgola
    Serial.print(campione);
    if (i < numeroCampioni - 1) {
      Serial.print(", ");
    } else {
      Serial.println(); // a capo dopo l'ultimo campione
    }

    // Aggiorna minimo e massimo
    if (campione < minimoCampione) {
      minimoCampione = campione;
    }
    if (campione > massimoCampione) {
      massimoCampione = campione;
    }
  }
}

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A0));
}

void loop() {
  const int numeroCampioni = 20;

  Serial.print("Genero ");
  Serial.print(numeroCampioni);
  Serial.println(" campioni casuali (0..100) e calcolo min/max...");

  calcolaMinMaxGlobali(numeroCampioni);

  Serial.print("Minimo trovato: ");
  Serial.println(minimoCampione);

  Serial.print("Massimo trovato: ");
  Serial.println(massimoCampione);

  Serial.println();
  delay(5000);
}

02. Passaggio per riferimento

Esempio 01: Scambia due valori passati per riferimento.

/*
  Prof. Maffucci Michele
  13.02.25
  Scambia due valori passati per riferimento.
*/

void scambiaPerRiferimento(int &a, int &b) {
  int temporaneo = a;
  a = b;
  b = temporaneo;
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  int numero1 = random(10);
  int numero2 = random(10);

  Serial.print("Valori prima dello scambio (n1, n2): ");
  Serial.print(numero1);
  Serial.print(", ");
  Serial.println(numero2);

  scambiaPerRiferimento(numero1, numero2);

  Serial.print("Valori dopo lo scambio (n1, n2):  ");
  Serial.print(numero1);
  Serial.print(", ");
  Serial.println(numero2);

  Serial.println();
  delay(1000);
}

Esempio 02: divisione con resto (quoziente + resto)

Nello sketch che segue una funzione calcola due risultati (quoziente e resto) tramite riferimenti, e in più restituisce true/false per gestire il caso del divisore zero.

/*
  Prof. Maffucci Michele
  13.02.26
  Calcola due risultati (quoziente e resto) tramite riferimenti, 
  restituisce true/false per gestire il caso del divisore zero.
*/

bool dividiConResto(int numeratore, int denominatore, int &quoziente, int &resto) {
  if (denominatore == 0) {
    return false; // errore: divisione per zero
  }

  quoziente = numeratore / denominatore;
  resto = numeratore % denominatore;
  return true;
}

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A0));
}

void loop() {
  int a = random(0, 101);   // 0..100
  int b = random(0, 11);    // 0..10 (include lo zero apposta)

  int q = 0;
  int r = 0;

  Serial.print("Operazione: ");
  Serial.print(a);
  Serial.print(" / ");
  Serial.println(b);

  if (dividiConResto(a, b, q, r)) {
    Serial.print("Quoziente: ");
    Serial.println(q);

    Serial.print("Resto: ");
    Serial.println(r);
  } else {
    Serial.println("Errore: divisione per zero (b = 0).");
  }

  Serial.println();
  delay(1500);
}

03. Scambio di valori versione migliorata. Trattare più valori insieme: usare una struct

Con la struct impacchettiamo più campi in un solo tipo (una “coppia”), la passiamo alla funzione e la funzione restituisce una nuova struct con i campi scambiati.

Esercizio 01: scambio di valori

/*
  Prof. Maffucci Michele
  13.02.26
  Scambio di valori usando una struct.
*/

struct Coppia {
  int primo;
  int secondo;
};

Coppia scambiaCoppia(Coppia c) {
  int temporaneo = c.primo;
  c.primo = c.secondo;
  c.secondo = temporaneo;
  return c;
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  Coppia dati = { random(10), random(10) };

  Serial.print("Valori prima dello scambio (p, s): ");
  Serial.print(dati.primo);
  Serial.print(", ");
  Serial.println(dati.secondo);

  dati = scambiaCoppia(dati);

  Serial.print("Valori dopo lo scambio (p, s):  ");
  Serial.print(dati.primo);
  Serial.print(", ");
  Serial.println(dati.secondo);

  Serial.println();
  delay(1000);
}

Esempio 02: Lettura analogica completa (raw + volt + percentuale)

La funzione ritorna un oggetto con tre valori: lettura grezza, tensione stimata e percentuale.

/*
  Prof. MAffucci Michele
  13.02.26
  Restituisce più valori raggruppandoli in una struct.
*/

struct LetturaAnalogica {
  int raw;          // 0..1023
  float volt;       // tensione stimata
  int percentuale;  // 0..100
};

const int PIN_INGRESSO = A0;
const float VREF = 5.0; // se usi una scheda a 3.3V, imposta 3.3

LetturaAnalogica leggiAnalogicoCompleto(int pin) {
  LetturaAnalogica risultato;

  risultato.raw = analogRead(pin);
  risultato.volt = risultato.raw * (VREF / 1023.0);
  risultato.percentuale = map(risultato.raw, 0, 1023, 0, 100);

  return risultato;
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  LetturaAnalogica misura = leggiAnalogicoCompleto(PIN_INGRESSO);

  Serial.print("Ingresso A0 -> raw: ");
  Serial.print(misura.raw);

  Serial.print(" | V: ");
  Serial.print(misura.volt, 2);

  Serial.print(" | %: ");
  Serial.println(misura.percentuale);

  delay(500);
}

Abbiamo visto tre strategie diverse per gestire più risultati in una funzione. E’ fondamentale scegliere quale usare nei vostri sketch, è importante capire bene cosa cambia tra passaggio per valore, passaggio per riferimento e uso di una struct.

Riassumo di seguito.

Passaggio dei valori a una funzione

Quando viene chiamata una funzione, potete consegnare i dati in due modi principali:

  1. Per valore (default)
  • la funzione riceve una copia dei parametri;
  • se dentro la funzione modificate quei parametri, state modificando la copia, non le variabili originali;
  • risultato: fuori dalla funzione i valori non cambiano.
  1. Per riferimento (&) — tipico in Arduino perché è C++

  • la funzione riceve un alias delle variabili originali;
  • dentro la funzione, quando assegnate a = …, state scrivendo proprio nella variabile chiamante.
  • risultato: fuori dalla funzione i valori cambiano davvero.

Nota: in C “puro” non esistono i riferimenti, quindi si userebbero puntatori (int *a, int *b). Arduino, però, compila in C++: i riferimenti sono disponibili.

Quando usare una struct (o un tipo “aggregato”)

La struct è utile quando:

  • volete trattare più valori come un unico oggetto logico (es. coordinate, min/max, stato di sensori, ecc.);
  • volete restituire più informazioni in un colpo solo (una sola return, ma con più campi dentro);
  • volete migliorare leggibilità: c.primo, c.secondo comunica il significato meglio di due variabili scollegate.

Costo/beneficio nell’uso della struct

  • Pro: codice più espressivo, dati “impacchettati”, interfaccia pulita.
  • Contro: c’è una copia della struct quando la passi/ritorni (di solito trascurabile se la struct è piccola). Su microcontrollori molto limitati, per struct grandi conviene passare per riferimento anche la struct.

Come detto ad inizio di questo post, nella prossima lezione vedremo una quarta variante molto diffusa nel mondo embedded: gli output parameters con puntatori (stile C) e una versione più moderna che usa const per rendere immediatamente chiaro quali dati sono solo in ingresso e quali vengono modificati dalla funzione.

Buon Coding a tutti 🙂

Arduino nello zaino: 4 “laboratori” trasportabili stampabili in 3D per avere sempre una base di prototipazione pronta

Chi fa didattica laboratoriale (o semplicemente ama sperimentare) lo sa: il problema non è avere gli strumenti, ma riuscire a portare con sé una dotazione minima che permetta di accendere il cervello “maker” ovunque ci si trovi.

Io ho già i miei laboratori completi, a casa e a scuola, dove posso fare tutto ciò che mi serve, però nello zaino porto sempre una piccola base di sperimentazione: una scheda Arduino, una breadboard, qualche cavetto e pochi componenti selezionati. Non è un “mini laboratorio” nel senso classico del termine, ma è qualcosa di altrettanto prezioso: un sistema ordinato e trasportabile che riduce l’attrito e rende immediata qualsiasi micro-attività.

In questo post vi segnalo 4 tipologie di contenitori/workstation stampabili in 3D pensate proprio per questo: tenere insieme scheda, breadboard, jumper e componenti, proteggere il setup e arrivare in aula (o ovunque) già pronto a partire.

Perché ritengo che questi organizer siano utili anche se avete un laboratorio completo

  • setup più veloce: appoggi, apri, colleghi l’USB e inizi;
  • ordine e componenti “a prova di zaino”: meno dispersione, meno “dov’è finito quel cavetto?”;
  • micro-attività replicabili: perfetti per dimostrazioni, tutoraggi, ASL, attività itineranti, laboratori in aule non attrezzate;
  • continuità nelle sperimentazioni personali: potete riprendere un prototipo esattamente dov’era rimasto, senza ricostruire tutto da zero.

All’organizer associo anche un piccolo contenitore rigido in cui dispongo ulteriori componenti elettronici.

The Folding Arduino Lab (il “classico” da zaino)

È quello che uso da sempre: The Folding Arduino Lab di Jason Welsh già segnalato qualche tempo fa su questo sito.
L’idea è semplice: un contenitore compatto che integra Arduino + breadboard (400 punti) + cassetti per cavetti e componenti. In uno spazio ridotto (indicativamente 10×9×8 cm) vi portate dietro l’essenziale.

I motivi per cui uso questa soluzione sono:

  • struttura “a libro”: protegge il setup e lo rende trasportabile, ovviamente non bisogna pretendere molti componenti sulla breadboard;
  • due vani/cassetti: ottimi per jumper, LED, resistenze, pulsanti, piccoli sensori;
  • è un progetto con molte varianti e remix: facile trovare adattamenti e accessori;
  • nota personale: l’autore ha sviluppato diverse versioni; io attualmente utilizzo la versione 2, su cui ho montato un Arduino UNO R4 WiFi.

Vi segnalo che con questo kit potete evitare, per le cerniere, l’uso di elementi metallici che possono essere sostituiti con filamento per la stampa 3D che risultano relativamente robusti e rimovibili.

Supporto/Stazione di lavoro modulare per Arduino UNO e breadboard (modulare e “scalabile”)

Questa soluzione è pensata come una workstation regolabile e modulare, ideale se vuoi una base ordinata non solo per trasporto, ma anche per lavorare “pulito” su banco (e poi richiudere e portare via).
La Modular Arduino UNO Breadboard Holder/Workstation (V2) è dichiarata come progetto modulare, con inserti, tray e mount selezionabili, e con impostazioni/accortezze legate alla stampa “print-in-place” in alcune parti.

Caratteristiche interessanti

  • modularità reale: potete scegliere vassoi/inserti in base a cosa usate (jumper, sensori, viteria, ecc.);
  • approccio “workstation” più che “scatola”: molto comoda per lavorare in modo ordinato;
  • ottima se volete aggiungere nel tempo moduli e supporti (display, sensori, ecc.).

Portable Arduino Lab (PAL) – molto compatto

Il Portable Arduino Lab (PAL) è una versione più piccola della workstation, pensata esplicitamente per “piccoli progetti on the go”, è dichiarato compatibile con Arduino UNO R3 e UNO R4.

Cosa mi piace

  • È progettato come “compagno di laboratorio”: base + chiusura + possibilità di storage;
  • ha indicazioni di stampa molto chiare: per esempio layer height 0,2 mm e attenzione alle tolleranze della cerniera/parti in movimento;
  • pPrevede anche opzioni e aggiornamenti: ad esempio supporti per breakout (ESP32 / Arduino Nano) sono citati tra gli update del progetto.

Nota pratica

In alcune configurazioni richiede viteria (M3x25) e una piccola fase di assemblaggio; non è un difetto, ma una scelta per robustezza e funzionalità.

Arduino R4 Laboratorio Portatile – “print in place” dedicato a UNO R4

Questa soluzione è centrata su Arduino UNO R4 e punta alla massima portabilità con la logica “print-in-place”. È indicato l’uso con breadboard da 400 punti e il fissaggio della scheda con viti M2.5 (fino a una certa lunghezza). (Seguire il link per prelevare i file per la stampa)

Scegliere questa soluzione se:

  • lavorate principalmente con UNO R4 e volete un contenitore dedicato.
  • se vi interessa un progetto già impostato con un layout essenziale: scheda + breadboard + vano.

Cosa mettere nello zaino

Se volete rendere davvero efficace uno di questi organizer, la differenza la fa la scelta dei componenti. Io ragiono per “massima resa didattica con minimo volume”:

  • Arduino (nel mio caso UNO R4 WiFi) + cavo USB;
  • breadboard 400 punti + cavetti jumper (M-M, M-F, F-F in piccola quantità);
  • set micro: LED + resistenze, 1–2 pulsanti, 1 potenziometro;
  • 1 sensore “jolly” (LDR o temperatura/umidità) + 1 attuatore (buzzer o micro-servo);
  • mini cacciavite / pinzetta, un paio di cavetti Dupont extra;
  • (opzionale) Power bank se volete lavorare senza PC per attività specifiche.

Sto realizzando in questi mesi una versione di un mini laboratorio trasportabile contenuto in una rugged bag, le classiche valigette a tenuta stagna molto robuste, le uso spesso per la realizzazione di giochi escape o per contenere apparati delicati, se riuscirò vi mostrerò più avanti il risultato.

Buon Making a tutti 🙂

Domande dagli utenti: “puoi chiarire il concetto di negativo in comune?”

Continuo con la serie delle domande che mi sono giunte sul gruppo Facebook BBC micro:bit Italy, questa volta dall’amico: Davide

ciao Michele Maffucci, uno degli altri “problemi” che ho notato che non capiscono, quando alimenti separatamente, il “negativo in comune”
Magari un giorno affronta l’argomento 🙂

Quando si alimenta separatamente (micro:bit o Arduino da una fonte e motori/driver da un’altra), molti si bloccano sul concetto di “negativo in comune”. Un modo semplice per capirlo è l’esempio dell’ascensore che spesso faccio durante le mie lezioni.

Immagina due persone che vogliono incontrarsi in un edificio:

  • la prima usa come riferimento il piano terra e dice: “sono al 2° piano”;
  • la seconda, però, considera “piano terra” il 1° piano (ha spostato lo zero): anche lei dice “sono al 2° piano”, ma in realtà si trova su un livello diverso.

Risultato: usano numeri uguali, ma riferiti a zeri diversi, quindi non riescono a coordinarsi e incontrarsi.

In elettronica succede la stessa cosa: un segnale “alto” (ad esempio 3,3 V) significa 3,3 V rispetto a un riferimento, cioè rispetto alla massa (GND). Se micro:bit e driver/servo non condividono la stessa massa, quel “3,3 V” può non essere interpretato correttamente perché lo “zero” dell’uno non coincide con lo “zero” dell’altro.

Nota importante: massa e terra non sono la stessa cosa (anche se a volte coincidono)

  • Massa / GND (0 V di riferimento): è il potenziale comune di riferimento del circuito, spesso chiamato anche 0 V. È il “piano terra” della nostra analogia: lo zero rispetto a cui misuriamo e capiamo i segnali.
  • Terra / PE (Protective Earth – protezione): è il collegamento all’impianto di terra, usato soprattutto per sicurezza elettrica (scariche, guasti, schermature).

In molti dispositivi alimentati da rete, la massa del circuito può essere collegata alla terra, e in quel caso massa e terra finiscono per trovarsi allo stesso potenziale e spesso si parla di “0 V”.

In sistemi a batteria (micro:bit, driver, servo, pacchi AA/AAA) come ad esempio i nostri robot didattici, non esiste una “terra” fisica collegata all’impianto: esiste solo la massa come riferimento comune.

Quindi, quando diciamo “mettere il negativo in comune”, intendiamo:

“Rendere comune il riferimento (GND) tra i dispositivi che devono scambiarsi segnali.”

in altro modo:

GND micro:bit < - > GND driver/servo < - > GND batteria motori

In breve: potete tenere alimentazioni separate, ma dovete rendere comune il riferimento (GND), altrimenti i segnali non hanno un “piano zero” condiviso e il controllo diventa instabile.

Schema pratico

GND micro:bit ─────────┐
GND driver/motor board ├──> punto massa comune
GND batteria motori ───┘

Il concetto è: micro:bit invia il segnale, il driver lo interpreta, ma entrambi devono riferirsi allo stesso “0 V”.

Schema di collegamento – casi tipici

A. micro:bit + driver motori DC (ponte H / Motor driver)

  • Batteria motori + (positivo) > Vmot / +VIN driver
  • Batteria motori (negativo) > GND driver
  • micro:bit pin (PWM/direzione) > IN1/IN2/ENA… (driver)
  • micro:bit GND > GND driver (fondamentale)

IMPORTANTE: non serve collegare i “positivi” tra loro; serve collegare i GND.

B. micro:bit + servo (alimentazione servo separata)

  • Batteria servo + (positivo) > V+ servo
  • Batteria servo (negativo) > GND servo
  • micro:bit pin segnale > SIG servo
  • micro:bit GND > GND servo

Senza GND in comune il servo può tremare, non rispondere o muoversi in modo erratico.

C. micro:bit alimentata e motori sullo stesso pacco batterie (solo se il pacco è adeguato)

  • Stesso pacco batterie > micro:bit (tramite regolazione corretta) + driver;
  • GND è già comune per costruzione;
  • è pratico, ma attenzione ai disturbi: spesso conviene comunque separare la potenza motori.

Accorgimenti costruttivi utili

  • collegare “a stella” le masse, ovvero un punto comune su cui colleghiamo tutte le masse vicino al driver/alimentazione motori, evitare se possibile collegamenti di masse in cascata;
  • mantenere i cavi motore e quelli di segnale separati quando possibile;
  • aggiungere condensatori di disaccoppiamento vicino al driver/servi (se il kit non li integra già).

Per approfondimenti consiglio la lettura del post: Sensori e attuatori lontani da Arduino: guida pratica al cablaggio corretto i consigli che vengono forniti possono essere adottati anche per la costruzione dei nostri robot didattici.

Questi concetti verranno approfonditi in modo pratico durante il mio prossimo corso di robotica.

Buon Making a tutti.

Domande dagli utenti: perché micro:bit non pilota i motori direttamente?


Nella giornata di ieri mi è arrivata una domanda molto sensata, una di quelle che prima o poi ci si pone tutti quando si prova a far muovere un robot con micro:bit o con Arduino.

“Se micro:bit riuscisse a passare da 3V a 5V si risparmierebbero i costi della scheda di espansione, nonché l’ottimizzazione degli spazi. Lei è d’accordo? Chissà perché non lo fanno: ormai tutti abbiamo bisogno di motorini.”

La risposta breve è questa:

Capisco il ragionamento, ma il vero ostacolo non è 3 V vs 5 V. Il punto è che un pin di micro:bit non è uno stadio di potenza.
Anche se la scheda fosse “a 5 V”, non potresti comunque collegare un motore direttamente ai pin in modo sicuro e affidabile.

Vediamo perché, con esempi concreti e riferimenti ai due kit che uso spesso nei corsi: Ring:bit V2 board e Kitronik :MOVE mini.

La spiegazione che segue è volutamente semplificata in quanto non necessariamente i colleghi che seguono i miei corsi sono docenti di materie di indirizzo tecnico.

Perché “alzare la tensione” non risolve il problema

Corrente: il motore chiede molta più energia di quella che un pin può dare

Un motore (anche piccolo) non “vuole solo tensione”: vuole soprattutto corrente, e ne vuole parecchia quando parte (corrente di spunto) e quando è sotto sforzo (ruote che spingono, attrito, urti).

Un pin GPIO di una scheda a microcontrollore è progettato per segnali e piccoli carichi, non per alimentare carichi elettromeccanici. Se provate a farlo, i sintomi tipici sono:

  • reset improvvisi della scheda,
  • comportamenti instabili,
  • surriscaldamento,
  • nel peggiore dei casi danni ai pin o al microcontrollore.

Disturbi e picchi: il motore “sporca” l’alimentazione e genera back-EMF

Il motore è un carico induttivo: quando viene acceso/spento o se ne cambia la velocità, può generare picchi di tensione (back-EMF) e disturbi elettrici che:

  • mandano in crisi la logica,
  • creano interferenze (anche sulla radio/BT),
  • degradano l’affidabilità nel tempo.

Serve un driver: lo “stadio di potenza” che separa logica e motore.

Per pilotare un motore DC, ad esempio quelli gialli che tipicamente vengono usati nei progetti didattici di robotica, serve uno stadio di potenza, cioè un driver motore, per esempio:

  • ponte H (per andare avanti/indietro e fare PWM in modo robusto),
  • oppure MOSFET + protezioni (se serve solo on/off o un verso).

Il driver fa tre cose fondamentali:

  • regge la corrente (anche i picchi),
  • gestisce la direzione e la velocità (PWM),
  • protegge micro:bit dai disturbi e dai picchi del motore.

Citando la richiesta dell’utente: “Ma allora perché micro:bit non è a 5V?”

In realtà molte schede “vivono” già in ambienti dove esistono 5 V (ad esempio USB), ma l’elettronica interna e i pin di I/O lavorano a bassa tensione (tipicamente 3,3 V) perché:

  • si riducono consumi e riscaldamento,
  • si protegge meglio la scheda,
  • si mantiene compatibilità con sensori moderni a bassa tensione,
  • e soprattutto (punto chiave): anche a 5 V i pin non diventerebbero “pilotamotori”.

Quindi: passare a 5 V non eliminerebbe la necessità di un driver. Cambierebbe solo alcuni dettagli di alimentazione/compatibilità, ma non la sostanza.

Il caso reale nei kit: Ring:bit V2 board e Kitronik :MOVE mini

Ring:bit V2 board: non è “la scheda che pilota motori”

La Ring:bit V2 board è principalmente una scheda di espansione/breakout:

  • rende più comodi alcuni collegamenti (ad esempio porte tipo GVS su P0/P1/P2),
  • integra un portabatterie (3×AAA) per alimentare il sistema/il robot,
  • fornisce un’interfaccia pratica per prototipare.

Va interpretata come interfaccia e distribuzione di alimentazione/connessioni, non come “micro:bit che pilota motori direttamente”.

Ring:bit V2

Kitronik :MOVE mini: usa servomotori, non motori DC senza elettronica di controllo integrata

La scheda Kitronik :MOVE mini può controllare due servomotori a rotazione continua. Questa scelta è utile per la didattica, perché un servo:

  • contiene già la propria elettronica di pilotaggio,
  • si controlla con un semplice segnale PWM (impulsi “stile servo”),
  • prende l’energia dal pacco batterie/board del kit, non dai pin di micro:bit.

In pratica:

  • micro:bit invia il comando (PWM),
  • il servo esegue, usando la sua alimentazione dedicata.

Questo è il motivo per cui, con :MOVE mini, si riesce ad avere un robot “semplice” e robusto senza introdurre subito il tema dei ponti H per motori DC.

:MOVE mini

Cosa vedremo nel corso: motori DC “veri” e driver dedicati

Durante il corso mostrerò anche l’altro scenario, quello tipico quando si usano i classici motori gialli da 6 V (motori DC con riduttore), dove il driver è obbligatorio.

motore TT

Lavoreremo in particolare con:

  • L298N (ottimo per capire il concetto di ponte H e cablaggi, anche se non è la soluzione più efficiente in assoluto),
  • Motor:bit di ELECFREAKS (più compatta e didattica, comoda per micro:bit).

Obiettivo: far capire chiaramente la differenza tra:

  • “motore DC” (serve driver + alimentazione adeguata),
  • “servo” (driver interno, controllo PWM più diretto).

Regola utile sempre: alimentazione separata e masse in comune

Quando si entra nel mondo motori/attuatori, una buona pratica è:

  • alimentare i motori/servi con una linea robusta (batterie/pack dedicato),
  • e mantenere massa (GND) in comune tra microcontrollore e driver/attuatori (quando richiesto), così i segnali di controllo hanno un riferimento corretto.

Questa singola regola elimina moltissimi “misteri” (reset, comportamenti casuali, servo che impazziscono).

Qualche precisazione in più sui motori DC o motori senza elettronica di controllo integrata

Troverete spesso la dicitura motori bare DC motor in pratica sono motori che hanno solo due terminali (o due fili):

  • fornite tensione > girano
  • togliete tensione > si fermano
  • invertite la polarità > invertono il verso di rotazione (se lo permettete elettricamente)

In ambito tecnico anglofono è abbastanza comune parlare di “bare DC motor” per indicare un motore senza elettronica di controllo integrata (cioè “il solo motore”, tipicamente a due fili) e spesso anche senza riduttore/struttura accessoria.

Esempi tipici:

  • i classici motori gialli TT 3–6 V usati nei robot economici
  • motorini DC “a spazzole” da modellismo o recuperati da giocattoli

I bare DC motor non hanno al loro interno:

  • driver di potenza
  • protezioni contro i picchi (back-EMF)
  • logica per interpretare un segnale di controllo

Quindi, per farli funzionare con micro:bit, serve aggiungere elettronica esterna:

  • un ponte H (es. L298N, TB6612, DRV8833) se vuoi avanti/indietro + PWM
  • oppure un MOSFET + diodo se ti basta on/off (e magari un solo verso)

L298N

TB6612

DRV8833

Differenza con un servo (o un motoriduttore “intelligente”)

Un servomotore (anche a rotazione continua) invece non è senza elettronica di controllo perché contiene già:

  • elettronica di pilotaggio
  • circuito di potenza
  • logica che interpreta il comando (impulsi PWM stile servo)

Per questo il micro:bit può “comandare” un servo con un semplice segnale, mentre con un motore DC senza elettronica di controllo deve essere gestito da un driver.

Buon Making a tutti 🙂

Dietro le quinte del corso “Robotica educativa a basso costo”: da DotBot:bit a Codino

In questi giorni sto lavorando alla preparazione della 6ª edizione del corso di robotica a basso costo ed ho rimesso mano a uno dei “classici” del mio laboratorio: DotBot:bit. Chi segue il sito da tempo lo conosce: nasceva come robottino essenziale per portare in classe micro:bit con un approccio pratico, replicabile e sostenibile.

Perché ripartire da DotBot:bit e perché aggiornarlo

DotBot:bit era nato con un obiettivo molto chiaro: fare robotica con materiali semplici, valorizzando la didattica laboratoriale e la possibilità di iterare rapidamente tra:

idea > prototipo > test > miglioramento.

Oggi lo scenario in classe è ancora più vario: c’è chi lavora con schede e moduli differenti, chi ha la stampa 3D, chi invece preferisce (o deve) restare sul cartone e su soluzioni ultra-economiche. Per questo ho progettato un’evoluzione concreta e “da corso”.

Nasce Codino: una struttura, due piattaforme

La novità si chiama Codino: una struttura aggiornata (derivata da DotBot:bit) pensata per ospitare in alternativa due setup molto diffusi in ambito micro:bit:

  • Ring:bit V2
  • Kitronik :MOVE mini

entrambe le schede hanno form factor compatto.

L’idea è semplice ma didatticamente potente: stessa “scocca” di progetto, due piattaforme, così il corso (e le attività in classe) si adattano ai vincoli reali: disponibilità di materiali, budget, tempi, livello della classe.

Cosa sto preparando per il corso

Durante la preparazione sto lavorando su tre fronti, tutti pensati per diventare attività trasferibili in classe:

  • Adattamento meccanico e modularità
    Montaggi rapidi, sostituzione della scheda senza rifare tutto da capo, riduzione delle parti “critiche” mi riferisco a quelle che si rompono o richiedono manutenzione.
  • Percorsi di prova “a difficoltà crescente”
    Dal primo movimento controllato fino a micro-sfide: traiettorie, correzioni, test su attrito e peso, ragionamento su stabilità e distribuzione delle masse.
  • Codino è pensato per arrivare senza frizioni alle attività che introdurrò in questa edizione più lunga:
    • controllo con gesture recognition via webcam (ML addestrato su gesti)
    • mini-progetti di Sumo
    • primi prototipi di braccio robot (meccanica essenziale + attuazione)
    • Robot semplici realizzati con Arduino

Tutti questi sono i contenuti extra resi possibili dall’estensione a 4 lezioni della 6ª edizione.

Stampa 3D o cartone: stesso progetto, due strade

Come nel DNA di DotBot:bit, anche Codino resta coerente con l’impostazione “basso costo”:

  • per chi ha una stampante 3D: struttura stampabile e facilmente iterabile;
  • per chi non ce l’ha: template e sagome in cartone, per costruire comunque un robot completo e funzionante.

Questo approccio “doppio” è ciò che rende il kit davvero spendibile: non è un modello unico, è un format replicabile.

Se volete seguire l’evoluzione e portarla in classe

Se vi interessa vedere Codino in azione e, soprattutto, costruire un percorso completo da replicare con i tuoi studenti, la 6ª edizione del corso “Creare un kit di robotica educativa a basso costo” parte il 16 gennaio 2026 e prosegue fino al 3 febbraio 2026 (4 incontri).

Nei prossimi giorni pubblicherò anche qualche foto “work in progress” della struttura Codino ed altri robot.

Buon Making a tutti 🙂