Mais um projeto de mecatrônica
aqui hoje: uma câmera robô controlada com ESP32. Vou te apresentar um código
multi task de controle físico de motor de passo com posicionamento em tempo
real e mostrar o seu funcionamento em um Slider.
Aqui neste vídeo quero te
mostrar como você move a câmera e como é o software que vai no ESP32. Portanto,
não falo da parte mecânica, mas deixo o projeto logo abaixo para você fazer o
download.
Demonstração
Recursos usados para construção da eletrônica
·
1 Esp32 LoRa com display OLED
·
1 Drivers DRV8825
·
1 motores de passo Nema 17
·
2 chaves de fim de curso ópticas
·
3 botões push
·
3 resistores 10k ohm
·
Jumpers para conexão
·
Protoboard
·
Fonte 12V
Montagem da eletrônica
Código
Includes e variáveis
#include <Arduino.h> //Importa as funções do arduino #include <Wire.h> //Necessário apenas para o Arduino 1.6.5 e posterior #include <SSD1306.h> //O mesmo que #include "SSD1306Wire.h" #include <SPI.h> //Lib de comunicação SPI //OLED_SDA -- GPIO4 //OLED_SCL -- GPIO15 //OLED_RST -- GPIO16 #define SDA 4 #define SCL 15 #define RST 16 //Instanciando e ajustando os pinos do objeto "display" SSD1306 display( 0x3c, SDA, SCL,RST); const int ENA = 23; //Pino "enable" - DRV8825 const int DIR = 22; //Pino "direction" - DRV8825 const int STP = 17; //Pino "step" - DRV8825 const int EMAX = 37; //Pino do fim de curso máximo const int EMIN = 36; //Pino do fim de curso mínimo double SPM = 400.0; //Passo por milimetro bool LVL = LOW; //Nível de ativacao da chave (alto ou baixo) int ACC; //Aceleração double MIN_SPEED; //Velocidade mínima double MAX_SPEED; //Velocidade máxima static double Absolute = 0; //variável que guarda a posição do motor const int BtBackPin = 12; //Pino do botão trás const int BtHomePin = 33; //Pino do botão home const int BtFowardPin = 13; //Pino do botão frente //Variáveis que guardam a leitura dos botões para usar em ambas as tasks int ButtonBack=0; int ButtonHome=0; int ButtonFoward = 0;
Função Setup e loop
void setup(){ Serial.begin(115200);//Apenas para debug pinMode(ENA, OUTPUT); pinMode(DIR, OUTPUT); pinMode(STP, OUTPUT); pinMode(EMAX, INPUT); pinMode(EMIN, INPUT); pinMode(BtBackPin,INPUT); pinMode(BtHomePin,INPUT); pinMode(BtFowardPin,INPUT); //Configuração de movimento motionConfig(200, 50, 5); //Criamos a task que gerencia o display OLED e os botões físicos xTaskCreatePinnedToCore(Task_display, "Task_display", 10000, NULL, 1, NULL, 0); Serial.println("task display - ONLINE"); //Criamos a task responsável pelo movimento do motor xTaskCreatePinnedToCore(Task_motion, "Task_motion", 10000, NULL, 2, NULL, 1); Serial.println("task motion - ONLINE"); } void loop(){ //loop vazio }
Funções básicas de movimento (Importado da biblioteca de motor de passo)
//Configura aceleração, velocidade máxima e velocidade mínima void motionConfig(double acceleration, double maxSpeed, double minSpeed) { ACC = acceleration * SPM; MAX_SPEED = maxSpeed * SPM; if (minSpeed > maxSpeed) MIN_SPEED = maxSpeed * SPM; else MIN_SPEED = minSpeed * SPM; } //Le as chaves de fim de curso bool eRead(int pin) { if (LVL && digitalRead(pin)) { return true; } if (!LVL && !digitalRead(pin)) { return true; } return false; } //Verifica o movimento do motor bool canGo(bool direction) { if (direction && eRead(EMAX)) return false; if (!direction && eRead(EMIN)) return false; return true; } //Gera o pulso do motor void motorMove(double period, bool direction) { digitalWrite(DIR, direction); if (canGo(direction)) { digitalWrite(STP, HIGH); delayMicroseconds(int(period) / 2); digitalWrite(STP, LOW); delayMicroseconds(int(period) / 2); } else { delayMicroseconds(period); } } //Movimenta o motor em modo relativo void motorMoveTo(double distance, bool direction) { double MIN_SPEED_PERIOD = 1.0 / MIN_SPEED; double MAX_SPEED_PERIOD = 1.0 / MAX_SPEED; double ACC_SPEED_PERIOD = MIN_SPEED_PERIOD; unsigned long PATH_STEPS = distance * SPM; long STEPS_TO_STOP = PATH_STEPS / 2; double MAX_SPEED_REACHED; bool flag = true; for (long int i = 0; i < PATH_STEPS; i++) { if (i < (PATH_STEPS / 2)) { if (ACC_SPEED_PERIOD > MAX_SPEED_PERIOD) { ACC_SPEED_PERIOD = 1.0 / sqrt((MIN_SPEED * MIN_SPEED) + (2.0 * ACC * i)); motorMove(1000000 * ACC_SPEED_PERIOD, direction); MAX_SPEED_REACHED = (1.0 / ACC_SPEED_PERIOD); } else { if (flag) { STEPS_TO_STOP = i; MAX_SPEED_REACHED = MAX_SPEED; flag = false; } motorMove(1000000 * MAX_SPEED_PERIOD, direction); } } else{ if (i > PATH_STEPS - STEPS_TO_STOP) { ACC_SPEED_PERIOD = 1.0 / sqrt((MAX_SPEED_REACHED * MAX_SPEED_REACHED) + 2.0 * (ACC * -1.0) * (i - (PATH_STEPS - STEPS_TO_STOP))); motorMove(1000000 * ACC_SPEED_PERIOD, direction); } else { motorMove(1000000 * MAX_SPEED_PERIOD, direction); } } } }
Novas funções de movimento
//Movimenta o motor em modo absoluto void MoveAbsolute(double coordinate){ double position; if(coordinate!=Absolute){ position = coordinate-Absolute; if(position<0){ motorMoveTo((position*(-1.0)),LOW); } else{ motorMoveTo(position,HIGH); } Absolute=Absolute+position; } } //Zera a posição do motor void HomeAxis(){ double SPEED_PERIOD = 1000000*(1.0 / (MAX_SPEED/2));//Metade da velocidade máxima while(digitalRead(EMIN)){ motorMove(SPEED_PERIOD,LOW); } Absolute=0; delay(250); MoveAbsolute(5); delay(250); while(digitalRead(EMIN)){ motorMove(SPEED_PERIOD*3,LOW); // 1/3 da velocidade máxima (período 3 vezes maior) } Absolute=0; }
Criação das Tasks
//Task que gerencia o display OLED e os botões físicos void Task_display(void *p){ //Inicia o display display.init(); //Vira a tela verticalmente display.flipScreenVertically(); //ajusta o alinhamento para a esquerda display.setTextAlignment(TEXT_ALIGN_LEFT); //ajusta a fonte para Arial 16 display.setFont(ArialMT_Plain_16); //Liga o display display.displayOn(); //Limpa o display display.clear(); TickType_t Taskdelay = 1 / portTICK_PERIOD_MS; while(true) { //Lê os botões de movimento ButtonBack = digitalRead(BtBackPin); ButtonHome = digitalRead(BtHomePin); ButtonFoward = digitalRead(BtFowardPin); //escreve no display a posião atual do motor display.clear(); display.drawString(0,0,"Posição:"); display.drawString(0, 28, String(Absolute,4)); display.drawString(67, 28, "mm"); display.display(); //delay que reinicia o WatchDog vTaskDelay(Taskdelay); } } //Task responsável pelo movimento do motor através dos botões void Task_motion(void *p){ while(true) { if(ButtonBack){ motorMove(50,LOW); if(canGo(LOW)){ Absolute = Absolute - (1.0/400.0); } } else{ if(ButtonFoward){ motorMove(50,HIGH); if(canGo(HIGH)){ Absolute = Absolute + (1.0/400.0); } } else{ if(ButtonHome){ HomeAxis(); } } } } }
5 Comentários
fascinante prataforma de suporte que vc realiza de boa vontade generosa parabens Fernando k eu precisava muito desse suporte Obrigado Fernando K
ResponderExcluirfascinante prataforma de suporte que vc realiza de boa vontade generosa parabens Fernando k eu precisava muito desse suporte Obrigado Fernando K
ResponderExcluirCaraka Fernandao!! Estava começando a pensar em montar um... e como que se caísse do céu... Maravilha!!
ResponderExcluirFui na Campus Party BR12, esperava ter lhe encontrado lá... encontrei o pessoal do Arduino Brasil, Brincando com Ideias... até o mito Newton Braga esteve lá... vlw pelos excelentes projetos... Uma hora ensina a fazer uma losa dessa ai. kkk!
Alguém tem o projeto mecânico da câmera robô, tipo slider que o professor montou?
ResponderExcluirOlá. Parabéns pelo seu trabalho. Onde consigo ver a parte mecanica?
ResponderExcluir