Tutoriel · Débutant · 1 h de lecture

Commander un robot en Bluetooth avec un module HC-05

Câblez un HC-05 à un Arduino, appairez-le à votre téléphone, et concevez un protocole de commandes série qui garde le robot réactif et sûr si la liaison tombe.

Introduction

Le HC-05 est le moyen le moins cher de rendre un robot sans fil. C’est un pont série Bluetooth : ce que votre téléphone envoie arrive sur le port série de l’Arduino comme des octets ordinaires, et ce que l’Arduino affiche repart vers le téléphone. Rien dans votre programme n’a besoin de savoir que Bluetooth existe.

Cette simplicité est l’attrait, et aussi le piège. Une liaison radio n’est pas un fil — elle tombe, elle retarde, et elle se déconnecte pendant que votre robot roule encore. L’essentiel de ce tutoriel porte sur cette différence.

Câblage, et l’erreur que presque tous commettent

Le module HC-05 fonctionne en logique 3,3 V, même si la carte d’interface accepte 5 V sur VCC. La broche RX ne tolère pas 5 V.

HC-05 Arduino Uno / Nano Notes
VCC 5V Le régulateur de la carte s’en charge
GND GND Masse commune avec tout le reste
TXD D10 (RX logiciel) Le 3,3 V sortant est lu comme HIGH par une entrée 5 V
RXD D11 (TX logiciel) via un diviseur Du 5 V direct l’endommagera avec le temps
EN / KEY D9 (optionnel) À HIGH à la mise sous tension pour le mode commandes AT

Abaissez la ligne d’émission 5 V de l’Arduino à 3,3 V avec un diviseur à deux résistances — 2 kΩ de la broche Arduino vers RXD du HC-05, et 3,3 kΩ de ce point vers la masse. Cela coûte deux composants et évite une panne vraiment enrageante à diagnostiquer, car un module ainsi endommagé continue souvent de à moitié marcher : il s’appaire, il émet, et il ignore ou corrompt silencieusement ce que vous lui envoyez.

Un schéma de câblage. Un Arduino Uno ou Nano relie sa ligne TXD directement à la broche D10 d'un module HC-05, légendé comme sûr car du 3,3 volts sortant est lu HIGH sur entrée 5 volts. Le retour de la broche D11 vers RXD du module passe par un diviseur 2 kilohms et 3,3 kilohms, avec un avertissement que du 5 volts direct en RXD endommage partiellement le module qui s'appaire encore mais corrompt ce qu'on lui envoie.
Trois des quatre fils sont triviaux. Le quatrième exige un diviseur, car du 5 V en RXD du module l'endommage lentement plutôt qu'évidemment. Télécharger le SVG

Utilisez SoftwareSerial, pas les broches 0 et 1. Le port série matériel est partagé avec l’USB, donc un module câblé dessus se bat avec le moniteur série et bloque les téléversements.

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

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

Appairage

Alimentez le robot, et la LED du module clignote vite — c’est « en attente d’appairage ». Sur votre téléphone, appairez HC-05 avec le code 1234 ou 0000.

Appairer n’est pas connecter. La liaison ne s’ouvre que quand une application du téléphone ouvre vraiment le port série. N’importe quel terminal série Bluetooth suffit pour commencer ; la LED du module ralentit en double clignotement une fois la connexion active.

Concevoir le protocole de commandes

Le premier protocole évident est un caractère par commande, et il marche une dizaine de minutes :

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

Deux choses tournent mal avec lui.

Il n’a pas de vitesse. Chaque commande est à plein gaz, le robot est donc immobile ou en charge. Envoyez plutôt une valeur avec la commande — une lettre et un nombre, terminés par un saut de ligne, trivial à analyser et à taper à la main en débogage :

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

Il suppose que le message arrive entier. bt.available() non nul signifie que quelques octets sont là, pas tous. Lire un caractère par boucle et agir aussitôt agit sur une demi-commande. Lire jusqu’au saut de ligne rend l’analyse fiable.

La panne qui compte : perdre la liaison

Un robot filaire s’arrête quand on lâche. Un robot sans fil continue la dernière chose ordonnée — si la dernière était « avant à fond » et que vous venez de sortir de portée, c’est un robot qui fonce sous le canapé à fond.

Un chronogramme. Une rangée d'impulsions de commandes arrive toutes les 100 millisecondes tant qu'un bouton est tenu, puis s'arrête à une ligne pointillée marquée signal perdu. En dessous, une barre sans temporisation reste rouge et roule hors de contrôle indéfiniment après la perte du signal. Une seconde barre avec temporisation homme-mort de 400 millisecondes passe à arrêté peu après la dernière commande.
Le flux de commandes s'arrête quand la liaison tombe, pas quand l'utilisateur lâche — d'où la temporisation autonome du robot. Télécharger le SVG

Tout robot sans fil exige une temporisation homme-mort. La règle est simple : si aucune commande n’est arrivée récemment, arrêtez.

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

Pour que cela aide, le contrôleur doit parler en continu. Faites envoyer au téléphone la commande courante répétée — toutes les 100 ms environ tant qu’un bouton est tenu — plutôt qu’une fois à l’appui et une fois au relâchement. Alors « bouton relâché » et « téléphone hors de portée » produisent la même issue sûre, et vous ne dépendez jamais d’un message de relâchement qui peut ne jamais arriver.

Utilisez millis() pour cela, jamais delay(). Un delay(200) dans la boucle fait 200 ms sans lire de commande, sans vérifier la temporisation, et le robot est sourd.

Mode commandes AT

Pour renommer le module ou changer son débit, maintenez EN/KEY à HIGH à la mise sous tension. La LED clignote lentement — environ toutes les deux secondes — signe du mode commandes plutôt que données.

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

Les commandes doivent être envoyées à 38 400 bauds en mode AT quel que soit le débit en mode données, et la plupart des micrologiciels exigent retour chariot et saut de ligne. Si AT ne rend rien, cet écart est presque toujours la cause.

Monter le débit de données vaut la peine pour télémétrer en retour, mais restez à 9 600 tant que le protocole se met au point — une liaison plus rapide rend surtout les bogues de cadrage plus difficiles à voir.

Vérifiez avant de rouler

Trois contrôles, dans cet ordre :

  1. Essai d’écho. Faites réafficher à l’Arduino ce qu’il reçoit. Si une ligne tapée revient intacte, câblage et débit sont bons.
  2. Essai d’analyse. Affichez la lettre et la valeur analysées. Confirmez que F180 donne F et 180, pas F et 1.
  3. Essai de temporisation. Envoyez une commande avant, puis fermez l’application ou éloignez-vous. Le robot doit s’arrêter dans votre temporisation. Sinon, corrigez avant de poser les roues au sol.

Une fois la liaison fiable, le même protocole de commandes s’intègre tel quel dans un robot avec autonomie : construisez la couche sans fil dans le projet de robot piloté au téléphone, ou passez à l’ESP32, qui sert une page de commande en Wi-Fi sans aucune application.

Explorer le graphe

Fait partie de ces réalisations

Les projets et parcours d'apprentissage qui incluent ce tutoriel.

Pour aller plus loin

Références