Control motor using speed measurement

Hello, I am trying to control a motor using the speed measurements I am currently taking using a hall effect sensor. However I did not manage to get the speed measurement from the void loop() and use it to control the motor.
What can I add in the MotorControl() function to get the speed from the void loop() and then use it to increase or decrease the speed of the motor?
Below you can see my code.

#include <Servo.h>
#include <SoftwareSerial.h>

SoftwareSerial BTserial(0,1);

Servo esc_signal;
int velocity = 30;


// Configuration constants:
const byte RevSensePin = 2;
const float WheelRadiusInMeters = 0.33;
const unsigned long DisplayIntervalMillis = 1000;  // Update once per second
const unsigned long MaxRevTimeMicros = 2000000UL; // >2 seconds per revolution counts as 0 RPM

// Variables used in the ISR and in the main code must be 'volatile'
volatile unsigned long RevSenseTimeMicros = 0;  //  Time that the rising edge was sensed
volatile unsigned long RevTimeMicros = 0;  // Microseconds between consecutive pulses

// Useful constants:
const unsigned long SixtySecondsInMicros = 60000000UL;
const float WheelCircumferenceInMeters = TWO_PI * WheelRadiusInMeters;

void setup()
{
  BTserial.begin(115200);
  delay(15000);
  esc_signal.attach(9);
  esc_signal.write(velocity);
  delay(100);
  pinMode(RevSensePin, INPUT);
  attachInterrupt(digitalPinToInterrupt(RevSensePin), RevSenseISR, RISING);
}

void loop()
{
  MotorControl();

  static unsigned previousRPM;
  // Only update the display once per DisplayIntervalMillis
  unsigned long currentMillis = millis();
  static unsigned long previousMillis = 0;
  if (currentMillis - previousMillis >= DisplayIntervalMillis)
  {
    previousMillis += DisplayIntervalMillis;

    // With interrupts disabled, make local copies of volatile variables
    // This is so the ISR can't change them while we read them
    noInterrupts();
    unsigned long revSenseTimeMicros = RevSenseTimeMicros;  //  Time that the last rising edge was sensed
    unsigned long revTimeMicros = RevTimeMicros;  // Microseconds between consecutive pulses
    interrupts();

    // Calculate RPM
    unsigned newRPM;
    if (micros() - revSenseTimeMicros > MaxRevTimeMicros)
      {newRPM = 0;   // Going so slow we're essentially stopped
      displayRPM(newRPM);}
    else
      newRPM = SixtySecondsInMicros / revTimeMicros;
      displayRPM(newRPM);

    // No need to update the display unless the RPM value has changed
    if (newRPM != previousRPM)
    {
      previousRPM = newRPM;
      displayRPM(newRPM);
    }
  }
}

void MotorControl()
{

}

void RevSenseISR()
{
  static unsigned long revSensePreviousMicros = 0;  // 'static' to retain value between calls

  RevSenseTimeMicros = micros();
  RevTimeMicros = RevSenseTimeMicros - revSensePreviousMicros; // Time for last revolution
  revSensePreviousMicros = RevSenseTimeMicros;
}

void displayRPM(unsigned RPM)
{
  float metersPerSecond = RPM * WheelCircumferenceInMeters / 60;

  BTserial.print("RPM = "); //print the word "RPM".
  BTserial.print(RPM); // print the rpm value.
  BTserial.print("\t\t Linear Speed = ");
  BTserial.print(metersPerSecond); //print the linear velocity value.
  BTserial.println(" m/s");
}
SoftwareSerial BTserial(0,1);

There is just no excuse for doing software serial on the hardware serial pins.

Why do you control the motor and then measure the speed? If the speed of the motor depends on the measured value, it would make sense to measure the value first, and then use the measured value.

You would make the MotorControl() function aware of the measured speed exactly the same way that you make displayRPM() aware of it.

if you auto-format your code (CTRL-T) you will see a problem with this code

    if (micros() - revSenseTimeMicros > MaxRevTimeMicros)
      {newRPM = 0;   // Going so slow we're essentially stopped
      displayRPM(newRPM);}
    else
      newRPM = SixtySecondsInMicros / revTimeMicros;
      displayRPM(newRPM);

The else clause contains only 1 statement, not two.

chrismil:
Hello, I am trying to control a motor using the speed measurements I am currently taking using a hall effect sensor.

For controlling the motor there is actually no need to calculate the RPM. Speed can be controlled with less code if you just work with the number of microsecs per revolution.

You could occasionally (like once or twice per second) calculate the RPM for the benefit of the humans. :slight_smile:

The usual way to make a motor run at a specific speed is by using PID control (probably all you need are the P and I elements). If you start with your motor control code that makes a proportionate change in the PWM value depending on the difference (error) between the actual speed and the desired speed then you have the P part of PID. However it is the I part that is more important. It takes account of the accumulated error by adding (or subtracting) a little to its value in proportion to the error. When the actual speed and the desired speed are the same the P element will be zero and the I element won't be changing.

There is an Arduino PID library but IMHO it just makes the whole thing appear mystical. I know other contributors will disagree with me.

...R