Tutorial · Principiante · 1 ora

Controlla un robot via Bluetooth con un modulo HC-05

Collega un HC-05 a un Arduino, associalo al telefono e progetta un protocollo seriale che mantenga il robot reattivo e sicuro quando cade il collegamento.

Introduzione

L’HC-05 è il modo più economico per rendere wireless un robot. È un ponte seriale Bluetooth: ciò che il telefono invia arriva sulla porta seriale dell’Arduino come byte ordinari e ciò che l’Arduino stampa torna al telefono. Nello sketch non devi fare in modo che Bluetooth esista.

Questa semplicità è il fascino, ma è anche la trappola. Un collegamento radio non è un cavo—può cadere, accumulare latenza e disconnettersi mentre il robot sta ancora avanzando. La maggior parte di questo tutorial riguarda proprio questa differenza.

Cablaggio e l’errore che quasi tutti fanno

Il modulo HC-05 funziona con una logica a 3.3 V, anche se la scheda breakout accetta 5 V su VCC. Il pin RX non tollera i 5 V.

HC-05 Arduino Uno / Nano Note
VCC 5V Il regolatore della scheda gestisce questo
GND GND Terra comune a tutto il resto
TXD D10 (soft RX) L’uscita a 3.3 V viene letta correttamente come HIGH da un ingresso a 5 V
RXD D11 (soft TX) attraverso un divisore 5 V diretti lo danneggiano nel tempo
EN / KEY D9 (facoltativo) Porta HIGH all’accensione per entrare in modalità comando AT

Riduci la linea di trasmissione a 5 V dell’Arduino a 3.3 V con un divisore a due resistenze—2 kΩ dal pin dell’Arduino a RXD dell’HC-05 e 3.3 kΩ da quel punto a terra. Costa due componenti ed evita un guasto che è davvero frustrante da diagnosticare, perché un modulo danneggiato in questo modo spesso continua a funzionare a metà: si associa, trasmette e ignora o corrompe silenziosamente ciò che gli invii.

Uno schema di cablaggio. Un Arduino Uno o Nano collega direttamente la propria linea TXD al pin D10 di un modulo HC-05, indicato come sicuro perché 3.3 volt in uscita vengono letti HIGH da un ingresso a 5 volt. Il percorso di ritorno dal pin D11 al pin RXD del modulo passa attraverso un divisore di tensione da 2 kiloohm e 3.3 kiloohm, con un avvertimento che 5 volt diretti in RXD danneggiano parzialmente il modulo, così si associa ancora ma corrompe ciò che invii.
Tre dei quattro fili sono banali. Il quarto richiede un divisore, perché 5 V nell'RXD del modulo lo danneggiano lentamente anziché in modo ovvio. Scarica SVG

Usa SoftwareSerial, non i pin 0 e 1. La porta seriale hardware è condivisa con USB, quindi un modulo collegato lì combatte con il monitor seriale e blocca i caricamenti.

#include <SoftwareSerial.h>
SoftwareSerial bt(10, 11);   // RX, TX

void setup() {
  Serial.begin(115200);      // USB, for debugging
  bt.begin(9600);            // HC-05 default baud
}

Associazione

Alimenta il robot e il LED del modulo lampeggia rapidamente: significa «in attesa di associazione». Sul telefono, associa HC-05 usando il codice 1234 oppure 0000.

L’associazione non è la connessione. Il collegamento si apre solo quando un’app sul telefono apre realmente la porta seriale. Per iniziare basta qualsiasi terminale seriale Bluetooth; quando la connessione è attiva, il LED del modulo passa a lampeggiare due volte di seguito.

Progettare il protocollo dei comandi

Il primo protocollo ovvio è un carattere per comando e funziona per circa dieci minuti:

if (bt.available()) {
  char c = bt.read();
  if (c == 'F') forward();
  else if (c == 'B') back();
  else if (c == 'S') stop();
}

Due cose vanno storte.

Non ha una velocità. Ogni comando è a piena potenza, quindi il robot è fermo oppure accelera. Invia invece un valore insieme al comando—una lettera e un numero, terminati da una nuova riga, facilissimi da analizzare e da digitare a mano durante il debug:

// "F180\n" — forward at 180 of 255
char buffer[16];
if (bt.available()) {
  int n = bt.readBytesUntil('\n', buffer, sizeof(buffer) - 1);
  buffer[n] = '\0';
  char cmd = buffer[0];
  int value = atoi(buffer + 1);
  ...
}

Assume che il messaggio arrivi intero. Quando bt.available() diventa diverso da zero significa che alcuni byte sono arrivati, non tutti. Leggere un carattere per ciclo ed eseguire subito l’azione significa agire su metà comando. Leggere fino alla nuova riga è ciò che rende affidabile l’analisi.

Il guasto che conta: perdere il collegamento

Un robot cablato si ferma quando rilasci il comando. Un robot wireless continua a fare l’ultima cosa che gli hai detto—che, se l’ultima cosa era «avanti a piena velocità» e appena sei uscito dalla portata, è un robot che finisce sotto il divano a tutta velocità.

Un diagramma temporale. Una fila di impulsi di comando arriva ogni 100 millisecondi mentre un pulsante è premuto, poi si ferma su una linea tratteggiata contrassegnata come segnale perso. Sotto, una barra che mostra l'assenza di timeout resta rossa e prosegue a controllare fuori controllo indefinitamente dopo la perdita del segnale. Una seconda barra con un deadman timeout di 400 millisecondi passa allo stato fermo poco dopo l'ultimo comando.
Il flusso di comandi si ferma quando cade il collegamento, non quando l'utente lascia andare—ed è per questo che il robot deve scadere da solo. Scarica SVG

Ogni robot wireless ha bisogno di un deadman timeout. La regola è semplice: se non è arrivato alcun comando di recente, fermati.

unsigned long lastCommandAt = 0;
const unsigned long TIMEOUT_MS = 500;

void loop() {
  if (readCommand()) lastCommandAt = millis();

  // Nothing heard recently? Assume the link is gone.
  if (millis() - lastCommandAt > TIMEOUT_MS) stop();
}

Perché sia utile, il controllore deve continuare a parlare. Fai inviare dal telefono il comando corrente ripetutamente—ogni 100 ms circa mentre un pulsante è premuto—anziché una volta alla pressione e una al rilascio. Così «pulsante rilasciato» e «telefono fuori portata» producono lo stesso risultato sicuro e non dipendi mai da un messaggio di rilascio che potrebbe non arrivare mai.

Usa millis() per questo, mai delay(). Un delay(200) nel ciclo blocca per 200 ms senza leggere comandi, senza controllare il timeout e con il robot sordo.

Modalità comando AT

Per rinominare il modulo o cambiare la velocità in baud, tieni EN/KEY a HIGH durante l’accensione. Il LED lampeggia lentamente—circa una volta ogni due secondi—e questo ti dice che sei in modalità comando anziché in modalità dati.

AT              → OK
AT+NAME=MyRobot → OK
AT+PSWD="4821"  → OK
AT+UART=38400,0,0

I comandi devono essere inviati a 38400 baud in modalità AT, indipendentemente dalla velocità in baud della modalità dati, e la maggior parte del firmware richiede sia il ritorno a capo sia la nuova riga. Se AT non restituisce nulla, quasi sempre è per questo.

Aumentare la velocità in baud dei dati vale la pena se stai trasmettendo telemetria, ma lasciala a 9600 mentre sistemi il protocollo—un collegamento più veloce rende soprattutto più difficili da vedere i bug di delimitazione.

Verifica prima di guidare

Tre controlli, in quest’ordine:

  1. Test di eco. Fai stampare dall’Arduino tutto ciò che riceve. Se una riga digitata torna intatta, il cablaggio e la velocità in baud sono corretti.
  2. Test di analisi. Stampa la lettera e il valore del comando analizzato. Verifica che F180 produca F e 180, non F e 1.
  3. Test del timeout. Invia un comando avanti, poi chiudi l’app o allontanati. Il robot deve fermarsi entro il timeout. Se non lo fa, correggi il problema prima di mettere le ruote sul pavimento.

Una volta affidabile il collegamento, lo stesso protocollo dei comandi entra direttamente in un robot con autonomia: costruisci lo strato wireless nel progetto del robot controllato dal telefono oppure passa all’ESP32, che serve una pagina di controllo via Wi-Fi e non richiede alcuna app.

Esplora il grafo

Fa parte di queste costruzioni

Progetti e percorsi di apprendimento che includono questo tutorial.

Per approfondire

Fonti