Archivi tag: coding

Progettare bene, programmare meglio: diagrammi di flusso – Lezione 1/5

Ripasso di inizio anno – appunti per la classe.

Perché bisogna imparare a realizzare i diagrammi di flusso (anche se “programmiamo poco”)?

Quando progetti un programma per Arduino, il problema più grande non è scrivere le parentesi giuste: è decidere l’ordine delle azioni e quando prendere decisioni. Un diagramma di flusso è un disegno semplice che mostra i passi da compiere, le scelte “sì/no” e l’ordine in cui tutto accade. È usato in informatica da decenni proprio per rappresentare, passo-passo, il comportamento di un algoritmo o di un processo.

Un flowchart ti aiuta a vedere il programma prima di scriverlo: rettangoli per le azioni (es. “accendi LED”), rombi per le domande (es. “pulsante premuto?”), ovali per inizio/fine, parallelogrammi per ingresso/uscita di dati, frecce per la direzione. L’idea è sempre quella: dall’alto verso il basso, una freccia alla volta, fino all’uscita. Questa notazione è diventata uno standard di fatto e, nelle versioni “complete”, include molte altre forme utili (ne esistono decine); noi useremo solo quelle essenziali.

Dove si usano e perché ci interessano in laboratorio di sistemi

I diagrammi di flusso non servono solo a chi programma: si usano per documentare, spiegare e migliorare processi in tanti contesti (scuola, aziende, sanità, logistica). Nel nostro laboratorio li usiamo per tradurre un problema reale (una luce che si accende, un sensore che decide) in una sequenza chiara. Questo approccio è lo stesso che trovi nel project management: rappresentare un processo rende più facile pianificare, allineare il team e trovare i colli di bottiglia.

Esistono poi varianti “cugine” dei flowchart che potresti incontrare:

  • Workflow (flusso di lavoro), molto usato per capire chi fa cosa e quando;
  • Swimlane (corsie), utile quando più persone o sottosistemi collaborano;
  • Data Flow Diagram / DFD (flusso di dati), focalizzato su come circolano i dati tra parti di un sistema.

Noi partiamo dal flowchart di base (azioni/decisioni) perché è il ponte più diretto verso il codice Arduino

Buone pratiche “da prima riga di codice”

  • Definisci il problema in una frase (“Cosa voglio ottenere?”).
  • Elenca i passi e le decisioni (domande “sì/no”).
  • Disegna il flusso con poche forme standard (Inizio > Azioni > Decisioni > Fine).
  • Cerca le inefficienze: passaggi inutili, decisioni doppie, attese esagerate.
  • Condividi e rivedi: il diagramma è un documento vivo; aggiornatelo quando cambi idea.

Questa routine è identica a quella usata nei team professionali quando costruiscono o migliorano un processo.

Dalla carta al digitale (e al testo)

Puoi disegnare su carta, usare strumenti visuali come Lucidchart o Miro (trascini le forme e colleghi con frecce), oppure scrivere i diagrammi come testo con Mermaid (“diagram as code”), che si integra bene nei siti e nelle note tecniche. In questa lezione useremo Mermaid proprio per abituarci a ragionare prima in blocchi, poi in pseudocodice, poi in C/C++ per Arduino.

Mappa veloce “flowchart > Arduino”

Inizio / Setup > setup(): qui imposti i pin come INPUT/OUTPUT.
Azione → istruzioni come digitalWrite(), analogWrite(), tone().
Decisione (rombo) > if (...) { ... } else { ... }, spesso con letture da sensori: digitalRead(), analogRead().
Ciclo > loop() che ripete le azioni in sequenza.
Questa corrispondenza 1:1 rende naturale “tradurre” il disegno in codice, riducendo gli errori e il tempo di debug. (Rivedremo questa mappa in ogni esempio pratico.)

Cosa evitare all’inizio

  • Frecce che si incrociano: rendono il percorso confuso.
  • Domande ambigue: un rombo = una domanda con risposta sì/no chiara.
  • Simboli inventati: resta su 4–5 forme standard; andrai veloce e capirai tutto al volo.
  • Salti di logica: se ti perdi, torna ai passi del processo (definisci > elenca > disegna > verifica).

Un buon diagramma di flusso è come una ricetta: indica ingredienti (sensori/attuatori), passaggi (azioni), domande al cuoco (“la pasta è al dente?” > sì/no). Se la ricetta è chiara, il codice funziona e tutti in team capiscono cosa fare.

Nota per i lettori (studenti e non): nei paragrafi successivi troverai la pipeline completa che useremo sempre: Problema > Diagramma (Mermaid) > Pseudocodice > Sketch Arduino, con esempi concreti (LED, pulsante, LDR, buzzer). Questa struttura è pensata per classi che iniziano: potete seguirla anche se non hai mai scritto una riga di codice.

Simboli nei diagrammi di flusso: poche forme bastano

L’elenco delle forme può sembrare infinito, ma non serve conoscerle tutte. Ogni simbolo indica un tipo di passaggio preciso e ha un contesto d’uso ben definito. Quando disegni, se ti senti perso, torna all’essenziale: per la grande maggioranza dei diagrammi bastano davvero alcune forme base; le altre servono in casi specifici. Qui sotto trovi quelle più ricorrenti.

Forme comuni del flowchart

Simbolo del diagramma di flusso Nome Descrizione
Inizio/Fine Segna il punto di avvio o la conclusione del flusso; delimita i confini del processo.
Processo / Azione Indica un passo operativo: un’attività, una funzione o un’elaborazione che “fa qualcosa”.
Decisione Rappresenta una domanda binaria (sì/no, vero/falso) che dirama il percorso su esiti diversi.
Input/Output (Dati) Mostra un ingresso (dato in arrivo, misura, comando) o un’uscita(risultato, messaggio, documento).
Linea di flusso Definisce la direzione della sequenza tra le forme; chiarisce l’ordine dei passi.
Sottoprocesso / Processo predefinito Collega a una procedura già definita altrove o a un gruppo di azioni consolidate.
Connettore in pagina Unisce parti lontane dello stesso schema senza incrociare frecce; migliora la leggibilità.
Connettore fuori pagina Collega a un continua su un’altra pagina; spesso include un riferimento o un codice.
Documento Indica la produzione o l’uso di un documento (ordine, report, lettera, promemoria).
Documenti multipli Come sopra, ma per più documenti generati/gestiti nello stesso passaggio.
Input manuale L’utente digita o inserisce dati a mano (es. login, compilazione di un campo).
Operazione manuale Passo che richiede intervento umano (non automatizzato) per proseguire.
Database / Archivio dati Dati archiviati in modo strutturato e interrogabili (lettura/scrittura/filtri).
Memoria interna Dati conservati all’interno del sistema/dispositivo durante l’elaborazione.
Attesa / Ritardo Indica una pausa temporale o un ritardo prima del passo successivo.
Commento / Nota Aggiunge chiarimenti al lettore; si collega con linea tratteggiata alla parte pertinente.

Alcune varianti di forma e naming possono cambiare leggermente a seconda dello strumento o dello standard adottato; l’insieme di base rimane comunque coerente tra le principali piattaforme.

Nella prossima lezione vedremo quali tool utilizzare per disegnare diagrammi di flusso.

Buon Coding a tutti 🙂

Corso di Processing – lezione 10

Variabili in Processing: dichiarazione, tipi e utilizzo

Una variabile è uno spazio di memoria con un nome, in cui possiamo memorizzare dati da usare e modificare nel corso del nostro programma. In Processing, le variabili sono fondamentali per personalizzare il comportamento degli oggetti grafici, mantenere lo stato del programma, contare, animare, verificare condizioni e molto altro.

1. Cos’è una variabile?

Potete immaginare una variabile come una scatola etichettata in cui potete inserire (e cambiare) un valore. Ogni scatola ha:

  • un nome
  • un tipo di dato
  • un valore (che può cambiare)

Sintassi base:

tipo nome = valore;

Esempio:

int lato = 50; // dichiara una variabile intera chiamata "lato" e le assegna il valore 50

2. Tipi principali di variabili in Processing

Numeri interi – int

Valori numerici senza decimali.

int x = 100;

Numeri con virgola – float

Numeri decimali.

float trasparenza = 127.5;

Valori logici – boolean

Può essere solo true (vero) o false (falso).

boolean attivo = true;

Testi – String

Sequenze di caratteri tra virgolette.

String saluto = "Ciao mondo!";

3. Usare variabili per disegnare

Possiamo usare le variabili per controllare dimensioni, posizione, colore, e altri aspetti grafici.

Esempio: dimensione variabile per un cerchio

int diametro = 100;

void setup() {
  size(400, 400);
  background(255);
  fill(0, 150, 255);
  ellipse(width/2, height/2, diametro, diametro);
}

Modifica il valore di diametro per vedere come cambia il disegno.

4. Variabili e animazioni

Le variabili possono essere aggiornate nel tempo per creare un movimento.

Esempio: far muovere un cerchio

float x = 0;

void setup() {
  size(400, 400);
}

void draw() {
  background(255);
  fill(255, 0, 0);
  ellipse(x, 200, 50, 50);
  x = x + 2; // ogni frame aumenta la posizione
}


Continua a leggere

Corso di Processing – lezione 09

Cosa sono gli eventi?

Rilevare eventi con mousePressed() e keyPressed() in Processing

Durante l’esecuzione di un programma, possono verificarsi azioni che non dipendono direttamente dal flusso continuo del codice, ma da interazioni esterne, come un clic del mouse, la pressione di un tasto o altri cambiamenti. Queste azioni prendono il nome di eventi.

In Processing, gli eventi che gestiamo più frequentemente sono quelli legati al mouse e alla tastiera. Per rispondere a questi eventi, il linguaggio ci mette a disposizione blocchi di codice speciali, simili a setup() e draw(), ma con una differenza fondamentale: il loro contenuto non viene eseguito automaticamente all’avvio del programma, né ripetuto in loop.

Le funzioni evento, come mousePressed() o keyPressed(), vengono eseguite una sola volta, solo quando si verifica una specifica azione dell’utente, come ad esempio un clic o la pressione di un tasto. Questo permette di rendere i nostri sketch interattivi e reattivi, eseguendo istruzioni solo al momento giusto.

1. La funzione mousePressed()

Questa funzione si attiva ogni volta che l’utente preme un tasto del mouse.

Esempio 1: disegnare un quadrato dove si fa clic

void setup() {
size(400, 400);
background(255);
}

void draw() {
// Vuoto, perché disegniamo solo quando si clicca
}

void mousePressed() {
fill(0, 200, 100);
noStroke();
rect(mouseX, mouseY, 40, 40);
}

Ogni clic del mouse disegna un nuovo quadrato verde nella posizione del puntatore.

2. La funzione keyPressed()

Viene eseguita ogni volta che si preme un tasto sulla tastiera.

Esempio 2: aumentare la dimensione di un cerchio premendo i tasti “+” o “-“

int diametro = 50;
void setup() {
  size(400, 400);
}

void draw() {
  background(255);
  fill(100, 100, 255);
  ellipse(width/2, height/2, diametro, diametro);
}

void keyPressed() {
  if (key == '+') {
    diametro += 10;
  } else if (key == '-') {
    diametro = max(10, diametro - 10);
  }
}

Premi + per ingrandire il cerchio e - per rimpicciolirlo, con un limite minimo.

Continua a leggere

Lezione 7 – Corso di Elettronica Creativa con Arduino Sensor Kit

Utilizzo del microfono analogico

In questa lezione vedremo come utilizzare il sensore di suono integrato nell’Arduino Sensor Kit, leggeremo il segnale analogico prodotto con l’istruzione analogRead() e ne interpreteremo i valori.
Verrà introdotto, in modo estremamente semplice il concetto di decibel e vedremo come procedere alla calibrazione del microfono in funzione delle attività di sperimentazione che verranno proposte.

Il microfono del Sensor Kit è pre‑cablat​o sulla linea analogica A0 tramite il connettore Grove, quindi non sono necessari ulteriori collegamenti.

Principio di funzionamento

Il modulo Grove Sound Sensor è un ottimo strumento per misurare i rumori intorno a voi. Quando l’aria vibra a causa di un suono, una sottile membrana nel microfono si piega avanti e indietro. Questi movimenti generano una variazione di tensione: più forte è il suono, più grande è la variazione e quindi più alto sarà il numero che andremo a leggere con Arduino mediante l’istruzione analogRead().

Approfondimento tecnico

Per chi ha qualche competenza in più in elettronica aggiungo che all’interno del modulo è presente un microfono a elettrete o microfono electret collegato a un piccolo amplificatore (LM358). L’amplificatore rende il segnale abbastanza grande da poter essere rilevabile da Arduino. Un circuito chiamato rivelatore di inviluppo converte le onde sonore in un valore di tensione continua che rappresenta l’intensità del suono istantaneo.

  • Il segnale in uscita varia da 0 V (silenzio) a 5 V (suono molto forte).
  • Arduino lo misura con il convertitore A/D a 10 bit, producendo numeri da 0 a 1023.
  • Il modulo è sensibile a frequenze fino a ~20 kHz (oltre il limite dell’udito umano).
  • L’amplificatore amplifica il segnale di circa 26 dB, così anche suoni deboli diventano misurabili.
  • Il consumo di corrente è basso, circa 4‑5 mA.

Nelle specifiche del dispositivo parlo di convertitore A/D a 10 bit e decibel (dB) e indico che l’amplificatore amplifica, in modo più semplice, ingrandisce di 26 dB, vediamo cosa vuol dire.

Qualche concetto tecnico spiegato in modo semplice

Cos’è un convertitore A/D a 10 bit

Un convertitore A/D (Analogico → Digitale) è come un traduttore: trasforma la tensione continua che esce dal sensore in numeri che il microcontrollore può elaborare.

10 bit significa che abbiamo 2¹⁰ = 1024 possibili valori, da 0 (0 V) a 1023 (5 V circa). Ogni “scalino” vale quindi circa 5 V / 1023 ≈ 0,005 V (5 millivolt). Più bit, più la scala è fine e la misura precisa.

Che cosa sono i decibel (dB) e perché l’amplificatore “ingrandisce” di 26 dB?

Il decibel (dB) è una grandezza adimensionale ed è un modo logaritmico di confrontare due grandezze: dice “quante volte più grande” è un segnale rispetto a un altro, ma usa il logaritmo per compattare numeri dimensionalmente diversi in una scala più gestibile. Inoltre il nostro orecchio non percepisce l’intensità del suono in modo lineare: se la potenza acustica raddoppia non ci sembra “due volte più forte”, ma solo un po’ più intensa. Questa risposta psicoacustica si descrive bene con una scala logaritmica, perciò usiamo i decibel.

Per le tensioni si usa la formula:

dB = 20 × log10(V2 / V1)

  • 0 dB ⇒ stessa tensione
  • +6 dB ⇒ tensione circa doppia
  • −6 dB ⇒ tensione circa metà

Dire che l’amplificatore aumenta il segnale di 26 dB significa che la tensione in uscita è circa 20× (volte) più grande di quella che entra (perché 20× ≈ 26 dB). Così anche un suono debole crea un segnale abbastanza grande da essere misurato da Arduino.

ATTENZIONE

Questo sensore è pensato per percepire la presenza di suoni e valutarne l’intensità, non per registrare l’audio né per misurazioni professionali in decibel. Per avere dati certificati servono microfoni calibrati e convertitori più veloci.

Esempio di base

/*
  Prof. Maffucci Michele
  24.06.25
  LED reagisce al suono
  Accende il LED sul pin 6 se il valore supera la soglia impostata.
*/

const int pinSuono   = A2;    // pin a cui è connesso il sensore
const int pinLED     = 6;     // LED del Sensor Kik
const int sogliaRumore = 200; // valore da calibrare in base all'ambiente

void setup() {
  pinMode(pinLED, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  int livello = analogRead(pinSuono);
  bool rumoreForte;
  // per approfondimenti sui tipi di dati:
  // https://www.maffucci.it/2020/11/15/arduino-tipi-di-dati-ripasso/

if (livello > sogliaRumore) {
    rumoreForte = true;
  } else {
    rumoreForte = false;
  }

if (rumoreForte) {
    digitalWrite(pinLED, HIGH);  // se supera la soglia il LED viene acceso
  } else {
    digitalWrite(pinLED, LOW);   // se non supera la soglia il led viene mantenuto apento
  }

Serial.print("Livello: ");
  Serial.print(livello);
  Serial.print("  Rumore forte? ");
  Serial.println(rumoreForte ? "SI" : "NO");

delay(500);
}

Continua a leggere

Corso di Processing – lezione 08

Cosa sono le variabili built-in?

Le variabili built-in sono variabili già definite da Processing che ci forniscono informazioni utili in tempo reale. Non dobbiamo dichiararle o assegnare loro un valore: possiamo semplicemente usarle nel nostro codice.

Alcune delle più importanti sono:

  • width e height: Dimensioni della finestra
  • mouseX e mouseY: Posizione del mouse
  • pmouseX e pmouseY: Posizione precedente del mouse
  • frameCount: Numero di frame dall’inizio del programma
  • key e keyCode: Tasti premuti sulla tastiera

Vediamo ora come utilizzare queste variabili in modo pratico.

1. width e height: conoscere le dimensioni della finestra

Le variabili width e height contengono la larghezza e l’altezza della finestra in pixel. Sono utili quando vogliamo posizionare oggetti in base alle dimensioni dello schermo.

Esempio: Disegnare un cerchio al centro della finestra

void setup() {
  size(500, 400); // Imposta la finestra a 500x400 pixel
}

void draw() {
  background(240);
  fill(0, 150, 255);
  ellipse(width / 2, height / 2, 100, 100); // Il cerchio sarà sempre al centro
}

In questo modo, il cerchio sarà sempre al centro, indipendentemente dalla grandezza della finestra.

Esercizio: Modifica il codice per disegnare due cerchi agli angoli opposti della finestra, usando width e height.
Continua a leggere