IoT

Carro de Controle Remoto com ESP-NOW

Eletrogate 26 de dezembro de 2023

Introdução

No post de hoje, nós iremos fazer um carrinho de controle remoto controlado por quatro push buttons!

O projeto consiste em duas partes: o Emissor e o Receptor. Para o emissor, nós iremos utilizar apenas um ESP8266 e quatro push buttons. Para o receptor, nós vamos usar um ESP32, que será conectado a um Arduino UNO para o controle dos motores.

Para fazer a transmissão dos dados sem fio entre os ESPs, nós iremos utilizar o protocolo ESP-NOW, desenvolvido pela Espressif.

No envio dos dados, o ESP8266 se conecta ao ESP32 por meio do endereço MAC do esp32, e envia os dados (Frente, Traz, Esquerda, Direita). Esses dados, quando recebidos pelo ESP32, serão transmitidos para o Arduino UNO por meio do protocolo de Master/Slave via I₂C.


Códigos

O código que deve ser carregado no ESP8266 é o seguinte:

//inclui as bibliotecas
#include <espnow.h>
#include <ESP8266WiFi.h>
//define em quais portas os botões serão conectados
#define botaoesq D5
#define botaobaixo D6
#define botaocima D7
#define botaodir D2

bool esq = 0;
bool dir = 0;
bool cima = 0;
bool baixo = 0;

// é necessario mudar o endereço de acordo com o endereço do seu ESP32
uint8_t receiverMacAddress[] = {0xC0,0x49,0xEF,0xE4,0xD8,0xA8};  //C0:49:EF:E4:D8:A8

struct PacketData
{
  byte esq;
  byte dir;
  byte cima;
  byte baixo;
};
PacketData data;

// callback quando os dados são enviados
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus)
{
  Serial.print("Status dos dados enviados: ");
  if (sendStatus == 0) {
    Serial.println("Envio ok!");
  }
  else {
    Serial.println("Falha no envio!");
  }
}

void setup() 
{
  
  Serial.begin(115200);
  pinMode(botaoesq, INPUT_PULLUP);
  pinMode(botaodir, INPUT_PULLUP);
  pinMode(botaocima, INPUT_PULLUP);
  pinMode(botaobaixo, INPUT_PULLUP);
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != 0) {
    Serial.println("Erro ao inicializar o ESP-NOW");
    return;
  }
  
  
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_register_send_cb(OnDataSent);
  
  
  esp_now_add_peer(receiverMacAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);

}
 
void loop() 
{
  if (digitalRead(botaoesq) == LOW) // Se o botão for pressionado
  {
    esq = 1;  //define a variável para verdadeira
  }
  else{         //caso contrário
    esq = 0;   //define a variável para falsa
  }
  if (digitalRead(botaodir) == LOW) // Se o botão for pressionado
  {
    dir = 1;  //define a variável para verdadeira
  }
  else{         //caso contrário
    dir = 0;    //define a variável para falsa
  }
  if (digitalRead(botaocima) == LOW) // Se o botão for pressionado
  {
    cima = 1;  //define a variável para verdadeira
  }
  else{         //caso contrário
    cima = 0;   //define a variável para falsa
  }
  if (digitalRead(botaobaixo) == LOW) // Se o botão for pressionado
  {
    baixo = 1; //define a variável para verdadeira
  }
  else{        //caso contrário
    baixo = 0; //define a variável para falsa
  }

  data.esq = esq;
  data.dir = dir;
  data.cima = cima;
  data.baixo = baixo;
  
  Serial.print("esq: ");
  Serial.println(esq);
  Serial.print("dir: ");
  Serial.println(dir);
  Serial.print("cima: ");
  Serial.println(cima);
  Serial.print("baixo: ");
  Serial.println(baixo);

  uint8_t result = esp_now_send(receiverMacAddress, (uint8_t *) &data, sizeof(data));
  
    delay(50);
  
}

O código que deve ser carregado no ESP32 é o seguinte:

//inclui as bibliotecas
#include <esp_now.h>
#include <WiFi.h>
#include <Wire.h>

const int slaveAdress = 0x08; // endereço da placa UNO na relação master/slave

#define SIGNAL_TIMEOUT 10000  
unsigned long lastRecvTime = 0;

struct PacketData
{
  byte esq;
  byte dir;
  byte cima;
  byte baixo;
};
PacketData receiverData;


// funçao callback quando os dados sao recebidos
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) 
{
  if (len == 0)
  {
    return;
  }
  memcpy(&receiverData, incomingData, sizeof(receiverData));

  // envia os dados para o UNO pela comunicação master/slave
  if(receiverData.cima == 1){      
    Wire.beginTransmission(slaveAdress);
    Wire.write("1");
    Wire.endTransmission();
  }
  if(receiverData.baixo == 1){
    Wire.beginTransmission(slaveAdress);
    Wire.write("2");
    Wire.endTransmission();
  }
  if(receiverData.dir == 1){
    Wire.beginTransmission(slaveAdress);
    Wire.write("3");
    Wire.endTransmission();
  }
  if(receiverData.esq == 1){
    Wire.beginTransmission(slaveAdress);
    Wire.write("4");
    Wire.endTransmission();
  }

  lastRecvTime = millis();   
}


void setup() 
{
  Wire.begin(); 
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) 
  {
    Serial.println("Erro inicializando ESP-NOW");
    return;
  }

  esp_now_register_recv_cb(OnDataRecv);
}
 
void loop() 
{
  //Checa a perda de sinal
  unsigned long now = millis();
  if ( now - lastRecvTime > SIGNAL_TIMEOUT ) 
  {
    Serial.println("sinal perdido");
  }
}

O código que deve ser carregado no Arduino UNO é o seguinte:

//inclui a biblioteca
#include "Wire.h" 
//define o endereço para o Master/Slave
const int  myAdress =  0x08;
//define onde os pinos da ponte H estão conectados no arduino
int pino1 = 4;
int pino2 = 5;
int pino3 = 6;
int pino4 = 7;
//variaveis para o controle dos dados recebidos
int dados = 0;
bool frente = false;
bool tras = false;
bool esquerda = false;
bool direita = false;
  
void setup(){
  Serial.begin(9600);
  Wire.begin(myAdress); //inicia o protocolo master/slave
  Wire.onReceive(receiveEvent);
  
  //define os pinos como saida
  pinMode(pino1, OUTPUT);
  pinMode(pino2, OUTPUT);
  pinMode(pino3, OUTPUT);
  pinMode(pino4, OUTPUT);
}
void loop(){
 Serial.print("DADOS: "); 
 Serial.println(dados);
    // condições para o controle do motor de acordo com os dados recebidos dos botões
    if (dados == 51) {
      Serial.println("RECEBIDO 1");
      direita = true ;  // se a placa receber que o botão de cima está pressionado, ele manda o robô ir para frente
    }
    if (dados == 49){
      Serial.println("RECEBIDO 2");
      tras = true; // se a placa receber que o botão de baixo está pressionado, ele manda o robô ir para trás
    }
    if (dados == 52){
      Serial.println("RECEBIDO 3");
      esquerda = true; // se a placa receber que o botão da direita está pressionado, ele manda o robô ir para direita
    }
    if(dados == 50){
      Serial.println("RECEBIDO 4");
      frente = true ; // se a placa receber que o botão da esquerda está pressionado, ele manda o robô ir para esquerda
    }
 if(tras == true){
   vaitras();
   tras = !tras;
   dados = 0;
 }
 else if(frente == true){
   vaifrente();
   frente = !frente ;
   dados = 0;
 }
 else if(esquerda == true){
   vaiesquerda();
   esquerda = !esquerda ;
   dados = 0;
 }
 else if(direita == true){
   vaidireita();
   direita = !direita;
   dados = 0;
 }
}
void receiveEvent(int howMany) {
  // verifica se existem dados para serem lidos no barramento I2C
  if (Wire.available()) {
    char received = Wire.read();
    Serial.println(received);
    dados = received;
    }
    int dados = Wire.read();
}
void vaifrente(){  //responsável por mandar o robo para frente
  digitalWrite(pino1, HIGH);
  digitalWrite(pino2, LOW);
  digitalWrite(pino3, HIGH);
  digitalWrite(pino4, LOW);
  delay(200);
  digitalWrite(pino1, HIGH);
  digitalWrite(pino2, HIGH);
  digitalWrite(pino3, HIGH);
  digitalWrite(pino4, HIGH);
}
void vaitras(){  //responsável por mandar o robo para trás
  digitalWrite(pino1, LOW);
  digitalWrite(pino2, HIGH);
  digitalWrite(pino3, LOW);
  digitalWrite(pino4, HIGH);
  delay(200);
  digitalWrite(pino1, HIGH);
  digitalWrite(pino2, HIGH);
  digitalWrite(pino3, HIGH);
  digitalWrite(pino4, HIGH);
}
void vaidireita(){ //responsável por mandar o robo para esquerda
  digitalWrite(pino3, LOW);
  digitalWrite(pino4, LOW);
  digitalWrite(pino1, LOW);
  digitalWrite(pino2, HIGH);
  delay(200);
  digitalWrite(pino1, HIGH);
  digitalWrite(pino2, HIGH);
  digitalWrite(pino3, HIGH);
  digitalWrite(pino4, HIGH);
}
void vaiesquerda(){ //responsável por mandar o robo para direita
  digitalWrite(pino3, LOW);
  digitalWrite(pino4, HIGH);
  digitalWrite(pino1, HIGH);
  digitalWrite(pino2, HIGH);
  delay(200);
  digitalWrite(pino1, HIGH);
  digitalWrite(pino2, HIGH);
  digitalWrite(pino3, HIGH);
  digitalWrite(pino4, HIGH);
}

Caso queira entender mais sobre o protocolo ESP-NOW,  acesse o post abaixo:
https://blog.eletrogate.com/esp-now-comunicacao-sem-fio-entre-esp32s/


Atenção

É necessário mudar o endereço Mac no código do emissor de acordo com o endereço MAC do seu esp32.

No meu caso, o endereço MAC do meu ESP32 é C0:49:EF:E4:D8:A8

Para descobrir o seu endereço MAC, basta carregar o seguinte código no seu esp32:

/******************************************************************************
                        ESP-NOW: Comunicação entre ESP32s
                      Sketch Obtendo endereço MAC do ESP32

                          Criado em 08 de Dezembro de 2022
                                por Michel Galvão

  Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
                            https://www.eletrogate.com/
******************************************************************************/

// Inclusão das bibliotecas
#include <WiFi.h>

void setup() {
  Serial.begin(115200); // configurada a taxa de transferência em 115200 bits por segundo para a transmissão serial
  WiFi.mode(WIFI_MODE_STA); // configura o WIFi para o Modo de estação WiFi
  
  Serial.print("Endereço MAC: ");
  Serial.println(WiFi.macAddress()); // retorna o endereço MAC do dispositivo

  while(1); // loop infinito
}

void loop() {}

Esse código foi feito pelo Michel Galvão lá no post sobre ESP-NOW.


Montagem

Diagrama do Emissor:

Diagrama do Receptor:

*É necessário remover o jumper da alimentação do circuito lógico da ponte H

Caso tenha interesse em mudar a alimentação do seu projeto da forma adequada, acesse o post abaixo:

Guia Definitivo de uso da Ponte H L298N


Sobre o Autor


Arthur Almeida

Estudante do Ensino médio , aficionado por criar novos projetos eletrônicos e automações, principalmente com o Arduino. No meu tempo livre eu gosto de pesquisar sobre novas tecnologias e tento criar projetos com elas.


Eletrogate

26 de dezembro de 2023

A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.

Tenha a Metodologia Eletrogate dentro da sua Escola! Conheça nosso Programa de Robótica nas Escolas!

Eletrogate Robô

Cadastre-se e fique por
dentro de novidades!