Arduinos & Breaduinos
Tachometer
Mesuring RPM's with arduino
The basic is to obtain a signal that indicates the rotation of an axle, shaft, wheel or any part that has a periodic movement.
We measure the time taken for a given point to reach a mark again, using some kind of sensor that emits a signal on a fixed point of the part.
On this case we will use a stationaryt hall effect sensor and a magnet atached to the moving part.
We store the time of signal occourence (t and ot) and obtain the travel time by the diference of the two last time meausres.
dt=t-ot
Now we have the movement period. Having the time in milliseconds, we can have the RPMs by:
rpm=60000/(t-ot)
In some cases the original signal emits several pulses by rotation, if so we just have to divide that value by the number of pulses.
If we want a displacement speed, a calibration must be done to map the RPM to distance, provided that no variable element is between the rotation part and the wheel.
There are several ways of obtaining the rotaion signal, anything that produces digital pulses per rotation will work, eventually requiring a calibrartion if not supplying 1 pulse per rotation.
We have used a hall effect sensor A3144 that worked very well just wired to the pin 8 of the arduino. However you can add some optional comonents to inprove signal quality and noise filter.
you can use a 2.2k resistor instead.
On this code we are using an I2C LCD
There is also a much simpler code using the PCINT library and printing to serial monitor here.
#include <Wire.h> // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
/* Pin to interrupt map:
* D0-D7 = PCINT 16-23 = PCIE2 = pcmsk2
* D8-D13 = PCINT 0-5 = PCIE0 = pcmsk0
* A0-A5 (D14-D19) = PCINT 8-13 = PCIE1 = pcmsk1
*/
#define interrupt_pin2 8 //Define Analog Pin (analog pins are 16-21)
volatile unsigned long t=0;
volatile unsigned long ot=0;
ISR(PCINT0_vect) {
if (PINB & 1) {
ot=t;
t=millis();
}
}
//actualizar o visor (aqui calibrado para um maximo de 3000 rpm, basta mudar o valor)
#define max_rpm 3000
void printVu(int r) {
int i=map(r, 0, max_rpm, 0, 20);
for(int n=0;n<20;n++) {
lcd.print((char)(n<i?255:' '));
}
}
void setup() {
Serial.begin(115200);
lcd.begin(20,4); // initialize the lcd for 20 chars 4 lines, turn on backlight
lcd.backlight(); // finish with backlight on
lcd.print("RPM with PCINT");
MCUCR = (1<<ISC01) | (1<<ISC00);
PCICR |= (1<<PCIE0);
PCMSK0 |= (1<<PCINT0);
pinMode(interrupt_pin2, INPUT); //Make pin an input
digitalWrite(interrupt_pin2,HIGH); //Enable pullup resistor on Analog Pin
interrupts();
}
unsigned int rpm=0;
void loop() {
//lcd.setCursor(0,3);lcd.print(millis()-t);lcd.print(" ");
if((millis()-t)>300) rpm=0;
else if (t!=ot) {
rpm=60000.0/(float)(t-ot);
}
Serial.print(rpm);Serial.print(" ");Serial.println(t-ot);
lcd.setCursor(0,1);
lcd.print(rpm);
lcd.print(" rpms ");
lcd.setCursor(0,2);
printVu(rpm);
}