Robô Tipo Rover Controlado pela Internet (MEC312)

Escrito por Pedro Bertoleti

Conforme os artigos anteriores sobre o NodeMCU evidenciaram, esta trata-se de uma placa muito interessante para quem quer realizar projetos inseridos no contexto de IoT (Internet of Things - Internet das Coisas). Mais precisamente nos últimos artigos sobre esta placa, foi possível ver suas possibilidades de controle de periféricos diversos, incluindo motores DC.

Agora, vamos juntar os assuntos abordados e criar um robô! Tal robô será do tipo rover (ou seja, um robô do tipo explorador, inspirado sobretudo nos robôs de exploração espacial), controlado por Internet. Ao fim deste artigo, o leitor será capaz de montar seu próprio robô e controlá-lo de qualquer lugar do planeta com acesso à Internet.

 

Material necessário

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

Uma placa NodeMCU

Uma fonte / carregador de celular (conector micro-USB) do tipo powerbank - tensão de 5V, com pelo menos 1A 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 NodeMCU)

Dois transistores BC548 (ou equivalente NPN como o BC337)

Dois push-buttons

Dois resistores 1K/0,25W

Dois resistores 2K2/0,25W

Dois resistores 220R/0,25W

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

 

 

Recomendações / pré-requisitos

É recomendado que você leia atentamente os seguintes artigos antes de prosseguir com a construção do rover:

Monitoramento de Temperatura Ambiente e Umidade Relativa do Ar via Internet 

Acionamento de Motor DC com NodeMCU (MIC167) 

 

Considerações sobre o controle de motores DC utilizado neste artigo

Conforme o artigo Acionamento de Motor DC com NodeMCU (MIC167), vimos que o controle de motores DC adotado tem as seguintes considerações:

O controle de motores DC adotado não compreende controle gradual de velocidade nem mudança de sentido de rotação. Apesar disso, é possível mover o robô para quaisquer direções desejadas.

Ainda sobre o controle de motores DC adotado, são utilizados relés. Embora muito simples para tal aplicação, o uso de relés é adequado para o aprendizado de montagem e programação do robô, podendo ser futuramente substituídos por tiristores e/ou circuitos de controle de rotação e velocidade de giro de motor.

 

 

Circuito esquemático

O circuito esquemático do robô é muito similar ao que vimos no artigo Acionamento de Motor DC com NodeMCU (MIC167) , conforme mostra a figura 1.

 

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

 

 

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

 

No lugar da bateria de 9V, como era feito no circuito do artigo Acionamento de Motor DC com NodeMCU (MIC167) , é altamente recomendável 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 desgaste de baterias. Portanto, a utilização de carregadores portáteis de celular irá 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.

Assim como no caso do artigo Acionamento de Motor DC com NodeMCU (MIC167), este robô possui o acionamento de motores feito à relé. O objetivo deste tipo de acionamento aqui foi a simplificação do circuito. Porém, se você desejar (e tiver domínio sobre), pode substituir o acionamento à relé por controle tiristorizado, o que irá permitir controle de velocidade (com saída PWM adequada do NodeMCU) e sentido de rotação..

AInda, assim como no caso do artigo Acionamento de Motor DC com NodeMCU (MIC167)  , você notará que foram utilizados transistores para acionar o Shield de Relés a partir do NodeMCU. 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 NodeMCU (o NodeMCU 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 um nível dentro do especificado.

 

 

Movimentação do rover

Conforme circuito de acionamento de motores, concluímos que a movimentação do rover será a seguinte:

 

Para frente: acionamento dos dois motores de forma simultânea (figura 2.a)

Para direita: acionamento do motor da esquerda somente (figura 2.b)

Para esquerda: acionamento do motor da direita somente (figura 2.c)

Ré: como este projeto não contempla controle de sentido de rotação dos motores, 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 2, onde é possível vermos a movimentação informada.

 

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

 

 

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: definir como controlar o robô através da Internet (via MQTT). Se você não está familiarizado com MQTT no NodeMCU, recomendo que leia o artigo Monitoramento de Temperatura Ambiente e Umidade Relativa do Ar via Internet.

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:

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

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

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

Caracter 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: caracter ‘1’ para acionado ou caracter ‘0’ para desacionado

Separador: caracterf ‘-’

Estado do motor esquerdo: caracter ‘1’ para acionado ou caracter ‘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 informadas no artigo Monitoramento de Temperatura Ambiente e Umidade Relativa do Ar via Internet http://www.newtoncbraga.com.br/index.php/microcontrolador/143-tecnologia/14409-monitoramento-de-temperatura-ambiente-e-umidade-relativa-do-ar-via-internet.

 

// Programa: código-fonte do robô tipo rover
// 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
//defines:
//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 D0
#define MOTOR_ESQUERDO D1
//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 EstMotDireto = '0'; //estado atual do motor da direita
char EstMotEsquerdo = '0'; //estado atual do motor da esquerda
//Prototypes
void initSerial(void);
void initWiFi(void);
void initMQTT(void);
void connectWiFi(void);
void InitOutputs(void);
void mqtt_callback(char* topic, byte* payload, unsigned int length);
void VerificaConexoesWiFIEMQTT(void);
/* Implementações das funções */
void setup()
{
   //Faz as inicializações necessárias
   InitOutputs();
   initSerial();
   initWiFi();
   initMQTT();
}
//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 initSerial(void)
   {
      Serial.begin(115200);
   }
//Função: inicializa e conecta-se na rede WI-FI desejada
//Parâmetros: nenhum
//Retorno: nenhum
void initWiFi(void)
   {
      delay(10);
      Serial.println("------Conexao WI-FI -----");
      Serial.print("Conectando-se na rede: ");
      Serial.println(SSID_WIFI);
      Serial.println("Aguarde");
      connectWiFi();
   }
//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 initMQTT(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); EstMotDireto = '1'; EstMotEsquerdo = '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); EstMotDireto = '0'; EstMotEsquerdo = '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); EstMotDireto = '1'; EstMotEsquerdo = '0'; } if (msg.equals(CARACTER_PARA_ROVER)) { //para parar, os dois motores são desligados digitalWrite(MOTOR_DIRETO, LOW); digitalWrite(MOTOR_ESQUERDO, LOW); EstMotDireto = '0'; EstMotEsquerdo = '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 connectWiFi(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 VerificaConexoesWiFIEMQTT(void) { if (!MQTT.connected()) reconnectMQTT(); //se não há conexão com o Broker, a conexão é refeita connectWiFi(); //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 EnviaEstadoOutputMQTT(void) { char EstadosMotores[4]; char separador = '-'; EstadosMotores[0] = EstMotDireto; EstadosMotores[1] = separador; EstadosMotores[2] = EstMotEsquerdo; EstadosMotores[3] = '\0'; MQTT.publish(TOPICO_PUB, EstadosMotores); Serial.print("- Estados dos motores enviadosvia MQTT ("); Serial.print(EstadosMotores); 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 InitOutputs(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 VerificaConexoesWiFIEMQTT(); EnviaEstadoOutputMQTT(); 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 ( https://chrome.google.com/webstore/detail/mqttlens/hemojaaeigabkbcookmlgmdigohjobjm?hl=pt-BR ) para enviar e receber informações via MQTT para o NodeMCU. 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)

 

  

Próximos passos

Os próximos passos deste rover agora dependem apenas de sua imaginação! Você pode praticamente acrescentar todos os sensores e atuadores que quiser, e fazer o monitoramento e controle dos mesmos via Internet também!

Quer um desafio? Que tal acrescentar um sensor de temperatura DHT22 no robô e monitorar a temperatura e umidade relativa do ar à distância? Se topar o desafio, segue uma dica de por onde começar: Monitoramento de Temperatura Ambiente e Umidade Relativa do Ar via Internet

 

 

Conclusão

Este artigo mostrou como construir um robô do tipo rover (explorador), utilizando como base artigos aqui do site relacionados ao NodeMCU.

Este robô é capaz de movimentar-se para frente, esquerda, direita e ré (indiretamente, através de giro de 180º ao movimentar-se para esquerda ou direita), sendo controlado por Internet. Logo, este robô pode ser considerado o embrião para qualquer projeto de robô explorador e, com os upgrades pertinentes, pode se tornar um robô para inspeção tubular e exploração de áreas perigosas e/ou inacessíveis a humanos.