Conforme demonstra este nosso artigo sobre o módulo WiFi LoRa 32(V2), ela consiste numa placa completa para quem quer realizar projetos completos inseridos no contexto de IoT (Internet of Things - Internet das Coisas). Indo desde interação com sensores, controle de periféricos diversos até comunicação wi-fi e LoRa, o módulo WiFi LoRa 32(V2) atende perfeitamente às necessidades da maioria dos projetos, sendo uma solução compacta e poderosa em termos de recursos de comunicação e poder computacional.

 

Dando continuidade aos usos deste módulo, vamos utilizá-lo para criar um robô! Tal robô é do tipo rover, ou seja, um robô do tipo explorador, inspirado principalmente nos robôs de exploração espacial que utilizam rodas para locomoção. Tal robô será controlado pela Internet, permitindo que o controle seja feito de qualquer lugar do planeta que possua conectividade à Internet. Como forma de explorar o maior número de possibilidades deste projeto, serão mostradas duas formas de fazer o acionamento e controle dos motores do rover: acionamento direto com relés e com um módulo amplificador/driver e ponte-H. Os motores deste robô serão pequenos motores DC comumente encontrados no mercado maker.

Ao fim deste artigo, o leitor será capaz de montar seu próprio robô, podendo escolher o acionamento e controle do motor DC mais adequado ao seu uso e controlá-lo de qualquer lugar do planeta via Internet.

 

Material necessário

Para reproduzir o projeto deste artigo, você precisará de:

Um módulo WiFi LoRa 32(V2)

Uma fonte / carregador de celular (conector micro-USB) do tipo powerbank - tensão de 5V, com pelo menos 2A de corrente de saída

Um chassis de robô com duas rodas (similar a este aqui). Chassis deste tipo já são vendidos com motores DC (de 3V até 6V de tensão de operação, já com caixa de redução acoplada)

Um cabo micro-USB (para programação do WiFi LoRa 32(V2))

Dois transistores BC548 (ou equivalente NPN, como o BC337, por exemplo)

Dois resistores 1K/0,25W

Dois resistores 2K2/0,25W

Módulo relé / Shield relé de 2 canais

Jumpers macho-macho

Um driver de motor DC (com Ponte H) usando o circuito integrado L298N. Tal driver é encontrado no mercado maker com o nome módulo L298N

 

 

Primeira forma de controle e acionamento de motores DC: via relés

Iniciaremos com a forma mais simples e intuitiva de controle e acionamento de motores DC: acionamento via relés ou controle on/off. Esta forma é a mais simples de controle e acionamento de motores DC existente, pois funciona da mesma forma de que se ligássemos uma “chave” para acionar o motor. Ou seja, trata-se de um controle do tipo on/off, puro e simples, utilizando como “chave” um relé.

Neste tipo de acionamento e controle de motores DC, no quesito de dimensionamento dos relés, devemos nos atentar não somente à tensão suportada na carga, mas também quanto à corrente de operação máxima suportada. Esta não deve ser menor que a corrente máxima (de pico) consumida pelo motor. Para o caso dos motores usados nesse projeto, a corrente de pico (na partida, por pouquíssimos milissegundos) atinge algo em torno de 1,2A, portanto qualquer relé capaz de suportar 1,2A ou mais de corrente elétrica e com tensão da carga igual ou superior a 6V pode ser utilizado.

Como esta forma de acionamento e controle de motor se resume basicamente em alimentar (on) e tirar a alimentação (off) do motor, a movimentação do rover é definida e restrita conforme a seguir:

 

Ir para frente: acionamento dos dois motores de forma simultânea (figura 1.a)

Girar para direita: acionamento do motor da esquerda somente (figura 1.b), de forma que o rover gire sobre seu próprio eixo.

Girar para esquerda: acionamento do motor da direita somente (figura 1.c), de forma que o rover gire sobre seu próprio eixo.

Parar: desacionamento de ambos os motores.

Ré: a forma de acionamento e controle simples on/off não contempla controle de sentido de rotação dos motores. Logo, não é possível mover o robô diretamente para trás. Logo, como estratégia para ir para trás, devemos mover o robô para a direita ou esquerda até que este dire 180º.

 

Observe a figura 1, onde é possível vermos a movimentação possível de ser feita com este tipo de controle e acionamento dos motores DC.

 

 

Figura 1 - movimentação do rover
Figura 1 - movimentação do rover

 

 

Circuito esquemático

O circuito esquemático do rover com controle e acionamento de motores com relés é mostrado na figura 2.

 

Figura 2 - circuito esquemático do projeto (robô do tipo rover)
Figura 2 - circuito esquemático do projeto (robô do tipo rover)

 

 

Porém, as seguintes observações são pertinentes:

Para a alimentação dos motores é necessário utilizar um carregador de baterias de celular portátil (conhecido no mercado como powerbank).

O motivo disso é que os motores, quando acionados, consomem muita energia, levando ao rápido consumo de baterias. Portanto, a utilização de carregadores portáteis de celular minimizará custos do projeto (e torná-lo recarregável). Tais carregadores portáteis possuem capacidade de fornecimento de corrente mais do que suficientes para o referido projeto.

Aqui, o objetivo do controle e acionamento dos motores com relés foi a simplificação do circuito.

Você notará que foram utilizados transistores para acionar o Shield de Relés a partir do WiFi LoRa 32(V2). Isso foi necessário, pois o Shield de Relés necessita de uma tensão de acionamento maior que a tensão de saída de um GPIO do módulo WiFi LoRa 32(V2) (o módulo WiFi LoRa 32(V2) utiliza 3,3V, enquanto o Shield de Relés necessita de 5V). Como não é uma boa ideia acioná-lo com tensão menor que a especificada, os transistores serão responsáveis por “converter” os níveis de tensão para àqueles dentro do especificado.

 

 

Controle da movimentação via Internet (com MQTT)

Agora que já definimos o circuito esquemático e movimentação do rover, falta somente uma definição antes de partirmos para o código-fonte do rover (versão do controle e acionamento de motores via relés): definir como controlar o robô através da Internet (via MQTT). Se você não está familiarizado com MQTT no módulo WiFi LoRa 32(V2), recomendo que leia o artigo de Monitoramento de Temperatura Ambiente e Umidade Relativa do Ar via Internet.

Para o controle via Internet do rover, primeiramente precisamos definir 3 caracteres / letras que, enviadas ao rover via MQTT, irão fazê-lo ir para frente, direita ou esquerda. Além disso, é necessário também um comando para fazê-lo parar (desligar os dois motores). Sendo assim, vamos definir estes caracteres / letras conforme o seguinte:

Caractere que, quando recebido, move o rover para frente: F (figura 3.a)

Caractere que, quando recebido, move o rover para direita: D (figura 3.b)

Caractere que, quando recebido, move o rover para esquerda: E (figura 3.c)

Caractere que, quando recebido, faz o rover parar: P

 

Observe a figura 3 para mais detalhes.

 

 

Figura 3 - movimentação do rover mediante comando recebido via MQTT
Figura 3 - movimentação do rover mediante comando recebido via MQTT

 

 

Além disso, via MQTT, é possível também monitorar o robô (monitorar sua movimentação). Para isso, o robô envia 3 caracteres em sequência via MQTT, conforme abaixo:

 

Estado do motor direito: caractere ‘1’ para acionado ou caractere ‘0’ para desacionado

Separador: caractere ‘-’

Estado do motor esquerdo: caractere ‘1’ para acionado ou caractere ‘0’ para desacionado

 

Código-fonte do rover

É chegada a hora de escrever o código-fonte do projeto.

 

IMPORTANTE 1: leia atentamente os comentários do mesmo para completa compreensão de seu funcionamento.

IMPORTANTE 2: instale a biblioteca relativa ao MQTT informada no artigo Monitoramento de Temperatura Ambiente e Umidade Relativa do Ar via Internet 

 

/* Programa: código-fonte do robô tipo rover (controle e acionamento de motores              com relés   Descrição: código-fonte do robô tipo rover, controlado por Internet via MQTT.               Sua movimentação é feita conforme a recepção de caracteres via MQTT:              F: rover se move para frente              D: rover se move para a direita              E: rover se move para a esquerda              P: o rover para (os motores são desacionados)   Autor: Pedro Bertoleti*//* includes */ #include <WiFi.h> #include <PubSubClient.h>/* defines gerais */#define BAUDRATE_SERIAL_DEBUG       115200/* defines de id mqtt e tópicos para publicação e subscribe */#define TOPICO_SUB "MQTTRoverEnvia"          /* tópico MQTT de escuta */#define TOPICO_PUB "MQTTRoverRecebe"         /* tópico MQTT de envio de informações para Broker */#define ID_MQTT  "RoboRoverINCB"             /* id mqtt (para identificação de sessão) */
                                             /* IMPORTANTE: este deve ser único no broker (ou seja,                                                             se um client MQTT tentar entrar com o mesmo                                                             id de outro já conectado ao broker, o broker                                                             irá fechar a conexão de um deles).                                              *//* defines - motores */#define MOTOR_DIRETO     12 /* GPIO 12 */#define MOTOR_ESQUERDO   13 /* GPIO 13 *//* defines - movimentacao */#define CARACTER_MOVE_FRENTE    "F"#define CARACTER_MOVE_DIREITA   "D"#define CARACTER_MOVE_ESQUERDA  "E"#define CARACTER_PARA_ROVER     "P"/* Variáveis e objetos globais: *//* WIFI */const char* SSID_WIFI = " ";     /* Coloque aqui o SSID_WIFI / nome da rede WI-FI que deseja se conectar */const char* PASSWORD_WIFI = " "; /* Coloque aqui a senha da rede WI-FI que deseja se conectar */
 /* MQTT */const char* BROKER_MQTT = "iot.eclipse.org"; /* URL do broker MQTT que se deseja utilizar */int BROKER_PORT = 1883;                      /* Porta do Broker MQTT *//* Variáveis e objetos globais */
WiFiClient espClient;              /* cria o objeto espClient */
PubSubClient MQTT(espClient);      /* objeto PubSubClient */char estado_motor_direito = '0';   /* estado atual do motor da direita */char estado_motor_esquerdo = '0';  /* estado atual do motor da esquerda */
 /* Prototypes */void init_serial_debug(void);void init_wifi(void);void init_MQTT(void);void connect_wifi(void); void init_outputs(void);void mqtt_callback(char* topic, byte* payload, unsigned int length);void verifica_conexoes_wifi_e_MQTT(void);void envia_estado_output_MQTT(void);/*  *  Implementações das funções */void setup() 
{
    //Faz as inicializações necessárias
    init_outputs();
    init_serial_debug();
    init_wifi();
    init_MQTT();
}
 /* Função: inicializa comunicação serial com baudrate 115200 (para fins de monitorar no terminal serial            o que está acontecendo.   Parâmetros: nenhum   Retorno: nenhum*/void init_serial_debug(void) 
{
    Serial.begin(BAUDRATE_SERIAL_DEBUG);
}/* Função: inicializa e conecta-se na rede WI-FI desejada   Parâmetros: nenhum   Retorno: nenhum*/void init_wifi(void) 
{
    delay(10);
    Serial.println("------Conexao WI-FI -----");
    Serial.print("Conectando-se na rede: ");
    Serial.println(SSID_WIFI);
    Serial.println("Aguarde");
    
    connect_wifi();
}
 /* Função: inicializa parâmetros de conexão MQTT(endereço do            broker, porta e seta função de callback)   Parâmetros: nenhum   Retorno: nenhum*/void init_MQTT(void) 
{
    MQTT.setServer(BROKER_MQTT, BROKER_PORT);   //informa qual broker e porta deve ser conectado
    MQTT.setCallback(mqtt_callback);            //atribui função de callback (função chamada quando qualquer informação de um dos tópicos subescritos chega)
}
 /* Função: função de callback            esta função é chamada toda vez que uma informação de            um dos tópicos subescritos chega)   Parâmetros: nenhum   Retorno: nenhum*/void mqtt_callback(char* topic, byte* payload, unsigned int length) 
{
    String msg;
    int i;
    /* obtem a string do payload recebido */
    for(i = 0; i < length; i++) 
    {
       char c = (char)payload[i];
       msg += c;
    }
  
    /* toma ação dependendo da string recebida:  */
    if (msg.equals(CARACTER_MOVE_FRENTE))
    {
        //para ir para frente, os dois motores são ligados
        digitalWrite(MOTOR_DIRETO, HIGH);
        digitalWrite(MOTOR_ESQUERDO, HIGH);
 
        estado_motor_direito = '1';
        estado_motor_esquerdo = '1';
    }
    if (msg.equals(CARACTER_MOVE_DIREITA))
    {
        /* para ir para a direita, somente o motor da esquerda é ligado */
        digitalWrite(MOTOR_DIRETO, LOW);
        digitalWrite(MOTOR_ESQUERDO, HIGH);
 
        estado_motor_direito = '0';
        estado_motor_esquerdo = '1';
    }
    if (msg.equals(CARACTER_MOVE_ESQUERDA))
    {
        /* para ir para a esquerda, somente o motor da direita é ligado */
        digitalWrite(MOTOR_DIRETO, HIGH);
        digitalWrite(MOTOR_ESQUERDO, LOW);
 
        estado_motor_direito = '1';
        estado_motor_esquerdo = '0';
    }
    if (msg.equals(CARACTER_PARA_ROVER))
    {
        /* para parar, os dois motores são desligados */
        digitalWrite(MOTOR_DIRETO, LOW);
        digitalWrite(MOTOR_ESQUERDO, LOW);
 
        estado_motor_direito = '0';
        estado_motor_esquerdo = '0';
    }
}
 /* Função: reconecta-se ao broker MQTT (caso ainda não esteja conectado ou em caso de a conexão cair)           em caso de sucesso na conexão ou reconexão, o subscribe dos tópicos é refeito.   Parâmetros: nenhum   Retorno: nenhum*/void reconnectMQTT() 
{
    while (!MQTT.connected()) 
    {
        Serial.print("* Tentando se conectar ao Broker MQTT: ");
        Serial.println(BROKER_MQTT);
        if (MQTT.connect(ID_MQTT)) 
        {
            Serial.println("Conectado com sucesso ao broker MQTT!");
            MQTT.subscribe(TOPICO_SUB); 
        } 
        else 
        {
            Serial.println("Falha ao reconectar no broker.");
            Serial.println("Havera nova tentatica de conexao em 2s");
            delay(2000);
        }
    }
}
 /* Função: reconecta-se ao WiFi   Parâmetros: nenhum   Retorno: nenhum*/void connect_wifi(void) 
{
    /* se já está conectado a rede WI-FI, nada é feito.        Caso contrário, são efetuadas tentativas de conexão */
    if (WiFi.status() == WL_CONNECTED)
        return;
        
    WiFi.begin(SSID_WIFI, PASSWORD_WIFI); // Conecta na rede WI-FI
    
    while (WiFi.status() != WL_CONNECTED) 
    {
        delay(100);
        Serial.print(".");
    }
  
    Serial.println();
    Serial.print("Conectado com sucesso na rede ");
    Serial.print(SSID_WIFI);
    Serial.println("IP obtido: ");
    Serial.println(WiFi.localIP());
}/* Função: verifica o estado das conexões WiFI e ao broker MQTT.            Em caso de desconexão (qualquer uma das duas), a conexão           é refeita.  Parâmetros: nenhum  Retorno: nenhum*/void verifica_conexoes_wifi_e_MQTT(void)
{
    if (!MQTT.connected()) 
        reconnectMQTT(); //se não há conexão com o Broker, a conexão é refeita
    
     connect_wifi(); //se não há conexão com o WiFI, a conexão é refeita
}/* Função: envia ao Broker o estado atual do output    Parâmetros: nenhum   Retorno: nenhum*/void envia_estado_output_MQTT(void)
{
    char estados_motores[4];
    char separador = '-'; 
    estados_motores[0] = estado_motor_direito;
    estados_motores[1] = separador;
    estados_motores[2] = estado_motor_esquerdo;
    estados_motores[3] = '\0';
    MQTT.publish(TOPICO_PUB, estados_motores);
    Serial.print("- Estados dos motores enviados via MQTT (");
    Serial.print(estados_motores);
    Serial.println(")");
    delay(1000);
}/* Função: inicializa os outputs em nível lógico baixo (desliga os dois motores)   Parâmetros: nenhum   Retorno: nenhum*/void init_outputs(void)
{
    pinMode(MOTOR_DIRETO, OUTPUT);
    pinMode(MOTOR_ESQUERDO, OUTPUT);
    
    digitalWrite(MOTOR_DIRETO, LOW);          
    digitalWrite(MOTOR_ESQUERDO, LOW);          
}/*  * Programa principal */void loop() 
{   
    /*    Ações a serem leitas no loop principak:    - garante funcionamento das conexões WiFi e ao broker MQTT    - envia o status de todos os outputs para o Broker    - envia keep-alive da comunicação com broker MQTT    */
    
    verifica_conexoes_wifi_e_MQTT();    
    envia_estado_output_MQTT();    
    MQTT.loop();
}

 

Resultado - movimentação e monitoramento via MQTT

Conforme mostrado no artigo Monitoramento de Temperatura Ambiente e Umidade Relativa do Ar via Internet, é possível utilizarmos o cliente MQTT MQTTLens ( Download ) para enviar e receber informações via MQTT do módulo WiFi LoRa 32(V2). Veja o resultado da recepção dos estados dos motores na figura 4.

  

Figura 4 - estado dos motores (recebidos via MQTT no cliente MQTTLens)
Figura 4 - estado dos motores (recebidos via MQTT no cliente MQTTLens)

 

 

Segunda forma de controle e acionamento de motores DC: via L298N

Aqui, acionaremos e controlar o motor utilizando um módulo que contém o circuito integrado L298N, um driver de motor e ponte H. Este circuito integrado permite o controle de dois motores (cujo consumo de corrente elétrica de cada motor seja, no máximo, 2A) de forma a, além de acionar e “desacionar” os mesmos, controlar os sentidos de rotação de cada motor (horário e anti-horário). Facilmente encontrado no mercado maker, ele é vendido na forma de um módulo, já com tudo necessário para operar. Tal módulo pode ser visto na figura 5, e é comumente encontrado como módulo L298N.

  

   Figura 5 - módulo de acionamento de motores (com ponte H) feito com o circuito integrado L298N
Figura 5 - módulo de acionamento de motores (com ponte H) feito com o circuito integrado L298N

 

 

As especificações do módulo L298N podem ser vistas a seguir:

Tensão de operação: 4V até 35V

Permite controle simultâneo de 2 motores DC ou 1 motor de passo

Corrente de operação máxima por motor/canal: 2A

Tensão da parte lógica/controle: 3,3V

Limites de temperatura de operação: -20°C a +135°C

Potência máxima: 25W (com uso de dissipador, já contido no módulo)

 

Funcionamento do módulo de driver de motor e ponte H

O módulo de driver de motor e ponte H tem as entradas e saídas definidas conforme mostrado na figura 6.

 

 

Figura 6 - entradas e saídas do módulo módulo de driver de motor e ponte H contendo o L298N (fonte da imagem: https://www.filipeflop.com/blog/motor-dc-arduino-ponte-h-l298n/)
Figura 6 - entradas e saídas do módulo módulo de driver de motor e ponte H contendo o L298N (fonte da imagem: https://www.filipeflop.com/blog/motor-dc-arduino-ponte-h-l298n/)

 

 

As entradas e saídas, bem como suas funcionalidades, estão detalhadas abaixo:

 

MOTOR A e MOTOR B: borne para ligação de dois motores DC (ou um motor de passo, se utilizado ambos os canais). Em cada canal (MOTOR A ou MOTOR B) é possível acionar e controlar o sentido de rotação de um motor DC de consumo de corrente de até 2A (isso é possível graças ao dissipador do L298N que acompanha o módulo)

ATIVA MA e ATIVA MB: jumpers para os motores A e B (ATIVA MA e ATIVA MB, respectivamente) que indicam se estes terão sua velocidade controlada por PWM (jumper ausente) ou se não haverá controle de velocidade dos motores (jumper presente).

ENTRADA (conjunto de entradas IN1, IN2, IN3 e IN4): conjunto de quatro entradas com finalidade de controlar tanto o acionamento quanto o sentido de rotação de cada motor individualmente (a lógica de acionamento das entradas será detalhada mais adiante neste mesmo artigo).

ATIVA 5V: este módulo permite, conforme especificação, controlar motores DC de tensão de operação de 4V até 35V. Além disso, o módulo conta com um regulador de tensão de 5V. No caso de controle de motores DC de tensão de operação entre 6-35V (ou seja, jumper presente em ATIVA 5V), o regulador de 5V disponibiliza 5V no pino correspondente (chamado 5V). Isso tem uma utilidade muito interessante para o caso de, a partir da alimentação do motor, alimentar outros componentes eletrônicos externos com 5V (poupando a necessidade de se utilizar um regulador de tensão de 5V externo adicional). Com jumper ausente em ATIVA 5V, o módulo espera que a alimentação para os motores venha de uma fonte externa, ligada ao pino 5V.

 

 

Controle da movimentação via Internet (com MQTT)

Neste ponto, o controle do robô via MQTT se difere um pouco do visto na versão com relés previamente neste artigo. A diferenciação se dá pelo fato de que, ao invés de se ter somente motor desligado e motor ligado como estados possíveis, com o módulo L298N existem os seguintes estados possíveis de acionamento e controle dos motores DC: motor parado, motor com giro em sentido horário e motor com giro em sentido anti-horário.

Além disso, como há a possibilidade de mudança no sentido de rotação dos motores, o robô ganha um novo movimento, o qual não era possível em sua versão de controle e acionamento de motores DC com relés: ir para trás (ré).

Desta forma, os caracteres utilizados para controlar o rover são:

 

Caractere que, quando recebido, move o rover para frente: F (figura 7.a)

Caractere que, quando recebido, move o rover para direita: D (figura 7.b)

Caractere que, quando recebido, move o rover para esquerda: E (figura 7.c)

Caractere que, quando recebido, move o rover para esquerda: R (figura 7.d)

Caractere que, quando recebido, faz o rover parar: P

 

Observe a figura 7 para mais detalhes.

 

 

 

Figura 7 - movimentação do rover mediante comando recebido via MQTT (com controle de motores utilizando módulo L298N)
Figura 7 - movimentação do rover mediante comando recebido via MQTT (com controle de motores utilizando módulo L298N)

 

 

Além disso, também há pequenas diferenças quanto às informações enviadas pelo rover ao via MQTT. Agora, cada motor pode ter seu estado representado por três caracteres distintos:

 

Motor parado: caractere ‘P’

Motor com giro em sentido horário: caractere ‘H’

Motor com giro em sentido anti-horário: caractere ‘A’

 

Portanto, a mensagem enviada pelo rover via MQTT tem formato definido conforme abaixo:

 

Estado do motor direito (caractere ‘P’, ‘H’, ou ‘A’)

Separador: caractere ‘-’

Estado do motor esquerdo (caractere ‘P’, ‘H’, ou ‘A’)

 

 

 

Acionamento de motores e controle de sentido de rotação com entradas IN1, IN2, IN3 e IN4

 Para entender por completo o módulo, resta apenas compreender como acionar os motores e controlar o sentido de rotação de cada um deles. Para isso, iremos fazer uso das entradas IN1, IN2, IN3 e IN4. De forma geral, as entradas IN1 e IN2 controlam o acionamento e sentido de rotação do motor A, enquanto IN3 e IN4 controlam o acionamento e sentido de rotação do motor B.

Observe a tabela 1. Nela, são informadas as condições de IN1, IN2, IN3 e IN4 para cada situação de acionamento e controle de rotação dos motores. Nela ‘1’ significa nível lógico alto (3,3V), ‘0’ significa nível lógico baixo (0V) e ‘X’ é uma don’t care condition.

 

IN1

IN2

IN3

IN4

Comportamento esperado

0

0

X

X

Motor A em “ponto morto” (sem giro e sem freio)

1

1

X

X

Motor A com freio (sem giro)

1

0

X

X

Motor A acionado e com giro em sentido horário

0

1

X

X

Motor A acionado e com giro em sentido anti-horário

X

X

0

0

Motor B em “ponto morto” (sem giro e sem freio)

X

X

1

1

Motor B com freio (sem giro)

X

X

1

0

Motor B acionado e com giro em sentido horário

X

X

0

1

Motor B acionado e com giro em sentido anti-horário

 

 

Circuito esquemático

O circuito esquemático do rover utilizando o módulo de driver de motor e ponte H com L298N pode ser visto na figura 8.

  

Figura 8 - circuito esquemático (com módulo L298N)
Figura 8 - circuito esquemático (com módulo L298N)

 

 

 A seguinte observação é pertinente: para a alimentação dos motores é necessário utilizar um carregador de baterias de celular portátil (conhecido no mercado como powerbank). O motivo disso é que os motores, quando acionados, consomem muita energia, levando ao rápido consumo de baterias. Portanto, a utilização de carregadores portáteis de celular minimizará custos do projeto (e torná-lo recarregável). Tais carregadores portáteis possuem capacidade de fornecimento de corrente mais do que suficientes para o referido projeto.

 

 

 

 

Código-fonte

 

É chegada a hora de escrever o código-fonte do projeto utilizando o módulo L298N para controlar os motores DC do rover.

IMPORTANTE 1: leia atentamente os comentários do mesmo para completa compreensão de seu funcionamento.

IMPORTANTE 2: este projeto também faz uso da biblioteca relativa ao MQTT informada no artigo Monitoramento de Temperatura Ambiente e Umidade Relativa do Ar via Internet .

 

/* Programa: código-fonte do robô tipo rover (controle e acionamento de motores              com amplificador e ponte H L298N)   Descrição: código-fonte do robô tipo rover, controlado por Internet via MQTT.               Sua movimentação é feita conforme a recepção de caracteres via MQTT:              F: rover se move para frente              D: rover se move para a direita              E: rover se move para a esquerda              R: rover se move para trás              P: o rover para (os motores são desacionados)   Autor: Pedro Bertoleti*//* includes */ #include <WiFi.h> #include <PubSubClient.h>/* defines gerais */#define BAUDRATE_SERIAL_DEBUG       115200/* defines de id mqtt e tópicos para publicação e subscribe */#define TOPICO_SUB "MQTTRoverEnvia"          /* tópico MQTT de escuta */#define TOPICO_PUB "MQTTRoverRecebe"         /* tópico MQTT de envio de informações para Broker */#define ID_MQTT  "RoboRoverINCB"             /* id mqtt (para identificação de sessão) */
                                             /* IMPORTANTE: este deve ser único no broker (ou seja,                                                             se um client MQTT tentar entrar com o mesmo                                                             id de outro já conectado ao broker, o broker                                                             irá fechar a conexão de um deles).                                              *//* defines - controle do L298N */#define IN1              13 /* GPIO 13 */#define IN2              12 /* GPIO 12 */#define IN3              25 /* GPIO 25 */#define IN4              17 /* GPIO 17 *//* defines - movimentacao */#define CARACTER_MOVE_FRENTE    "F"#define CARACTER_MOVE_DIREITA   "D"#define CARACTER_MOVE_ESQUERDA  "E"#define CARACTER_MOVE_TRAS      "R"#define CARACTER_PARA_ROVER     "P"/* Variáveis e objetos globais: *//* WIFI */const char* SSID_WIFI = " ";     /* Coloque aqui o SSID_WIFI / nome da rede WI-FI que deseja se conectar */const char* PASSWORD_WIFI = " "; /* Coloque aqui a senha da rede WI-FI que deseja se conectar */
 /* MQTT */const char* BROKER_MQTT = "iot.eclipse.org"; /* URL do broker MQTT que se deseja utilizar */int BROKER_PORT = 1883;                      /* Porta do Broker MQTT *//* Variáveis e objetos globais */
WiFiClient espClient;              /* cria o objeto espClient */
PubSubClient MQTT(espClient);      /* objeto PubSubClient */char sentido_motor_direito =  'P';   /* sentido de rotação atual do motor da direita */char sentido_motor_esquerdo = 'P';   /* sentido de rotação atual do motor da esquerda */
 /* Prototypes */void init_serial_debug(void);void init_wifi(void);void init_MQTT(void);void connect_wifi(void); void init_outputs(void);void mqtt_callback(char* topic, byte* payload, unsigned int length);void verifica_conexoes_wifi_e_MQTT(void);void envia_estado_output_MQTT(void);/*  *  Implementações das funções */void setup() 
{
    //Faz as inicializações necessárias
    init_outputs();
    init_serial_debug();
    init_wifi();
    init_MQTT();
}
 /* Função: inicializa comunicação serial com baudrate 115200 (para fins de monitorar no terminal serial            o que está acontecendo.   Parâmetros: nenhum   Retorno: nenhum*/void init_serial_debug(void) 
{
    Serial.begin(BAUDRATE_SERIAL_DEBUG);
}/* Função: inicializa e conecta-se na rede WI-FI desejada   Parâmetros: nenhum   Retorno: nenhum*/void init_wifi(void) 
{
    delay(10);
    Serial.println("------Conexao WI-FI -----");
    Serial.print("Conectando-se na rede: ");
    Serial.println(SSID_WIFI);
    Serial.println("Aguarde");
    
    connect_wifi();
}
 /* Função: inicializa parâmetros de conexão MQTT(endereço do            broker, porta e seta função de callback)   Parâmetros: nenhum   Retorno: nenhum*/void init_MQTT(void) 
{
    MQTT.setServer(BROKER_MQTT, BROKER_PORT);   //informa qual broker e porta deve ser conectado
    MQTT.setCallback(mqtt_callback);            //atribui função de callback (função chamada quando qualquer informação de um dos tópicos subescritos chega)
}
 /* Função: função de callback            esta função é chamada toda vez que uma informação de            um dos tópicos subescritos chega)   Parâmetros: nenhum   Retorno: nenhum*/void mqtt_callback(char* topic, byte* payload, unsigned int length) 
{
    String msg;
    int i;
    /* obtem a string do payload recebido */
    for(i = 0; i < length; i++) 
    {
       char c = (char)payload[i];
       msg += c;
    }
  
    /* toma ação dependendo da string recebida: */
    if (msg.equals(CARACTER_MOVE_FRENTE))
    {
        /* para ir para frente, os dois motores são ligados em sentido horário */
        digitalWrite(IN1, HIGH);          
        digitalWrite(IN2, LOW);  
        digitalWrite(IN3, HIGH);          
        digitalWrite(IN4, LOW); 
        
        sentido_motor_direito = 'H';
        sentido_motor_esquerdo = 'H';
    }
    if (msg.equals(CARACTER_MOVE_TRAS))
    {
        /* para ir para trás, os dois motores são ligados em sentido anti-horário */
        digitalWrite(IN1, LOW);          
        digitalWrite(IN2, HIGH);  
        digitalWrite(IN3, LOW);          
        digitalWrite(IN4, HIGH);        
        sentido_motor_direito = 'A';
        sentido_motor_esquerdo = 'A';
    }
    if (msg.equals(CARACTER_MOVE_DIREITA))
    {
        /* para ir para a direita,o motor da direita move-se em sentido anti-horário e            o motor da esquerda em sentido horário */
        digitalWrite(IN1, LOW);          
        digitalWrite(IN2, HIGH);
        digitalWrite(IN3, HIGH);          
        digitalWrite(IN4, LOW);
        sentido_motor_direito = 'A';
        sentido_motor_esquerdo = 'H';
    }
    if (msg.equals(CARACTER_MOVE_ESQUERDA))
    {
        /* para ir para a direita,o motor da direita move-se em sentido horário e            o motor da esquerda em sentido anti-horário */
        digitalWrite(IN1, HIGH);          
        digitalWrite(IN2, LOW);
        digitalWrite(IN3, LOW);          
        digitalWrite(IN4, HIGH); 
        
        sentido_motor_direito = 'H';
        sentido_motor_esquerdo = 'A';
    }
    if (msg.equals(CARACTER_PARA_ROVER))
    {
        /* para parar, os dois motores são desligados */
        digitalWrite(IN1, HIGH);          
        digitalWrite(IN2, HIGH);  
        digitalWrite(IN3, HIGH);          
        digitalWrite(IN4, HIGH);  
 
        sentido_motor_direito = 'P';
        sentido_motor_esquerdo = 'P';
    }
}
 /* Função: reconecta-se ao broker MQTT (caso ainda não esteja conectado ou em caso de a conexão cair)           em caso de sucesso na conexão ou reconexão, o subscribe dos tópicos é refeito.   Parâmetros: nenhum   Retorno: nenhum*/void reconnectMQTT() 
{
    while (!MQTT.connected()) 
    {
        Serial.print("* Tentando se conectar ao Broker MQTT: ");
        Serial.println(BROKER_MQTT);
        if (MQTT.connect(ID_MQTT)) 
        {
            Serial.println("Conectado com sucesso ao broker MQTT!");
            MQTT.subscribe(TOPICO_SUB); 
        } 
        else 
        {
            Serial.println("Falha ao reconectar no broker.");
            Serial.println("Havera nova tentatica de conexao em 2s");
            delay(2000);
        }
    }
}
 /* Função: reconecta-se ao WiFi   Parâmetros: nenhum   Retorno: nenhum*/void connect_wifi(void) 
{
    /* se já está conectado a rede WI-FI, nada é feito.        Caso contrário, são efetuadas tentativas de conexão     */
    if (WiFi.status() == WL_CONNECTED)
        return;
        
    WiFi.begin(SSID_WIFI, PASSWORD_WIFI); // Conecta na rede WI-FI
    
    while (WiFi.status() != WL_CONNECTED) 
    {
        delay(100);
        Serial.print(".");
    }
  
    Serial.println();
    Serial.print("Conectado com sucesso na rede ");
    Serial.print(SSID_WIFI);
    Serial.println("IP obtido: ");
    Serial.println(WiFi.localIP());
}/* Função: verifica o estado das conexões WiFI e ao broker MQTT.            Em caso de desconexão (qualquer uma das duas), a conexão           é refeita.  Parâmetros: nenhum  Retorno: nenhum*/void verifica_conexoes_wifi_e_MQTT(void)
{
    if (!MQTT.connected()) 
        reconnectMQTT(); //se não há conexão com o Broker, a conexão é refeita
    
     connect_wifi(); //se não há conexão com o WiFI, a conexão é refeita
}/* Função: envia ao Broker o estado atual do output    Parâmetros: nenhum   Retorno: nenhum*/void envia_estado_output_MQTT(void)
{
    char estados_motores[4];
    char separador = '-'; 
    estados_motores[0] = sentido_motor_direito;
    estados_motores[1] = separador;
    estados_motores[2] = sentido_motor_esquerdo;
    estados_motores[3] = '\0';
    MQTT.publish(TOPICO_PUB, estados_motores);
    Serial.print("- Estados dos motores enviados via MQTT (");
    Serial.print(estados_motores);
    Serial.println(")");
    delay(1000);
}/* Função: inicializa os outputs de controle dos motores   Parâmetros: nenhum   Retorno: nenhum*/void init_outputs(void)
{
    pinMode(IN1, OUTPUT);
    pinMode(IN2, OUTPUT);
    pinMode(IN3, OUTPUT);
    pinMode(IN4, OUTPUT);
    /* Configura controles para que o robô fique parado (ambos os motores parados) */
    digitalWrite(IN1, HIGH);          
    digitalWrite(IN2, HIGH);  
    digitalWrite(IN3, HIGH);          
    digitalWrite(IN4, HIGH);                  
}/*  * Programa principal */void loop() 
{   
    /*    Ações a serem leitas no loop principak:    - garante funcionamento das conexões WiFi e ao broker MQTT    - envia o status de todos os outputs para o Broker    - envia keep-alive da comunicação com broker MQTT    */
    
    verifica_conexoes_wifi_e_MQTT();    
    envia_estado_output_MQTT();    
    MQTT.loop();
}

 

Resultado - movimentação e monitoramento via MQTT

Conforme mostrado anteriormente neste mesmo artigo, é possível utilizarmos o cliente MQTT chamado MQTTLens para enviar e receber informações via MQTT do módulo WiFi LoRa 32(V2). Veja o resultado da recepção dos estados dos motores na figura 8.

 

Figura 8 - estado dos motores (P, H ou A) recebidos via MQTT no cliente MQTTLens
Figura 8 - estado dos motores (P, H ou A) recebidos via MQTT no cliente MQTTLens

 

 

Conclusão

 Neste artigo, aprendemos como se faz um robô tipo rover (explorador) controlado por Internet, utilizando como placa de desenvolvimento / placa programável o módulo WiFi LoRa 32(V2). Ainda, foram apresentadas duas formas de se fazer o controle dos motores do rover: via relés (controle simples on/off) e via módulo com circuito integrado L298N, sendo este último mais completo pois possibilita controle de sentido de rotação dos motores.

Com os projetos aqui apresentados, o leitor poderá extrapolar o uso dos mesmos de forma praticamente sem limites, inclusive inserindo sensores e software capazes de transformar este rover em um robô autônomo, se assim desejar.