Come collegare un microcontroller Esp32 e Raspbery Pi.

Dialogo con Gemini.

Esp32 e RaspberyyPi: qual è il miglior modo di connettere un ESP32 serial al RPI?

Il miglior modo in assoluto per connettere un ESP32 in modalità seriale a un Raspberry Pi dipende dal contesto del tuo progetto, ma si divide principalmente in due strade: via cavo USB (la più semplice e sicura) o tramite pin GPIO / UART (la più compatta per sistemi integrati). [1, 2]

Di seguito viene analizzato come implementare entrambe le soluzioni e quale scegliere.


Opzione 1: Connessione tramite cavo USB (Consigliata)

Questo è il metodo più robusto ed efficiente per la maggior parte dei progetti. Consiste nel collegare la porta USB dell’ESP32 a una delle porte USB del Raspberry Pi tramite un comune cavo dati. [1, 2]

  • Perché è la migliore: Non richiede saldature, gestisce automaticamente la conversione dei livelli di tensione ed evita problemi di messa a terra. Inoltre, alimenta l’ESP32 direttamente dal Raspberry Pi. [1, 2]
  • Lato Raspberry Pi: La scheda verrà vista come un dispositivo seriale sotto /dev/ttyUSB0 o /dev/ttyACM0. Puoi usare script Python con la libreria pyserial per leggere e scrivere dati. [1, 2]
  • Lato ESP32: Utilizzi i normali comandi Serial.print() e Serial.read() nello sketch Arduino o in MicroPython. [1, 2]

Opzione 2: Connessione diretta UART tramite PIN GPIO (Per sistemi embedded)

Se hai bisogno di risparmiare spazio e non vuoi cavi USB volanti, puoi collegare direttamente i pin GPIO dedicati alla comunicazione UART delle due schede. [1]

Schema dei collegamenti obbligatorio:

Sia il Raspberry Pi che l’ESP32 lavorano a 3.3V, quindi i pin possono essere collegati direttamente senza convertitori di livello logico. Tuttavia, è fondamentale incrociare i pin di trasmissione (TX) e ricezione (RX): [1, 2, 3]

ESP32 Pin [1, 2]Raspberry Pi PinFunzioneNote
GNDGND (es. Pin 6)Terra in comuneObbligatorio per stabilire il riferimento elettrico.
TX (es. GPIO 1]RX (GPIO 15, Pin 10)Trasmissione datiL’ESP32 invia e il Raspberry riceve.
RX (es. GPIO 3]TX (GPIO 14, Pin 8)Ricezione datiIl Raspberry invia e l’ESP32 riceve.

Nota: Se usi la seriale principale dell’ESP32 (GPIO 1 e 3) per i pin, potresti creare conflitti durante il caricamento del codice via USB. In alternativa puoi mappare una seconda seriale hardware (UART2) dell’ESP32 sui pin GPIO 16 (RX2) e 17 (TX2). [1]

Configurazione software necessaria sul Raspberry Pi:

Per usare i pin GPIO 14 e 15 sul Raspberry Pi, devi prima liberare la seriale hardware solitamente occupata dalla console di sistema:

  1. Apri il terminale del Raspberry Pi e digita sudo raspi-config.
  2. Vai su Interface Options > Serial Port.
  3. Alla domanda “Would you like a login shell to be accessible over serial?”, seleziona No.
  4. Alla domanda “Would you like the serial port hardware to be enabled?”, seleziona Yes.
  5. Salva e riavvia il Raspberry Pi. La porta sarà accessibile da codice all’indirizzo /dev/serial0. [1]

Confronto diretto: Quale scegliere?

Criterio [1, 2]Cavo USB (Opzione 1)Pin GPIO UART (Opzione 2)
Difficoltà di configurazioneMolto bassa (Plug and Play)Media (Richiede modifiche software e cablaggi)
Ingombro hardwareElevato (Cavo USB esterno)Minimo (Fili jumper corti o PCB dedicato)
AlimentazioneInclusa nel cavo USBSeparata (L’ESP32 richiede alimentazione dedicata)
Rischio elettricoZeroBasso (Rischio di cortocircuito in caso di pin errati)

Alternativa Wireless (Se le schede sono distanti)

Se la connessione seriale fisica rappresenta un limite, ricorda che l’ESP32 e il Raspberry Pi dispongono entrambi di connettività Wi-Fi integrata. Se il tuo obiettivo è scambiare messaggi o dati di sensori, l’approccio moderno più efficiente consiste nell’installare un broker MQTT (come Mosquitto) sul Raspberry Pi e inviare i dati dall’ESP32 tramite protocollo MQTT via Wi-Fi. [1, 2, 3]

Se vuoi procedere con una delle due configurazioni seriali, fammi sapere:

  • Preferisci utilizzare il cavo USB o i pin GPIO?
  • Che linguaggio di programmazione userai sul Raspberry Pi (es. Python, Node.js)?
  • Hai bisogno di un esempio di codice per inviare e ricevere i messaggi tra le due schede?

You said: Come fare a bloccare l’assegnazione della porta da UDEV?

Per bloccare l’assegnazione della porta seriale (evitando che cambi nome ogni volta che scolleghi e ricolleghi l’ESP32) devi creare una regola UDEV personalizzata. Questo ti permette di assegnare un nome fisso e univoco (un “symlink”) alla tua scheda, come /dev/esp32.

Ecco la procedura passo dopo passo per bloccare la porta sul Raspberry Pi:

1. Trova i dati identificativi (ID) del tuo ESP32

Collega l’ESP32 al Raspberry Pi tramite il cavo USB e digita nel terminale:

bash

lsusb

Use code with caution.

Identifica la riga corrispondente al convertitore seriale dell’ESP32 (es. CP210x o CH340). Vedrai una riga simile a questa:

Bus 001 Device 004: ID 10c4:ea60 Silicon Labs CP210x UART Bridge

Segnati i due valori dopo ID:

  • Vendor ID (idVendor): 10c4 (le prime 4 cifre)
  • Product ID (idProduct): ea60 (le ultime 4 cifre)

2. Crea la regola UDEV

Crea un nuovo file di configurazione per UDEV digitando:

bash

sudo nano /etc/udev/rules.d/99-esp32.rules

Use code with caution.

Incolla all’interno del file la seguente riga, sostituendo i valori di idVendor e idProduct con quelli che hai trovato al punto 1:

text

SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", SYMLINK+="esp32", MODE="0666"

Use code with caution.

  • SYMLINK+="esp32": Crea un alias fisso chiamato /dev/esp32.
  • MODE="0666": Concede i permessi di lettura e scrittura a tutti gli utenti (evita problemi di permessi con Python).

Salva e esci premendo CTRL+O, Invio e poi CTRL+X.


3. Ricarica le regole di UDEV

Per rendere effettive le modifiche senza riavviare il Raspberry Pi, esegui questi due comandi:

bash

sudo udevadm control --reload-rules
sudo udevadm trigger

Use code with caution.


4. Verifica il funzionamento

Scollega e ricollega il cavo USB dell’ESP32. Ora verifica se il link statico è stato creato correttamente digitando:

bash

ls -l /dev/esp32

Il terminale ti mostrerà che /dev/esp32 punta direttamente alla porta dinamica corrente (es. -> ttyUSB0). Da questo momento in poi, nel tuo codice Python o Node.js, potrai aprire la porta seriale puntando sempre a /dev/esp32, dimenticandoti dei cambi di porta.


Se hai più schede ESP32 uguali (con stesso Vendor e Product ID) e vuoi distinguerle, fammi sapere:

  • Vuoi differenziarle usando il loro numero di serie hardware univoco?
  • Che sistema operativo specifico o versione di Raspberry Pi OS stai utilizzando?

You said: Il numero di serie con schede compatibili non sempre è univoco …

Hai perfettamente ragione: i cloni low-cost (che usano chip come il CH340 o varianti del CP2102) spesso condividono lo stesso identico numero di serie [2] o lasciano il campo seriale vuoto.

Se colleghi due di queste schede identiche, UDEV non riesce a distinguerle via software. L’unico modo certo per bloccare e differenziare le porte in questo scenario è usare l’identificazione geometrica, ovvero bloccare la porta in base alla porta USB fisica del Raspberry Pi a cui la scheda è collegata.

Ecco come mappare l’ESP32 in base alla sua posizione fisica:

1. Trova il percorso fisico della porta (KERNELS)

Scollega tutte le schede e collega il tuo ESP32 nella porta USB del Raspberry Pi che intendi dedicargli.

Esegui questo comando per identificare il percorso hardware (sostituisci ttyUSB0 con la porta effettiva se diversa):

bash

udevadm info --name=/dev/ttyUSB0 --attribute-walk | grep KERNELS | head -n 1

Use code with caution.

Il terminale restituirà una riga simile a questa:

KERNELS=="1:1.3" oppure KERNELS=="3-1:1.0"

Questo valore rappresenta l’esatta coordinata fisica della porta USB che stai usando.


2. Modifica la regola UDEV basandoti sulla porta fisica

Apri nuovamente il file delle regole:

bash

sudo nano /etc/udev/rules.d/99-esp32.rules

Cancella la vecchia regola e inseriscine una che utilizzi il parametro KERNELS al posto del seriale. In questo modo dici a UDEV: “Qualunque cosa venga collegata a QUESTA specifica porta USB, nominala esp32_porta1”.

SUBSYSTEM=="tty", KERNELS=="1:1.3", SYMLINK+="esp32_porta1", MODE="0666"

(Sostituisci 1:1.3 con il valore esatto emerso dal tuo comando al punto 1).

Se hai una seconda scheda identica, collegala a un’altra porta USB del Raspberry Pi, ripeti il punto 1 per scoprire il suo KERNELS (es. 1:1.4) e aggiungi una seconda riga nel file:

SUBSYSTEM=="tty", KERNELS=="1:1.4", SYMLINK+="esp32_porta2", MODE="0666"

Use code with caution.

Salva e chiudi (CTRL+O, Invio, CTRL+X).


3. Ricarica e applica

Applica le nuove regole digitando:

bash

sudo udevadm control --reload-rules && sudo udevadm trigger

Use code with caution.

L’unico vincolo di questo metodo

La porta è ora bloccata e stabile, ma è legata all’hardware: se scolleghi l’ESP32 e lo inserisci in una porta USB differente del Raspberry Pi, il link /dev/esp32_porta1 non verrà creato. Dovrai ricordarti di lasciare la scheda sempre nella stessa presa fisica.

Vuoi procedere configurando più schede contemporaneamente sulla stessa macchina, o riscontri problemi a recuperare il parametro KERNELS sul tuo modello di Raspberry Pi?

You said: Se invece uso un microcontroller MEGA che ha più UART, ma a 5V?

Se decidi di sostituire l’ESP32 con un Arduino Mega (o un clone basato su ATmega2560), la situazione cambia radicalmente a causa del disallineamento dei livelli logici di tensione. L’Arduino Mega lavora a 5V, mentre il Raspberry Pi tollera al massimo 3.3V sui suoi pin GPIO.

Se colleghi direttamente il pin TX del Mega (5V) al pin RX del Raspberry Pi (3.3V), rischi di bruciare permanentemente i pin del Raspberry Pi.

Ecco le soluzioni migliori per gestire i 5V e sfruttare le molteplici porte UART hardware del Mega (UART0, UART1, UART2, UART3):


Soluzione 1: Il cavo USB (Consigliata per la UART principale)

Se usi la porta USB principale dell’Arduino Mega (corrispondente a Serial), il chip di interfaccia USB-Seriale integrato sulla scheda gestisce già tutta la conversione di tensione.

  • Come funziona: Colleghi il Mega al Raspberry Pi con il classico cavo USB.
  • UDEV: Lato Raspberry Pi non cambia nulla. Puoi applicare esattamente la stessa regola geometrica basata su KERNELS vista nel passaggio precedente. Il Mega verrà visto generalmente come /dev/ttyACM0.

Soluzione 2: Convertitore di Livello Logico (Obbligatorio per UART1, UART2, UART3)

Se vuoi usare le altre tre porte seriali hardware dell’Arduino Mega (Serial1 sui pin 18/19, Serial2 sui pin 16/17, o Serial3 sui pin 14/15) per collegarti direttamente ai pin GPIO del Raspberry Pi, devi interporre un sistema di riduzione della tensione.

Opzione A: Partitore di tensione a resistenze (Solo sulla linea TX del Mega)

La linea critica è quella in cui il Mega “parla” e il Raspberry Pi “ascolta” (TX Mega \(\rightarrow \) RX Raspberry). Puoi ridurre i 5V a circa 3.3V usando due semplici resistenze come partitore.

TX (Mega, 5V) ---- [ Resistanza 1kΩ ] ----+---- RX (Raspberry Pi, 3.3V)

                                          |
                                  [ Resistanza 2kΩ ]
                                          |
GND (Mega) -------------------------------+---- GND (Raspberry Pi)

La linea inversa (TX Raspberry \(\rightarrow \) RX Mega) non ha bisogno di modifiche: i 3.3V inviati dal Raspberry Pi sono sufficienti per essere letti come livello logico “ALTO” dall’Arduino Mega a 5V.

Opzione B: Convertitore di Livello Logico Bidirezionale (I2C/UART)

È una piccola schedina economica (basata su transistor come il BSS138) che separa nettamente la linea ad alta tensione (HV, 5V) da quella a bassa tensione (LV, 3.3V).

text

[ Arduino Mega 5V ]                     [ Convertitore ]                    [ Raspberry Pi 3.3V ]
Pin 5V --------------------------------- HV          LV -------------------- Pin 3.3V
Pin GND -------------------------------- GND        GND ------------------- Pin GND
Pin 18 (TX1) --------------------------- HV1        LV1 ------------------- Pin 10 (RX, GPIO 15)
Pin 19 (RX1) --------------------------- HV2        LV2 ------------------- Pin 8  (TX, GPIO 14)

Come mappare i dati nel codice (Esempio UART1)

L’Arduino Mega ti permette di ricevere dati su una seriale (es. da un sensore) e rilanciarli al Raspberry Pi su un’altra. Ecco un esempio pratico in cui il Mega riceve comandi dal Raspberry Pi sulla porta Serial1 (pin 18/19) e risponde.

Lato Arduino Mega (Sketch):

cpp

void setup() {
  // Inizializza la seriale hardware 1 connessa al Raspberry Pi
  Serial1.begin(9600); 
}

void loop() {
  if (Serial1.available() > 0) {
    char data = Serial1.read();
    
    // Rispondi al Raspberry Pi
    Serial1.print("Mega ha ricevuto: ");
    Serial1.println(data);
  }
}

Lato Raspberry Pi (Python):

Configura la seriale interna del Raspberry Pi (dopo averla liberata tramite raspi-config come visto nella prima risposta):

python

import serial
import time

# /dev/serial0 punta alla UART hardware dei pin GPIO 14/15
ser = serial.Serial('/dev/serial0', 9600, timeout=1)
time.sleep(2) # Attesa reset Arduino

ser.write(b'A')
risposta = ser.readline().decode('utf-8').rstrip()
print(risposta) # Stamperà: "Mega ha ricevuto: A"

Hai già in mente quale delle 4 porte UART del Mega ti serve isolare, o hai bisogno dello schema per collegare più periferiche seriali contemporaneamente alle diverse porte dell’Arduino?