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