Tutorial · Beginner · 1 uur

Bestuur een robot via Bluetooth met een HC-05-module

HC-05 op een Arduino bedraden, aan je telefoon koppelen en een serieel protocol ontwerpen dat de robot responsief en veilig houdt bij verbindingsverlies.

Inleiding

De HC-05 is de goedkoopste manier om een robot draadloos te maken. Het is een Bluetooth-seriële brug: wat je telefoon stuurt komt op de seriële poort van de Arduino aan als gewone bytes, en wat de Arduino afdrukt gaat terug naar de telefoon. Niets in je sketch hoeft te weten dat Bluetooth bestaat.

Die eenvoud is de aantrekkingskracht, en tegelijk de valkuil. Een radiolink is geen draad — hij valt weg, hij heeft vertraging, en hij verbreekt terwijl je robot nog aan het rijden is. Het meeste van deze tutorial gaat over dat verschil.

Bedrading, en de fout die bijna iedereen maakt

De HC-05-module voert zijn logica op 3,3 V, ook al accepteert het breakout-bord 5 V op VCC. De RX-pin is niet 5 V-tolerant.

HC-05 Arduino Uno / Nano Opmerkingen
VCC 5V de regelaar van het bord regelt dit af
GND GND gemeenschappelijke aarde met al het andere
TXD D10 (soft RX) 3,3 V uit wordt door een 5 V-ingang prima als logisch HOOG gelezen
RXD D11 (soft TX) via een deler 5 V er recht in beschadigt hem op den duur
EN / KEY D9 (optioneel) trek HOOG bij het inschakelen voor AT-commandomodus

Breng de 5 V-zendlijn van de Arduino omlaag naar 3,3 V met een deler van twee weerstanden — 2 kΩ van de Arduinopin naar de RXD van de HC-05, en 3,3 kΩ van dat knooppunt naar aarde. Het kost twee componenten en voorkomt een fout die werkelijk frustrerend is om te diagnosticeren, want een module die zo beschadigd raakt blijft vaak half werken: hij koppelt, hij zendt, en hij negeert of vervormt stilzwijgend wat je hem stuurt.

Een bedradingsschema. Een Arduino Uno of Nano verbindt zijn TXD-lijn rechtstreeks met pin D10 van een HC-05-module, gemarkeerd als veilig omdat 3,3 volt uit HOOG wordt gelezen op een 5-voltsingang. Het retourpad van pin D11 naar de RXD-pin van de module loopt via een spanningsdeler van 2 kilohm en 3,3 kilohm, met de waarschuwing dat 5 volt rechtstreeks in RXD de module gedeeltelijk beschadigt zodat hij nog wel koppelt maar vervormt wat je hem stuurt.
Drie van de vier draden zijn simpel. De vierde heeft een deler nodig, omdat 5 V in de RXD van de module hem langzaam beschadigt in plaats van duidelijk. SVG downloaden

Gebruik SoftwareSerial, niet pinnen 0 en 1. De hardware-seriële poort wordt gedeeld met USB, dus een module die daar is bedraad vecht met de seriële monitor en blokkeert uploads.

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

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

Koppelen

Voed de robot van stroom en de LED van de module knippert snel — dat betekent “wacht op koppeling”. Koppel op je telefoon met HC-05 met de code 1234 of 0000.

Koppelen is geen verbinding maken. De link gaat pas open als een app op de telefoon de seriële poort daadwerkelijk opent. Elke Bluetooth-serieterminal voldoet om mee te beginnen; de LED van de module vertraagt tot een dubbele knipper zodra er een verbinding is.

Het commandoprotocol ontwerpen

Het voor de hand liggende eerste protocol is één teken per commando, en het werkt ongeveer tien minuten:

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

Twee dingen gaan er mis.

Het heeft geen snelheid. Elk commando is vol gas, dus de robot staat stil of rijdt vol gas. Stuur in plaats daarvan een waarde mee met het commando — één letter en een getal, afgesloten met een newline, wat triviaal te parseren is en triviaal om tijdens het debuggen met de hand te typen:

// "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);
  ...
}

Het neemt aan dat het bericht compleet aankomt. Dat bt.available() niet-nul wordt betekent dat er sommige bytes zijn, niet allemaal. Eén teken per lus lezen en er meteen op reageren betekent reageren op de helft van een commando. Lezen tot aan de newline is wat de parsing betrouwbaar maakt.

De fout die ertoe doet: de verbinding kwijtraken

Een bedraade robot stopt als je loslaat. Een draadloze robot blijft doen wat je hem als laatste hebt gezegd — en als dat “vooruit op volle snelheid” was en je net buiten bereik bent gelopen, is dat een robot die op volle vaart onder de sofa schiet.

Een tijddiagram. Een rij commandopulsen komt elke 100 milliseconden binnen zolang een knop ingedrukt wordt, en stopt dan bij een stippellijn die
De commandostroom stopt wanneer de verbinding wegvalt, niet wanneer de gebruiker loslaat — en daarom moet de robot zelf op een timeout reageren. SVG downloaden

Elke draadloze robot heeft een dodemansschakeling nodig. De regel is eenvoudig: als er recent geen commando is binnengekomen, stop dan.

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();
}

Om dat te helpen moet de regelaar aan de praat blijven. Laat de telefoon het huidige commando herhaaldelijk sturen — elke 100 ms of zo zolang een knop ingedrukt is — in plaats van eenmaal bij indrukken en eenmaal bij loslaten. Dan leveren “knop losgelaten” en “telefoon buiten bereik” dezelfde veilige uitkomst op, en je leunt nooit op een loslaatbericht dat misschien nooit aankomt.

Gebruik hiervoor millis(), nooit delay(). Een delay(200) in de lus is 200 ms waarin geen commando wordt gelezen, de timeout niet wordt gecontroleerd en de robot doof is.

AT-commandomodus

Om de module een andere naam te geven of de baudrate te wijzigen, houd je EN/KEY HOOG tijdens het inschakelen. De LED knippert langzaam — ongeveer eens per twee seconden — en zo weet je dat je in commandomodus staat en niet in datamodus.

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

Commando’s moeten in AT-modus op 38400 baud worden verstuurd, ongeacht de baudrate in datamodus, en de meeste firmware vereist zowel carriage return als newline. Geeft AT niets terug, dan is dat vrijwel altijd de reden.

De databaudrate verhogen loont als je telemetrie terugstuurt, maar laat hem op 9600 staan tot je het protocol goed hebt — een snellere link maakt framingfouten vooral lastiger om te zien.

Verifieer voordat je rijdt

Drie controles, in deze volgorde:

  1. Echotest. Laat de Arduino afdrukken wat hij ontvangt. Komt een getypte regel intact terug, dan zijn de bedrading en de baudrate goed.
  2. Parsetest. Druk de geparseerde commandoletter en -waarde af. Bevestig dat F180 F en 180 oplevert, niet F en 1.
  3. Timeouttest. Stuur een commando vooruit en sluit daarna de app of loop weg. De robot moet binnen je timeout stoppen. Doet hij dat niet, repareer dat dan voordat je wielen de vloer raken.

Zodra de verbinding betrouwbaar is, past hetzelfde commandoprotocol direct in een robot met autonomie: bouw de draadloze laag in het project robot op afstandsbediening, of stap over op de ESP32, die een besturingspagina over wifi serveert en helemaal geen app nodig heeft.

Verken de graaf

Onderdeel van deze bouwprojecten

Projecten en leerroutes waarin deze tutorial voorkomt.

Verder lezen

Bronnen