Get RPM output from BLDC-8015A motor driver

Hello people,

I am using an BLDC Motor driver for a project, I have managed to give the motor driver an input by potentiometer and I have somewhat managed to implement an switch to turn the motor on and of but I want to get an output in RPM. I think I have to connect the speed pin from the driver to an interuptpin on the arduino but I only get a return of RPM 0 so far. this is the datasheet with information about the motor driver ( China Brushless DC motor Driver BLDC-8015A Manufacturer and Supplier | ACT )
The code I have so far is: tab 1

extern double Amps;
void setup() {
 Serial.begin(9600);    // Debuggen via seriële monitor
 setupMotor();          // Initialiseer motorbesturing
 setupMotorSpeed();     // Initialiseer snelheidsmeting
 setupCurrentSense();   // Initialiseer stroommeting
}

void loop() {
 // Motorbesturing (met knoppen en potentiometer)
 controlMotor();

 // Bereken de werkelijke snelheid (RPM)
 calculateRPM(6); // 6 pulsen per omwenteling (pas dit aan volgens je setup)
 float currentRPM = getActualRPM();

 // Voer stroommetingen uit
 CurrentSense();

 // Debug-output naar seriële monitor
 Serial.print("RPM: ");
 Serial.print(currentRPM);
 Serial.print("\tAmps: ");
 Serial.println(Amps, 3); // Stroom in Ampère met 3 decimalen

 delay(200); // Update-interval
}

tab 2:

 // CurrentSense.ino
// CurrentSense.ino
double Amps = 0;
// Pinnen
const int analogIn = A1; // ACS712 analoge pin

// Variabelen
const int mVperAmp = 100; // 100 voor 20A Module, 66 voor 30A Module
const int ACSoffset = 2500; // Offset in mV (kan variëren per module)
int RawValue = 0;
double Voltage = 0;


// Initialisatie van stroommeting
void setupCurrentSense() {
  // Geen seriële initialisatie nodig, want deze gebeurt in de main
}

// Functie voor stroommeting
void CurrentSense() {
  RawValue = analogRead(analogIn); // Lees de analoge waarde van ACS712
  Voltage = (RawValue / 1024.0) * 5000; // Bereken spanning in mV
  Amps = ((Voltage - ACSoffset) / mVperAmp); // Bereken stroom in Ampère

  // Debuggen gebeurt in de hoofdcode (main)
}

tab 3

// Pindefinities
const int aviPin = 9;         // PWM-uitgang voor snelheid
const int brakeSwitchPin = 6; // Rem-schakelaar
const int motorDirPin = 3;    // Richting pin voor motor driver
const int motorBrakePin = 4;  // Rem pin voor motor driver
const int potPin = A0;        // Potentiometer-pin

// Variabelen voor motorstatus
bool motorBrake = false;      // Remstatus van de motor
int motorSpeed = 0;           // Snelheid van de motor (0-255)

// Debouncing timer voor de schakelaar
unsigned long lastDebounceTimeBrake = 0;
unsigned long debounceDelay = 500;  // Debounce vertraging (ms)

bool lastSwitchStateBrake = HIGH; // Vorige toestand van de rem-schakelaar

void setupMotor() {
  pinMode(aviPin, OUTPUT);        // PWM pin voor snelheid
  pinMode(brakeSwitchPin, INPUT_PULLUP); // Rem-schakelaar met interne pull-up
  pinMode(motorDirPin, OUTPUT);          // Richting pin voor motor driver
  pinMode(motorBrakePin, OUTPUT);        // Rem pin voor motor driver
  pinMode(potPin, INPUT);               // Potentiometer pin voor snelheid

  // Zet de richting van de motor initieel op false (tegen de klok in)
  digitalWrite(motorDirPin, LOW);

  Serial.begin(9600); // Seriële communicatie voor debugging
}

void controlMotor() {
  // Rem-schakelaar logica
  bool currentSwitchStateBrake = digitalRead(brakeSwitchPin); // Lees de huidige schakelaarstatus
  if (currentSwitchStateBrake == LOW && lastSwitchStateBrake == HIGH && (millis() - lastDebounceTimeBrake) > debounceDelay) {
    motorBrake = !motorBrake;           // Toggle de remstatus
    lastDebounceTimeBrake = millis();   // Reset debouncing timer
    Serial.print("Motor Brake: ");
    Serial.println(motorBrake ? "Engaged" : "Released");
  }
  lastSwitchStateBrake = currentSwitchStateBrake;  // Sla de vorige toestand op

  // Lees de potmeterwaarde voor snelheid (0-1023)
  int potValue = analogRead(potPin);  // Leest de waarde van de potmeter (0-1023)
  motorSpeed = map(potValue, 0, 1023, 0, 255);  // Zet de waarde om naar een bereik van 0-255 voor PWM

  // Motorbesturing: pas rem en snelheid aan
  applyBrake(motorBrake);             // Zet de remstatus
  analogWrite(aviPin, motorSpeed);    // Zet de snelheid van de motor via PWM

  // Debugging informatie
  Serial.print("Motor Speed: ");
  Serial.println(motorSpeed);
}

// Functie om de remstatus van de motor in te stellen
void applyBrake(bool brake) {
  if (brake) {
    digitalWrite(motorBrakePin, HIGH); // Zet de rem aan
  } else {
    digitalWrite(motorBrakePin, LOW);  // Zet de rem uit
  }
}

And tab 4 as the important tab

// Pinnen
const int speedPin = 2;       // SPEED-pin van motor driver
volatile unsigned long pulseCount = 0; // Pulsteller
unsigned long lastTime = 0;
float actualRPM = 0.0;

// Initialisatie
void setupMotorSpeed() {
  pinMode(speedPin, INPUT); // Zet de SPEED-pin als invoer
  attachInterrupt(digitalPinToInterrupt(speedPin), countPulse, RISING); // Koppel een interrupt aan de pin
  Serial.println("Motor speed monitoring initialized."); // Debug bevestiging
}

// Pulsenteller: wordt aangeroepen via interrupt
void countPulse() {
  pulseCount++; // Tel elke puls
  Serial.println("Pulse detected!"); // Debug: bevestiging dat er een puls is ontvangen
}

// RPM berekenen
void calculateRPM(int pulsesPerRevolution) {
  unsigned long currentTime = millis();
  unsigned long elapsedTime = currentTime - lastTime;

  if (elapsedTime >= 1000) { // Berekening elke seconde
    actualRPM = (pulseCount * 60.0) / pulsesPerRevolution; // Omrekening naar RPM
    pulseCount = 0; // Reset de pulsteller voor de volgende berekening
    lastTime = currentTime; // Reset de timer
    Serial.print("Calculated RPM: "); // Debug: print de berekende RPM
    Serial.println(actualRPM);
  }
}

// Haal de werkelijke RPM-waarde op
float getActualRPM() {
  return actualRPM;
}

thank you for the help

You need to set the pin to input-Pullup() so a positive voltage is applied to the internal opt-isolator. The control will pull the pin down for the RPM signal. Be sure to do the correct math for the motor RPM.

2 Likes

Hi, thank you for answering,

I have an RPM output using the following code

volatile unsigned int pulseCount = 0;
unsigned long lastTime = 0;

void setup() {
  pinMode(2, INPUT_PULLUP); // Verbind de SPEED-uitgang met pin 2 van de Arduino.
  attachInterrupt(digitalPinToInterrupt(2), countPulse, RISING); // Tel pulsen.
  Serial.begin(9600);
}

void loop() {
  unsigned long currentTime = millis();
  
  if (currentTime - lastTime >= 1000) { // Bereken elke seconde
    noInterrupts();
    unsigned int count = pulseCount;
    pulseCount = 0;
    interrupts();

    // Pas de waarden hieronder aan op basis van je motorconfiguratie
    int polePairs = 3; // Aantal poolparen van de motor
    int frequencyMultiplier = 6; // Interne frequentieverhoging
    float rpm = (count * 60.0) / (polePairs * frequencyMultiplier);


    
    Serial.print("RPM: ");
    Serial.println(rpm);

    lastTime = currentTime;
  }
}

void countPulse() {
  pulseCount++;
}

The problem now is that te signal seems to be very unstable, I get outputs from 0 RPM to 60 RPM whil I let the BLDC motor go at a constant speed, could this be a problem from using jump wires to connect the driver with the arduino? or something else?

I think that may be the problem because I also get unstable returns from the ampère meter (from the seccond code part in the first message)

The code looks ok, Why not begin debugging by printing the raw pulsecount before doing your calculation. See if it is stable.

1 Like

I am not getting any pulses returned, using the following code:

volatile unsigned int pulseCount = 0;
unsigned long lastTime = 0;

void setup() {
  pinMode(2, INPUT_PULLUP); // Verbind de SPEED-uitgang met pin 2 van de Arduino. Gebruik een externe pull-up weerstand.
  attachInterrupt(digitalPinToInterrupt(2), countPulse, RISING); // Tel pulsen bij een stijgende flank.
  Serial.begin(9600);
}

void loop() {
  unsigned long currentTime = millis();
  
  if (currentTime - lastTime >= 1000) { // Bereken elke seconde
    noInterrupts();
    unsigned int count = pulseCount;
    pulseCount = 0;
    interrupts();

    // Pas de waarden hieronder aan op basis van je motorconfiguratie
    int polePairs = 4; // Aantal poolparen van de motor
    int frequencyMultiplier = 6; // Interne frequentieverhoging
    float rpm = (count * 60.0) / (polePairs * frequencyMultiplier);

    Serial.print("RPM: ");
    Serial.println(rpm);
    Serial.print("pulseCount: ");
    Serial.println(pulseCount);
    lastTime = currentTime;
  }
}

void countPulse() {
  pulseCount++;  // Verhoog de puls-teller bij elke puls
  Serial.println("Pulse detected");
}

because i don't get Pulse detected returned I fell like i did something wrong with the interupt function

Yes, looks like and interrupt on a rising signal on a digital line that is held high most of the time is wrong. What happens if you change the interrupt trigger to change or to falling?

1 Like

with both change and falling it returns Pulse detected but it still delivers pulse count 0 :edit when i change pulsecount to count in Serial.println it does return the pulse count and I notice that at higher speeds it can't count any pulses, ( mabey they are to close to eachother for the arduino to count those)

https://forum.arduino.cc/t/serial-println-inside-isr-bad-idea/298010

1 Like

Yes, do not do any serial.print() inside interrupt code! It will just fill the output buffer and cause your program to stop until there is more space in the buffer.

1 Like

You code does work at low frequencies, but at 9600Bd it takes nearly 17ms to print "Pulse detected" plus CR & LF.

If another pulse comes along before the printing has finished then the pulse count will be wrong. This occurs around 125 rpm.

1 Like

Thank you all for answering, I will remove the pulse detected, I just added it to check if the interrupt was working. But the system only found 2 to 5 pulses in a second while the motor went a lot faster then 12.5 RPM. The arduino has trouble picking up the rest of the pulses to find the correct RPM, the rated speed of the motor is 3000 RPM, the arduino was unable to pick up any pulses at the higher frequenties. I will apply the changes in morning when I am at my internship. (Small company, no one knows how this works and this is my 2th time doing something a bit complex with the arduino)

Bad idea! Don't do this in the future. Your pulse count will give you the identical information and is not inhibited by slow output or limited buffer size or required interrupts being enabled.
A test of pulse count being greater than 0 will give the same information.

1 Like

with the pulse detected print removed I pick up some more pulses, but the pulsecount still is unreliable and way to low. In the picture is visible how i conected everything (eventhough I am currently only using Digital pin 2) is there some hardware I need to obtain all incomming pulses, or is it still a software issue?




Yes, you need to find an oscilloscope of almost any type to monitor the lead you are using for interrupts. Beg, borrow or steal one, even for a day or so.

Your rats nest of wires concern me, but since you have too FEW interrupts, noise pickup does not seem to be causing this problem.

Please tell us how many interrupts per second should be happening?

1 Like

I would try with a real resistor as pullup on pin 2.

1 Like

at 24V 0,1 A I counted 116 rotations in a minute, 116/2,5= 46,4 pulses per second. At this speed the arduino mesures between 0 and 5 rpm so 2 pulses max, with the external resistor as pullup like ZX80 suggested I observed more movement between different speeds, so at 0,3A it generely mesured between 30 and 50 RPM (somethimes with a 25 or 55 but those were more rare). In the futere the current power supply will be swaped out for a permenent connection so I can't relay on that to get the needed information. Also the rats nest of wires will be fixed when i make the thing I have designed. I unfortionetly do not have acces to an oscilloscope for the forseable future

Maybe that should be:

void setupMotorSpeed() {
  pinMode(speedPin, INPUT_PULLUP); // Zet de SPEED-pin als invoer
  attachInterrupt(digitalPinToInterrupt(speedPin), countPulse, FALLING);

?

The link posted said 12 pulses per rev. 600 pulses per second for 50 revolutions per second.

1 Like

This somehow does it with the external resistor, I obtained all the pulses, still somewhat inconsistent but it does give about the right RPM, I need to change the math a little bit so when I add load to the motor it takes more Amps to reach the same RPM but because the higher Amps it sends more pulses
but thank you all so much for helping me get this far

This is the current full code

volatile unsigned int pulseCount = 0;
unsigned long lastTime = 0;

void setup() {
  pinMode(2, INPUT_PULLUP); 
  attachInterrupt(digitalPinToInterrupt(2), countPulse, FALLING);
  Serial.begin(9600);
}

void loop() {
  unsigned long currentTime = millis();
  
  if (currentTime - lastTime >= 1000) { // Bereken elke seconde
    noInterrupts();
    unsigned int count = pulseCount;
    pulseCount = 0;
    interrupts();

    // Pas de waarden hieronder aan op basis van je motorconfiguratie
    int polePairs = 4; // Aantal poolparen van de motor
    int frequencyMultiplier = 6; // Interne frequentieverhoging
    float rpm = (count * 60.0) / (polePairs * frequencyMultiplier);

    Serial.print("RPM: ");
    Serial.println(rpm);
    Serial.print("pulseCount: ");
    Serial.println(count);
    lastTime = currentTime;
  }
}

void countPulse() {
  pulseCount++;  // Verhoog de puls-teller bij elke puls
}

I added the following piece of code at the end instead of the current void countPulse(){

unsigned long lastInterruptTime = 0; 

void countPulse() {
  unsigned long currentTime = millis();
  if (currentTime - lastInterruptTime > 10) {
    pulseCount++;
    lastInterruptTime = currentTime;
  }
}

this seems to work for getting a more stable signal for lower frequenties of speeds, but for higher speeds it didn't pick up anything anymore, would somting like if lower the x pulses do this code, else do the other piece of code in the interupt work?

This was for two motors or two polePairs, The motor I use has 8poles or 4 PolePairs, I think that is the difference between the example in the link and what I, also I never shared the link from the motor itself, link for motor I use the 57BLF03 version