Urgent Help Needed: DC Motor Speed (in RPM) Control Using Arduino

Hello! I am struggling to accurately measure the speed of the DC motor in revolutions per minute (RPM) and integrate this functionality into my Arduino-based control system. This is a critical aspect of my project, and I believe your knowledge and experience in this field could greatly assist me in overcoming this challenge.

Could you please provide detailed instructions or code snippets on how to implement RPM measurement in speed for a DC motor using Arduino? Any insights, tips, or resources you can share would be immensely valuable to me at this stage. Thanks!

What encoder is attached to the motor? How many counts per revolution?

we don't know yet the encoder that will be using.

this was my previous work


as you can see there's a feedback for the speed and we use potentio. however, we want to integrate the speed in RPM

Your own project, or a school/college assignment?

What is the motor specification and what if anything does it operate? Could it have a slotted disc, making a photo-diode or IR sensor possible? Or, if it’s large, could a small magnet be attached to allow a Hall Effect sensor? Etc… More detail will encourage more suggestions.

And a Google search for ‘arduino DC motor speed measurement’ gave several possibly useful start points.

Oh, and if you are actually using PWM to drive the motor with Arduino yourself, then you might not even need a sensor

1 Like

The posted circuit shows no encoder. Cannot add code to calculate RPM and the other values till you can get time per revolution or revoution per unit time.

Add the encoder circuit t the schematic.

1 Like

can u suggest what type of encoder?

As @Terrypin suggested, more detail will make answering the question easier.

What exact mototrs do you have? Post data sheets. Often encoders can be added to existing motors.

What is the physical setup of your projesct? It can be easy to add a magnetic or optical switch so that revolutions can be counnted.

1 Like

There is a part, I think it's called motor encoder.
Looks like this

The chosen encoder is going to be a function of the motor and what will be or not be practical to work with the motor. What is the motor shaft diameter and configuration? What is the expected motor RPM range? The speed (RPM) sensor is a matter of choice based on a few things I have mentioned. A simple Google of "Arduino Tachometer" or "Arduino Motor Speed Sensor" should yield plenty of results depending on your speed sensor choice based on your motor and project in general. There are Hall Effect sensors and Optical sensors just to name a few and until you choose a sensor you can forget about code.

Just as a side note the L298 motor controller is not a good choice with so many newer and better motor controllers out there. This is especially true of 5.0 volt motors since the L298 will have loss in what the motor actually gets.

Ron

1 Like

Hi! I am currently working on a project involving the control of a DC motor using an Arduino, with the added functionality of measuring the motor's RPM through an encoder and displaying this feedback on an LCD. The system is designed to include start and stop functionalities.

I've encountered an issue with the code that I'm struggling to resolve. The main problem appears when trying to integrate the RPM readings from the motor encoder with the LCD display updates. The motor either does not respond to the start/stop commands or the RPM readings displayed are inaccurate or erratic.

Could you provide some guidance or suggest modifications to my approach? Any example codes, debugging tips, or resource recommendations would be highly appreciated

#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

// Define switch pins
#define potentiometer  A0  //10k Variable Resistor
#define START  A1 // Clockwise Button
#define STOP A2 // Stop Button
#define greenLEDPin A3 // Green LED pin
#define redLEDPin A4 // Red LED pin

const int motorSpeedPin = 4; // PWM pin for motor speed control (L293D Enable)
int motorSpeed = 0; // Variable to store motor speed

// Define motor control pins
const int hallPin=8;
const unsigned long sampleTime=1000;
const int maxRPM = 10000;
const int M1_Ena  = 11; // Enable1 L298 for PWM
const int M1_in1 = 10; // In1  L298 for Clockwise
const int M1_in2 = 9;  // In2  L298 for Anticlockwise

int volume_pin = A0;
int read_ADC;

int pwm_pin = 11;
int duty_cycle;
int duty_cycle_lcd;

void setup(){
   Serial.begin(9600);// initialize serial communication at 9600 bits per second:

   pinMode(potentiometer, INPUT);
   pinMode(START, INPUT_PULLUP);
   pinMode(STOP, INPUT_PULLUP);

   // Motor control pins as outputs
   pinMode(hallPin,INPUT);
   pinMode(volume_pin, INPUT);
   pinMode(pwm_pin, OUTPUT);
   pinMode(M1_Ena, OUTPUT);
   pinMode(M1_in1, OUTPUT);
   pinMode(M1_in2, OUTPUT);

   lcd.begin(20,4);  
   lcd.print("Motor Speed:"); // Display text on LCD
   pinMode(motorSpeedPin, OUTPUT); // Set PWM pin as output
}

void loop(){ 
int rpm=getRPM();

   read_ADC = analogRead(potentiometer);
   duty_cycle = map(read_ADC, 0, 1023, 0, 255);  
   duty_cycle_lcd = map(read_ADC, 0, 1023, 0, 100); 
   motorSpeed = map(read_ADC, 0, 1023, 0, 255); // Read potentiometer value and map it to motor speed (0-255)

   analogWrite(M1_Ena, duty_cycle);
   analogWrite(motorSpeedPin, motorSpeed); // Control motor speed using PWM

lcd.setCursor(0,0);
lcd.print("Duty Cycle: ");
lcd.print(duty_cycle_lcd); 
lcd.print("%  ");

lcd.setCursor(0,1);
lcd.print("Direction:");
if(set==0){ 
   lcd.print("Stop      ");
   digitalWrite(M1_in1, LOW);  
   digitalWrite(M1_in2, LOW);
   digitalWrite(greenLEDPin, LOW); // Turn off green LED
   digitalWrite(redLEDPin, HIGH); // Turn on red LED
 
} else if(set==1){ 
   lcd.print("Clockwise   ");
   digitalWrite(M1_in1, HIGH);  
   digitalWrite(M1_in2, LOW);
   digitalWrite(greenLEDPin, HIGH); // Turn on green LED
   digitalWrite(redLEDPin, LOW); // Turn off red LED
}

    lcd.setCursor(0, 2); // Set cursor position on LCD
   lcd.print("Speed:");
   lcd.print(motorSpeed); // Display motor speed on LCD
   delay(50);
}

int getRPM(){
  // sample for sampleTime in millisecs
int kount=0;
boolean kflag=LOW;
unsigned long currentTime=0;
unsigned long startTime=millis();
while (currentTime<=sampleTime){
if(digitalRead(hallPin)==HIGH){kflag=HIGH;}
if(digitalRead(hallPin)==LOW && kflag==HIGH){
kount++;
kflag=LOW;
}
currentTime=millis()-startTime;
}
int kount2rpm = int(30000./float(sampleTime))*kount;
return kount2rpm;
}

So, finally you tell that the encoder has a hall sensor.
Rpm of motor is still not known...
My guess is that you will miss counts when you make this non blocking (unless the motor goes really slow...
You should use an interrupt here...

how can I use an interrupt? can you give me a specific component to use?

I am not an expert on interrupts.
It is not a thing, it is a special sort of code.
Look for examples or library code
Google: hall sensor rpm interrupt arduino

And you sjould find things to start from.

Its been asked before - we NEED to know what motor you are using,

This is how you provide that information - with a LINK
https://cpc.farnell.com/pro-elec/pel00883/dc-motor-high-torque-6-12v/dp/MC02742

and what the motor is driving and how it is connected physically. With a sketch, a photo ..

if you need urgent help you need to give us that information.

I think you are not really in a hurry, are you?

I am since it is mmy project and I'am a newbie for this. sorry...

In that case: where is the data on the motor?
If you haven't any: is there a number on the motor? If not: post a picture of the motor...

1 Like

this is base on the schematic, its a motor encoder

So what is it like in the real world?

1 Like

Hi guys, please bear with me 'coz I'm so in newbie in this kind of world. So, I have implemented forward and reverse functionalities in my motor control system, where the direction of rotation is controlled by the PWM duty cycle. However, I am experiencing a peculiar problem where the RPM values seem to be behaving in an unexpected manner.

Specifically, when I adjust the PWM duty cycle to a higher value, I notice that the RPM drops to a lower value, and conversely, when I adjust it to a lower value, the RPM increases. This behavior is contrary to what I would expect, as higher PWM duty cycles should typically result in higher motor speeds and consequently higher RPM readings.

I am unsure whether this issue stems from a problem in the accurate simulation on proteus, or the code logic or if there might be an issue with the pins or connections in my setup. Please help me

example pics when simulating forward direction


#include <LiquidCrystal.h>

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

#define potentiometer  A0  // 10k Variable Resistor
#define buttonForward A1 // Forward Button
#define buttonStop A2 // Stop Button
#define buttonReverse A3 // Reverse Button

#define greenLEDPin A4 // Green LED pin
#define redLEDPin A5 // Red LED pin
#define blueLEDPin 0 // Blue LED pin

#define M1_Ena 11 // Enable1 L298 for PWM
#define M1_in1 10 // In1  L298 for Clockwise
#define M1_in2 9  // In2  L298 for Anticlockwise

const int motorSpeedPin = 4; // PWM pin for motor speed control (L293D Enable)
int motorSpeed = 0; // Variable to store motor speed

int read_ADC = 0;
int duty_cycle;
int duty_cycle_lcd;
int set = 0; // Variable to store motor direction (0: Stop, 1: Forward, 2: Reverse)  

const int maxRPM = 400; // Maximum RPM of the motor
const int pulsesPerRevolution = 24; // Number of pulses per revolution of the motor encoder

unsigned long lastMillis = 0;
volatile unsigned long pulseCount = 0;
float rpm = 0;
const int TimeInterval = 1000; // Time interval in milliseconds for RPM calculation

void setup() {
  Serial.begin(9600);
  pinMode(potentiometer, INPUT);
  pinMode(buttonForward, INPUT_PULLUP);
  pinMode(buttonStop, INPUT_PULLUP);
  pinMode(buttonReverse, INPUT_PULLUP);

  // Motor control pins as outputs
  pinMode(M1_Ena, OUTPUT);
  pinMode(M1_in1, OUTPUT);
  pinMode(M1_in2, OUTPUT);

  lcd.begin(20, 4);
  lcd.print("Motor Speed:"); // Display text on LCD
  pinMode(motorSpeedPin, OUTPUT); // Set PWM pin as output

  attachInterrupt(digitalPinToInterrupt(3), countPulses, RISING);
}

void loop() {
  // Read potentiometer value and map it to motor speed (0-255)
  read_ADC = analogRead(potentiometer);
  duty_cycle = map(read_ADC, 0, 1023, 0, 255);
  duty_cycle_lcd = map(read_ADC, 0, 1023, 0, 100);
  motorSpeed = map(read_ADC, 0, 1023, 0, 255);

  // Control motor speed using PWM
  analogWrite(M1_Ena, duty_cycle);
  analogWrite(motorSpeedPin, motorSpeed); // Control motor speed using PWM

  // Update LCD with duty cycle
  lcd.setCursor(0, 0);
  lcd.print("Duty Cycle: ");
  lcd.print(duty_cycle_lcd);
  lcd.print("%  ");

  // Check button inputs for motor direction control
  if (digitalRead(buttonForward) == LOW) {
    setDirection(1); // Forward
  } else if (digitalRead(buttonStop) == LOW) {
    setDirection(0); // Stop
  } else if (digitalRead(buttonReverse) == LOW) {
    setDirection(2); // Reverse
  }

  // Display motor direction and speed on LCD
  displayDirection();
  lcd.setCursor(0, 2);
  lcd.print("Speed:");
  lcd.print(motorSpeed);

  // Calculate RPM every specified time interval
  calculateRPM();

  delay(50); // Delay for stability
}

void setDirection(int direction) {
  set = direction;
  switch (set) {
    case 0: // Stop
      analogWrite(M1_Ena, 0); // Turn off motor
      break;
    case 1: // Forward
      digitalWrite(M1_in1, HIGH); // Set motor direction to clockwise
      digitalWrite(M1_in2, LOW);
      break;
    case 2: // Reverse
      digitalWrite(M1_in1, LOW); // Set motor direction to anticlockwise
      digitalWrite(M1_in2, HIGH);
      break;
  }
}

void displayDirection() {
  lcd.setCursor(0, 1);
  lcd.print("Direction:");
  switch (set) {
    case 0:
      lcd.print("Stop      ");
      digitalWrite(greenLEDPin, LOW); // Turn off green LED
      digitalWrite(redLEDPin, HIGH); // Turn on red LED
      digitalWrite(blueLEDPin, LOW); // Turn off blue LED
      break;
    case 1:
      lcd.print("Forward   ");
      digitalWrite(greenLEDPin, HIGH); // Turn on green LED
      digitalWrite(redLEDPin, LOW); // Turn off red LED
      digitalWrite(blueLEDPin, LOW); // Turn off blue LED
      break;
    case 2:
      lcd.print("Reverse   ");
      digitalWrite(greenLEDPin, LOW); // Turn off green LED
      digitalWrite(redLEDPin, LOW); // Turn off red LED
      digitalWrite(blueLEDPin, HIGH); // Turn on blue LED
      break;
  }
}

void calculateRPM() {
  unsigned long currentMillis = millis();
  if (currentMillis - lastMillis >= TimeInterval) {
    rpm = (pulseCount * 60.0 * 1000.0) / (pulsesPerRevolution * TimeInterval); // Calculate RPM
    pulseCount = 0;
    lastMillis = currentMillis;

    lcd.setCursor(0, 3);
    lcd.print("RPM: ");
    lcd.print(rpm);
  }
}

void countPulses() {
  pulseCount++; // Increment pulse count for RPM calculation
}