Go Down

Topic: Ler velocidade angular encoder (Read 2047 times) previous topic - next topic

matheusmachado

Olá,
Estou querendo faze um controle PID de um robo daqueles do kit de robótica para arduino.
Entretanto, estou querendo levantar o modelo matemático do motor.
Para isto, comprei um encoder óptico com LM393 para ler o número de rotações do disco perfurado que veio no kit de robótica.
Porém estou com dúvida qual a frequência de amostragem e como programar para calcular a velocidade angular do motor. Aqui neste site (http://www.arduinoecia.com.br/2016/02/sensor-de-velocidade-lm393-arduino.html) tem, porém a frequência de amostragem é muito alta, 1s para ler e calcular a velocidade angular. gostaria de ajuda.
Matheus

bubulindo

Uma maneira de fazer isto seria utilizar um timer como contador.

http://www.electroschematics.com/9846/avr-8-16-bit-timers-counters/
http://www.atmel.com/Images/Atmel-2505-Setup-and-Use-of-AVR-Timers_ApplicationNote_AVR130.pdf
http://www.avrfreaks.net/forum/16-bit-timer-3-external-pulse-counter

Depois de teres isto feito, podes reportar a contagem de x em x tempo, permitindo-te calcular a velocidade do motor. Outra coisa que terás de fazer é configurar o programa para interromper e contar o número de interrupções para teres uma ideia correcta do número de pulsos total.

Os sites que coloquei não são especificos para este problema, mas tem informação que chegue para perceber o que disse.

Outra maneira é utilizares uma interrupção num pino e programares uma interrupção dum timer para guardar/enviar os dados via porta série.

This... is a hobby.

matheusmachado

Aqui está o código que encontrei e adaptei para meu robo. Gostaria de saber como adaptar o código para ler a velocidade angular num período pequeno e com uma grande quantidade de dados, para levantar a curva e levantar a função de transferencia do motor.

int pino_D0 = 2;
int pino_D02 = 3;
int rpm;
int rpm2;
volatile byte pulsos;
volatile byte pulsos2;
unsigned long timeold;
unsigned long timeold2;
float tempo;
float radianosmotor1;
float radianosmotor2;

//Altere o numero abaixo de acordo com o seu disco encoder
unsigned int pulsos_por_volta = 20;

void setup()
{
  Serial.begin(9600);
  //Pino do sensor como entrada
  pinMode(pino_D0, INPUT);//Interrupcao 0 - pino digital 2
  pinMode(pino_D02, INPUT);//Interrupção 1 - pino digital 3
  //Aciona o contador a cada pulso
  attachInterrupt(0, contador, FALLING);
  attachInterrupt(1, contador2, FALLING);
  pulsos = 0;
  rpm = 0;
  timeold = 0;
  pulsos2 = 0;
  rpm2 = 0;
  timeold2 = 0;
}

void loop()
{
  tempo = millis();
  //Atualiza contador a cada segundo
  if (tempo - timeold >= 1000)
  {
    Serial.print("Pulsos");
    Serial.print("  ");
    Serial.print(pulsos);
    //Desabilita interrupcao durante o calculo
    detachInterrupt(0);
    rpm = (1000 / pulsos_por_volta ) / (tempo - timeold) *pulsos* 2*3,14;
    timeold = tempo;
    pulsos = 0;

    //Mostra o valor de RPM no serial monitor
    Serial.print("  RPM Motor 1 = ");
    Serial.print(rpm, DEC);
    Serial.print("  ");
    //Habilita interrupcao
    attachInterrupt(0, contador, FALLING);
  }
   if (tempo - timeold2 >= 1000)
  {
    Serial.print("Pulsos");
    Serial.print("  ");
    Serial.print(pulsos2);
    //Desabilita interrupcao durante o calculo
    detachInterrupt(1);
    rpm2 = (1000 / pulsos_por_volta ) / (tempo - timeold2) *pulsos2* 2*3,14;
    timeold2 = millis();
    pulsos2 = 0;

    //Mostra o valor de RPM no serial monitor
    Serial.print("  ");
    Serial.print("RPM Motor 2= ");
    Serial.print(rpm2, DEC);
    //Habilita interrupcao
    attachInterrupt(1, contador2, FALLING);
    Serial.print("  ");
  radianosmotor1=rpm;
  Serial.print("  Radianos Motor 1 ");
  Serial.println(radianosmotor1);
  Serial.print("  ");
  radianosmotor2=(rpm2);
  Serial.print("Radianos Motor 2 ");
  Serial.println(radianosmotor2);
  }

}

void contador()
{
  //Incrementa contador
  pulsos++;
}
void contador2()
{
  pulsos2++;
}





bubulindo

O problema desse código é que tem um erro na temporização... A medição nunca é feita precisamente de segundo a segundo mas acima de um segundo. Isso é realizado aqui:

Code: [Select]

  if (tempo - timeold2 >= 1000)


Se trocares o 1000 por 500 ficas com uma amostragem maior... no entanto, não é preciso porque a medição é sempre feita quando o tempo é maior ou igual e diria que em 99.9% das vezes a condição é maior e não igual. Logo pode dar para fazeres um modelo, mas não vai ser preciso.

No entanto, nem tudo é mau... este código conta pulsos com interrupções (como referi no meu post), logo falta agora configurares um temporizador para interromper o programa de x em x milisegundos (a tua frequência de amostragem) e enviar os dados dos pulsos para a porta série.
Pesquisa por uma biblioteca chamada TimerOne... creio que é o que pretendes.
This... is a hobby.

Go Up