arduino - Calculate RPM with a quadrature rotary encoder -
i have written following code calculate rpm of dc motor using quadrature rotary encoder , arduino mega:
int n3 = 7; //n3 sur la l298n motor shield int n4 = 8; //n4 sur la l298n motor shield int enb = 9; //enb sur la l298n motor shield int potpin = a0; //analog pin 0 sur la carte arduino int valeurlu = 0; //valeur lu du potentiomètre int valeur_a_ecrire = 0; //valeur à envoyer au moteur int pin_a_encodeur = 3; int etat_courant_encodeur = 0; int etat_precedant_encodeur = 0; void setup() { attachinterrupt(digitalpintointerrupt(3),updateposition,change); pinmode(n3, output); pinmode(n4, output); pinmode(enb, output); pinmode(a0, input); pinmode(pin_a_encodeur, input); serial.begin(9600); } void loop() { valeurlu = analogread(potpin); valeur_a_ecrire = (255.0/1023.0)*valeurlu; digitalwrite(n4, high); digitalwrite(n3, low); analogwrite(enb, valeur_a_ecrire); etat_courant_encodeur = digitalread(pin_a_encodeur); serial.print(valeur_a_ecrire); serial.print(" "); serial.println(etat_courant_encodeur); }
i'm able read read information encoder sends it's series of ones , zeros (11000111... etc). how can use information calculate rpm of motor? encoder has resolution of 64 counts per revolution. in advance on how solve problem.
since reading pin encoder, 16 impulses per turn.
here's 1 way it...
//... #define sample_delay (1000) // gets 1 reading per second. // adjust delay fit needs #edfine pulses_per_turn (32) // 32 state changes per turn on 1 line, unsigned int pulsecount; bool laststate; unsigned int lasttime; float rpm; // speed in turns/minute, doesn't have floating point. void setup() { // ... pinmode(pin_a_encodeur, input); laststate = digitalread(pin_a_encodeur); } void loop() { bool curstate = digitalread(pin_a_encodeur); if (curstate != laststate) { ++pulsecount; laststate = curstate; } if ((unsigned int)millis() - lasttime >= sample_delay) { rpm = (pulsecount * (60000.f / ((unsigned int)millis() - lasttime))) / pulses_per_turn; pulsecount = 0; lasttime = (unsigned int)millis(); } //... }
the casting of return value of milis() because don't need 32 bits of millis counter count 1000, saves 2 bytes of memory.
by playing sample_delay, notice there trade-off between stability of readings, , sampling frequency. best value sample_delay depend on application, , speed range of motor.
the results depend on else in main loop. loop should not have delay(), opr may miss pulses. if cannot avoid that, should move pulse detection code in isr.
another way it:
//... #define sample_delay (1000) // gets 1 reading per second. // adjust delay fit needs #define pulses_per_turn (32) // 32 state changes per turn on 1 line, volatile unsigned int pulsecount; // note volatile keyword here. unsigned int lasttime; float rpm; // speed in turns/minute, doesn't have floating point. void setup() { // ... pinmode(pin_a_encodeur, input); laststate = digitalread(pin_a_encodeur); attachinterrupt(digitalpintointerrupt(pin_a_encodeur), onpulse, change); } void loop() { if ((unsigned int)millis() - lasttime >= sample_delay) { unsigned int pulses; nointerrupts(); pulses = pulsecount; // atmega 8 bits, must disable interruts pulsecount = 0; // read/write 16 bit values accessed isr interrupts(); // re-enable interrupts. // 60000 milliseconds in 1 minute rpms. rpm = (pulses * (60000.f / ((unsigned int)millis() - lasttime))) / pulses_per_turn; lasttime = (unsigned int)millis(); } //... } void onpulse() { ++pulsecount; }
note digital sampling lead variations in readings. remember if decide store rpms in integer, have use unsigned long type
, including millis per minute constant 60000ul
, avoid overflows.
note not pins created equal. some pins can linked interrupt. see arduino doc at: https://www.arduino.cc/en/reference/attachinterrupt
Comments
Post a Comment