Robótica com C — Bloco 3: Projetos Práticos
Um painel de iluminação RGB controlado pelo celular via Bluetooth. Você digita um comando no app e as cores dos LEDs mudam instantaneamente — sem fio, sem botão físico, sem cabo USB. Este projeto introduce o módulo Bluetooth HC-05, que a partir daqui será o canal de comunicação de todos os projetos do Bloco 3 que envolvem o celular.
Por que começar com LEDs RGB? LEDs são inofensivos, dão feedback visual imediato e permitem verificar se o Bluetooth está funcionando sem precisar de relay ou motor. É o "Hello, World!" do controle remoto por celular — e o protocolo de comandos aprendido aqui é idêntico ao dos próximos projetos.
O HC-05 é um módulo de comunicação serial sem fio que opera na faixa de 2,4 GHz. Para o Arduino, ele é completamente transparente: recebe bytes do celular via rádio Bluetooth e os entrega ao Arduino pela UART, exatamente como se fossem bytes do cabo USB.
⚠️ Divisor de tensão obrigatório no RX do HC-05: o Arduino envia 5V no pino TX, mas o HC-05 suporta no máximo 3,3V no pino RX. Conectar diretamente pode danificar o módulo ao longo do tempo. O divisor é simples:
Arduino TX (pino 11) ──── R1 (1kΩ) ──┬──── HC-05 RX
│
R2 (2kΩ)
│
GND
Tensão no HC-05 RX = 5V × R2/(R1+R2) = 5V × 2/3 ≈ 3,3V ✓
| Aspecto | HC-05 | HC-06 |
|---|---|---|
| Modos | Mestre e escravo — pode iniciar conexão | Apenas escravo — aguarda conexão |
| Configuração AT | Sim — nome, senha, baud rate configuráveis | Limitada |
| Preço (BR) | R$ 20–35 | R$ 12–20 (mais barato) |
| Para este projeto | ✅ Funciona perfeitamente | ✅ Também funciona |
HC-05 ou HC-06? Para todos os projetos deste curso, onde o celular inicia a conexão com o Arduino, tanto o HC-05 quanto o HC-06 funcionam. O HC-06 é mais barato e mais simples de usar. O HC-05 é mais versátil. Use o que você tiver disponível — o código é idêntico.
Para enviar comandos do celular ao Arduino, use o app Serial Bluetooth Terminal (Android), disponível gratuitamente na Play Store. Ele permite:
Configuração dos botões de macro (recomendado):
| Botão | Macro (texto enviado) | Cor/Função |
|---|---|---|
| M1 | R | 🔴 Vermelho |
| M2 | G | 🟢 Verde |
| M3 | B | 🔵 Azul |
| M4 | W | ⚪ Branco (todos) |
| M5 | X | ⚫ Apagar tudo |
| M6 | ? | 📋 Ver comandos |
Para usuários iOS: o HC-05/HC-06 usa Bluetooth Classic (não BLE), que não é suportado nativamente pelo iOS desde o iPhone 4. Use um módulo HM-10 (Bluetooth LE) com o app LightBlue ou BLE Terminal HM-10 para iOS. O código do Arduino é praticamente o mesmo — só muda o nome do objeto Serial.
| Componente | Conexão | Observação |
|---|---|---|
| HC-05 VCC | → 5V | O módulo aceita 5V na alimentação |
| HC-05 GND | → GND | — |
| HC-05 TX | → pino 10 (RX software) | Conexão direta — HC-05 envia 3,3V, Arduino aceita |
| HC-05 RX | → divisor R1/R2 → pino 11 (TX software) | Divisor obrigatório: R1=1kΩ, R2=2kΩ |
| LED vermelho + 220Ω | pino 9 → R → LED → GND | Pino PWM para controle de brilho futuro |
| LED verde + 220Ω | pino 6 → R → LED → GND | Pino PWM |
| LED azul + 220Ω | pino 5 → R → LED → GND | Pino PWM |
Por que pinos PWM para LEDs? Esta aula usa digitalWrite() (liga/desliga). Na extensão da Seção 6, você vai usar analogWrite() para controlar o brilho de cada canal com valores 0–255. Reservar pinos PWM agora evita remontagem depois.
O Wokwi não tem o HC-05 como componente nativo. Não é possível simular o rádio Bluetooth nem parear o celular com o simulador. Porém, como a Aula 46 demonstrou, a lógica de processarComando() é completamente independente do canal — o que permite uma estratégia de simulação muito prática.
Estratégia: Serial Monitor como substituto do celular. No Wokwi, você digita os comandos (R, G, B, W, X) diretamente no Monitor Serial — exatamente como faria pelo app no celular. A lógica de processamento é 100% idêntica. Só o rádio não é simulado, e rádio não tem como testar em software de qualquer forma.
Para simular no Wokwi, use esta versão adaptada do código — troca SoftwareSerial bluetooth por Serial:
// ── Versão WOKWI (simulação) ───────────────────────
// Remove SoftwareSerial — usa Serial direto
// Envie comandos pelo Monitor Serial: R G B W X ?
// Comportamento idêntico ao projeto com HC-05 real
const int PINO_R = 9;
const int PINO_G = 6;
const int PINO_B = 5;
bool estadoR = false, estadoG = false, estadoB = false;
void atualizarLEDs() {
digitalWrite(PINO_R, estadoR ? HIGH : LOW);
digitalWrite(PINO_G, estadoG ? HIGH : LOW);
digitalWrite(PINO_B, estadoB ? HIGH : LOW);
}
void enviarStatus() {
Serial.print("RGB: ");
Serial.print(estadoR ? "R" : "-");
Serial.print(estadoG ? "G" : "-");
Serial.println(estadoB ? "B" : "-");
}
void processarComando(char cmd) {
switch (cmd) {
case 'R': estadoR = true; break;
case 'r': estadoR = false; break;
case 'G': estadoG = true; break;
case 'g': estadoG = false; break;
case 'B': estadoB = true; break;
case 'b': estadoB = false; break;
case 'W': estadoR = estadoG = estadoB = true; break;
case 'X': estadoR = estadoG = estadoB = false; break;
case '?': Serial.println("Cmds: R/r G/g B/b W X"); return;
case '\n': case '\r': return;
default: Serial.print("Desconhecido: "); Serial.println(cmd); return;
}
atualizarLEDs();
enviarStatus();
}
void setup() {
pinMode(PINO_R, OUTPUT);
pinMode(PINO_G, OUTPUT);
pinMode(PINO_B, OUTPUT);
atualizarLEDs();
Serial.begin(9600);
Serial.println("=== RGB Wokwi — envie: R G B W X ?");
}
void loop() {
if (Serial.available() > 0) {
processarComando(Serial.read());
}
}
| Aspecto | Versão Wokwi (simulação) | Versão física (HC-05) |
|---|---|---|
| Canal de comunicação | Monitor Serial (teclado) | Bluetooth HC-05 (celular) |
| Objeto usado | Serial |
bluetooth (SoftwareSerial) |
Função processarComando() |
Idêntica — nenhuma mudança | Idêntica — nenhuma mudança |
| Comportamento dos LEDs | Idêntico | Idêntico |
| O que NÃO é simulado | O rádio Bluetooth e o pareamento | — |
Fluxo de trabalho recomendado para todos os projetos Bluetooth do Bloco 3:
Serial por bluetooth — o código já está validado, só o canal mudaEssa separação economiza muito tempo: problemas de lógica são encontrados e resolvidos no simulador, sem precisar desmontar o circuito físico. Problemas de hardware (divisor de tensão, baud rate, pareamento) são isolados para a etapa 2.
/* * ===================================================== * Projeto 02 — LEDs RGB via Bluetooth HC-05 * ===================================================== * Comandos (maiúsculo = liga, minúsculo = desliga): * R/r = vermelho | G/g = verde | B/b = azul * W = todos ligados (branco) * X = todos apagados * ? = lista de comandos * ===================================================== */ #include <SoftwareSerial.h> // ── Bluetooth ────────────────────────────────────── // SoftwareSerial(RX, TX) — pinos do ARDUINO // HC-05 TX → pino 10 | HC-05 RX → pino 11 (via divisor) SoftwareSerial bluetooth(10, 11); // ── Pinos dos LEDs (todos PWM) ───────────────────── const int PINO_R = 9; const int PINO_G = 6; const int PINO_B = 5; // ── Estado atual de cada canal ───────────────────── bool estadoR = false; bool estadoG = false; bool estadoB = false; // ════════════════════════════════════════════════════ // Aplica o estado atual nos pinos físicos // ════════════════════════════════════════════════════ void atualizarLEDs() { digitalWrite(PINO_R, estadoR ? HIGH : LOW); digitalWrite(PINO_G, estadoG ? HIGH : LOW); digitalWrite(PINO_B, estadoB ? HIGH : LOW); } // ════════════════════════════════════════════════════ // Envia o estado atual de volta ao celular // ════════════════════════════════════════════════════ void enviarStatus() { bluetooth.print("RGB: "); bluetooth.print(estadoR ? "R" : "-"); bluetooth.print(estadoG ? "G" : "-"); bluetooth.println(estadoB ? "B" : "-"); } // ════════════════════════════════════════════════════ // Processa um comando recebido pelo Bluetooth // ════════════════════════════════════════════════════ void processarComando(char cmd) { switch (cmd) { case 'R': estadoR = true; break; case 'r': estadoR = false; break; case 'G': estadoG = true; break; case 'g': estadoG = false; break; case 'B': estadoB = true; break; case 'b': estadoB = false; break; case 'W': // branco — todos ligados estadoR = estadoG = estadoB = true; break; case 'X': // apagar tudo estadoR = estadoG = estadoB = false; break; case '?': bluetooth.println("Cmds: R/r G/g B/b W=branco X=apagar"); return; // não atualiza LEDs nem envia status case '\n': case '\r': return; default: bluetooth.print("Desconhecido: "); bluetooth.println(cmd); return; } atualizarLEDs(); enviarStatus(); // Espelha no Serial USB para debug Serial.print("[BT cmd='"); Serial.print(cmd); Serial.print("'] RGB: "); Serial.print(estadoR ? "R" : "-"); Serial.print(estadoG ? "G" : "-"); Serial.println(estadoB ? "B" : "-"); } // ════════════════════════════════════════════════════ // SETUP e LOOP // ════════════════════════════════════════════════════ void setup() { pinMode(PINO_R, OUTPUT); pinMode(PINO_G, OUTPUT); pinMode(PINO_B, OUTPUT); atualizarLEDs(); // garante que todos começam apagados Serial.begin(9600); bluetooth.begin(9600); Serial.println("=== RGB Bluetooth ==="); Serial.println("Aguardando conexao do celular..."); // Sinaliza que está pronto: pisca todos uma vez estadoR = estadoG = estadoB = true; atualizarLEDs(); delay(300); estadoR = estadoG = estadoB = false; atualizarLEDs(); } void loop() { if (bluetooth.available() > 0) { char cmd = bluetooth.read(); processarComando(cmd); } // Espelha tráfego do Serial USB para o Bluetooth (debug) if (Serial.available() > 0) { bluetooth.write(Serial.read()); } }
=== RGB Bluetooth ===
Aguardando conexao do celular...
[celular envia "R"] [BT cmd='R'] RGB: R--
[celular envia "G"] [BT cmd='G'] RGB: RG-
[celular envia "b"] [BT cmd='b'] RGB: RG-
[celular envia "W"] [BT cmd='W'] RGB: RGB
[celular envia "X"] [BT cmd='X'] RGB: ---
Espelhar Serial ↔ Bluetooth no loop(): as duas linhas if (bluetooth.available()) e if (Serial.available()) criam uma "ponte" bidirecional. Enquanto testa, você pode enviar comandos tanto pelo celular quanto pelo Monitor Serial do computador. Remova essa ponte quando o projeto for para produção.
Agora que os pinos são PWM, expanda o protocolo para aceitar valores de brilho. Formato: prefixo + valor (padrão da Aula 46), ex: "R128" → vermelho em 50% de brilho:
// Substitui os bool por int (0–255) e usa analogWrite int brilhoR = 0, brilhoG = 0, brilhoB = 0; void atualizarLEDs() { analogWrite(PINO_R, brilhoR); analogWrite(PINO_G, brilhoG); analogWrite(PINO_B, brilhoB); } // No processarComando(), substitua o switch por: void processarMensagem(String msg) { if (msg.length() < 1) return; char canal = msg[0]; int valor = constrain(msg.substring(1).toInt(), 0, 255); switch (canal) { case 'R': brilhoR = valor; break; case 'G': brilhoG = valor; break; case 'B': brilhoB = valor; break; case 'W': brilhoR = brilhoG = brilhoB = valor ? valor : 255; break; case 'X': brilhoR = brilhoG = brilhoB = 0; break; default: bluetooth.println("Formato: R0-255 G0-255 B0-255 W X"); return; } atualizarLEDs(); bluetooth.print("RGB: "); bluetooth.print(brilhoR); bluetooth.print(" "); bluetooth.print(brilhoG); bluetooth.print(" "); bluetooth.println(brilhoB); } // No loop(), substitua bluetooth.read() por readStringUntil: void loop() { if (bluetooth.available()) { String msg = bluetooth.readStringUntil('\n'); msg.trim(); if (msg.length() > 0) processarMensagem(msg); } }
[celular envia "R255"] RGB: 255 0 0
[celular envia "G128"] RGB: 255 128 0
[celular envia "B64"] RGB: 255 128 64
[celular envia "W"] RGB: 255 255 255
[celular envia "X"] RGB: 0 0 0
| Problema | Causa provável | Solução |
|---|---|---|
| HC-05 não aparece no Bluetooth do celular | Módulo não está em modo de descoberta ou não está ligado | Verifique VCC e GND — o LED deve estar piscando rápido |
| Pareia mas não recebe dados | TX/RX invertidos ou divisor de tensão incorreto | Confira: HC-05 TX → Arduino pino 10 (RX); HC-05 RX → divisor → Arduino pino 11 (TX) |
| Dados corrompidos / caracteres errados | Baud rate diferente entre HC-05 e bluetooth.begin() |
O baud padrão do HC-05 é 9600. Tente também 38400 se 9600 não funcionar |
| Arduino reinicia ao conectar o Bluetooth | SoftwareSerial interferindo com Serial durante o boot | Desconecte TX/RX do HC-05 ao carregar o sketch, reconecte após |
| LED do HC-05 não para de piscar rápido | Nenhum celular conectado | Normal — vai parar ao conectar pelo app |
| Conceito | Aula 46 (Serial USB) | Este projeto (Bluetooth) |
|---|---|---|
| Objeto de comunicação | Serial |
bluetooth (SoftwareSerial) |
| Verificar dados disponíveis | Serial.available() |
bluetooth.available() |
| Ler um byte | Serial.read() |
bluetooth.read() |
| Enviar texto | Serial.print() |
bluetooth.print() |
| Lógica de processamento | processarComando(cmd) |
processarComando(cmd) — idêntica |
| Inicialização | Serial.begin(9600) |
bluetooth.begin(9600) |
| Limitação de hardware | Comprimento do cabo USB | ~10 metros de alcance |
Confirmação do que a Aula 46 prometeu: a lógica de processarComando() é copiada literalmente da Aula 46. A única mudança é o nome do objeto — Serial vira bluetooth. O padrão available() → read() → switch(cmd) é 100% reutilizável.
Teste sua compreensão do módulo Bluetooth e do projeto RGB: