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.
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.
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.
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.
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.