Plot Voltage vs Speed using Encoder DC Motor with Arduino

I am using an N20B DC motor with an encoder to measure speed, an L298N motor driver for control, and a potentiometer to adjust the motor speed.

I want to display the voltage and speed curves on the Serial Plotter. The speed will change by adjusting the voltage using a potentiometer, demonstrating a first-order system response. From these curves, I aim to derive the transfer function, such as Kτs+1\frac{K}{\tau s + 1}τs+1K​.

Additionally, I would like to know how to determine in the code the motor's encoder pulses per revolution (e.g., encoderPPR = 12) and set the measurement interval (e.g., interval = 100 ms).
I used the code below,

#define ENA 5   // PWM pin for motor speed control
#define IN1 9   // Motor driver IN1
#define IN2 10  // Motor driver IN2
#define ENC_A 2 // Encoder signal A (interrupt pin)
#define ENC_B 3 // Encoder signal B
#define POT A0  // Potentiometer for adjusting voltage

volatile long encoderCount = 0; // Encoder pulse count
float rpm = 0;                 // Motor speed in RPM
unsigned long lastTime = 0;

const int encoderPPR = 12;      // Pulses per revolution of the encoder
const int gearRatio = 150;       // Gear ratio of the motor
const int effectivePPR = encoderPPR * gearRatio; // Effective PPR for the output shaft
const int interval = 100;        // Time interval for RPM calculation (ms)

// Interrupt service routine for encoder signal
void readEncoder() {
  if (digitalRead(ENC_B) == HIGH) {
    encoderCount++; // Increment count for forward rotation
  } else {
    encoderCount--; // Decrement count for reverse rotation
  }
}

void setup() {
  // Motor driver pins
  pinMode(ENA, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);

  // Encoder pins
  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);

  // Attach interrupt for encoder signal
  attachInterrupt(digitalPinToInterrupt(ENC_B), readEncoder, RISING);

  // Initialize serial communication
  Serial.begin(9600); // For Arduino Serial Plotter
}

void loop() {
  // Read potentiometer value (0-1023)
  int potValue = analogRead(POT);

  // Map potentiometer value to PWM (0-255) and calculate input voltage
  int pwmValue = map(potValue, 0, 1023, 0, 255);
  float inputVoltage = (potValue * 6.0) / 1023.0; // Convert to voltage (assuming 6V reference)

  // Apply PWM to motor driver
  analogWrite(ENA, pwmValue);
  digitalWrite(IN1, HIGH); // Motor forward direction (Encoder rotate clockwise)
  digitalWrite(IN2, LOW);

  // Calculate RPM
  unsigned long currentTime = millis();
  if (currentTime - lastTime >= interval) { // Every `interval` ms
    rpm = (encoderCount / (float)effectivePPR) * (60000.0 / interval); // Calculate RPM
    encoderCount = 0; // Reset encoder count
    lastTime = currentTime;

// Plot RPM vs Voltage in Serial Plotter
    Serial.print(inputVoltage); // Plot Voltage
    Serial.print(",");
    Serial.println(rpm);        // Plot RPM
  }
}

I moved your topic to an appropriate forum category @alh4ss4n .

In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.

This is an important part of responsible forum usage, as explained in the "How to get the best out of this forum" guide. The guide contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.

1 Like

I have no idea what that means.

What did you expect to happen, and what happened instead?

Please post your code in line, using code tags (<code> post editor button).

" attachInterrupt(digitalPinToInterrupt(ENC_B), readEncoder, RISING);"

Pin 4 is NOT an external interrupt pin.

  • a conventional approach is to use a timer that captures a running count each time it expires and subtract the count from the previous count.
  • not sure if you need to handle contact bounce using a mechanical encoder. optical and hall effect encoders don't have bounce
  • not sure if you expect an x vs y plot which is not possible using the Serial plotter

I've provided the code, as you can see. Regarding your question, I specify what I need in the first line.

I want to display the voltage and speed curves on the Serial Plotter.
or even in serial monitor then copy it and move it to excel sheet also

Additionally, I would like to know how to determine in the code the motor's encoder pulses per revolution (e.g., encoderPPR = 12 ) and set the measurement interval (e.g., interval = 100 ms ).

Thank you

Ok, thank you i will make sure not happen again

1 Like

i have replaced that with pin No. 3

Is your motor a gearmotor (with speed reducing gearbox attached)?
If so, do you have access to the back of the motor so it can be turned by hand?

Is your motor a gearmotor (with speed reducing gearbox attached)?

Yes, it's same as in this link (6V, 105 R.P.M)

If so, do you have access to the back of the motor so it can be turned by hand?

Also, it can be turned by hand from the side of encoder wheel but not from the shaft side
and if so, what is the point of that I didn't understand what you mean?

So you can turn the motor shaft 1 turn and see how many pulses you get.

Yes, you’re right, but the pulses on Serial Plotter are updating too quickly.

as speed vs voltage or
speed vs time and voltage vs time

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.