I am trying to make a project that should determine the rpm of a motor. To do that I am using a 200 rpm geared motor, proximity sensor and arduino clone. Suggest me a code to achieve this. I am currently using this code:-
// Pin connected to the sensor output
#include "U8glib.h"
U8GLIB_SH1106_128X64 oled(U8G_I2C_OPT_NONE);
const int sensorPin = 2;
// Variables
volatile int rotationCount = 0;
volatile bool rotationDetected = false;
unsigned long prevTime = 0;
float rpm = 0.0;
void setup() {
// Initialize serial communication
Serial.begin(9600);
// Attach an interrupt to the sensor pin
attachInterrupt(digitalPinToInterrupt(sensorPin), countRotation, FALLING);
}
void loop() {
oled.firstPage();
do {
page1();
} while (oled.nextPage() );
if (rotationDetected) {
unsigned long currTime = micros();
unsigned long timeDiff = currTime - prevTime;
// Calculate RPM
rpm = 60000000.0 / timeDiff; // Convert to RPM
rotationDetected = false;
prevTime = currTime;
}
}
void countRotation() {
// Increment the rotation count
rotationCount++;
rotationDetected = true;
}
void page1(void) {
oled.setFont(u8g_font_profont12);
oled.setPrintPos(0, 10);
oled.print("No of rotation : " );
oled.setPrintPos(0, 25);
oled.print(rotationCount);
oled.setPrintPos(0, 40);
oled.print("RPM of DC Motor :");
oled.print(rpm);
}
But it has some error, it increases the rpm value as I increase the speed of motor but shows only some fixed values rather than the correct value.
Find the attached picture and link of the working video... Notice the rotation count is working fine but the rpm value is changing if fixed values. I changed the speed of the motor by gently adjusting the knob of pwm speed controller.
#include "U8glib.h"
U8GLIB_SH1106_128X64 oled(U8G_I2C_OPT_NONE);
const int sensorPin = 2;
// Variables
volatile int rotationCount = 0;
volatile bool rotationDetected = false;
unsigned long prevTime = 0;
float rpm = 0.0;
float avgRpm = 0.0;
float avgrpm = 0.0;
int count = 0;
void setup() {
// Initialize serial communication
Serial.begin(9600);
// Attach an interrupt to the sensor pin
attachInterrupt(digitalPinToInterrupt(sensorPin), countRotation, FALLING);
}
void loop() {
oled.firstPage();
do {
page1();
} while (oled.nextPage() );
if (rotationDetected) {
unsigned long currTime = micros();
unsigned long timeDiff = currTime - prevTime;
// Calculate RPM
rpm = 60000000.0 / timeDiff; // Convert to RPM
rotationDetected = false;
prevTime = currTime;
if (count < 10) {
avgRpm += rpm;
count++;
} else {
avgrpm = avgRpm/10;
Serial.print("Average RPM: ");
Serial.println(avgrpm);
count = 0;
avgRpm = 0.0;
}
}
}
void countRotation() {
// Increment the rotation count
rotationCount++;
rotationDetected = true;
}
void page1(void) {
oled.setFont(u8g_font_profont12);
oled.setPrintPos(0, 10);
oled.print("No of rotation : " );
oled.setPrintPos(0, 25);
oled.print(rotationCount);
oled.setPrintPos(0, 40);
oled.print("RPM of DC Motor :");
oled.setPrintPos(0, 55);
oled.print(avgrpm);
}
It does work to a certain limit, I could get rpm readings in much greater resolution compared to the one obtained using previous code. But I feel like it could still be optimized. Forum, any other suggestions?
You need the best estimate of the actual rpm. Now the RPM will not change instantaneously, so you can improve your estimate based on the history of the readings.
To do this you can use a simple digital filter. An exponential moving average filter is described here
new EMA =F * new reading + (1 -F) * last EMA
where F is a value normally between 0.1 and 0.3