I'm a beginner of arduino. i want to maintain the constant rpm of bldc motor with 3 out of 1 hall sensor using pid algorithm

#include <PID_v2.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

int hallSensorPin = 3;
volatile int hallState = LOW;
volatile int lastHallState = LOW;
const int pwmPin = 11;
const int hallSensorPulsesPerRotation = 15;
double rpm;
double kp = 1, Ki = 0, Kd = 0;

double setpoint =120, input, output;

PID myPID(&input, &output, &setpoint, kp, Ki, Kd, DIRECT);

volatile unsigned long hallSensorCounter = 0;
unsigned long previousRisingEdgeTime = 0;
volatile unsigned long Interrupts = 0;
volatile unsigned long timeSinceLastRisingEdge;
unsigned long previousMillis = 0;

void hallSensorInterrupt() {
hallState = digitalRead(hallSensorPin);

if (hallState == HIGH) {
  // A rising edge (north-to-south) has been detected for the first Hall sensor
  Interrupts++;
}

}
void setup() {
Serial.begin(9600);
pinMode(hallSensorPin, INPUT_PULLUP);
pinMode(pwmPin, OUTPUT);
lcd.init(); // I2C
lcd.backlight();
lcd.clear();

attachInterrupt(digitalPinToInterrupt(hallSensorPin), hallSensorInterrupt, CHANGE);

myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0, 255);

}

void loop() {
unsigned long currentMillis = millis();
if ((currentMillis - previousRisingEdgeTime) > 1000) {

  timeSinceLastRisingEdge = currentMillis - previousRisingEdgeTime;
  previousRisingEdgeTime = currentMillis;

  double pulsesPerSecond = (1000.0*Interrupts) / timeSinceLastRisingEdge;
  rpm = (pulsesPerSecond*60.0)/hallSensorPulsesPerRotation;

  myPID.Compute();
  analogWrite(pwmPin, output);

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

lcd.setCursor(0, 1);
lcd.print("pwm:");
lcd.print(output);

  Interrupts = 0;
  previousRisingEdgeTime = currentMillis;

}

}

So does your code work?

no still i can't maintain the constant rpm. is this possible to maintain the constant rpm.

How are you measuring RPM?
How much does it vary?
Is the load on the motor constant?

Setting Ki and Kd to zero You turn the PID into a pure proportional control.

  1. rpm = pps*60/ppr(i think 30 is my ppr of my motor because 30 poles and 3 hall sensor)
  2. 05:17:50.545 -> pwm: 120.00
    05:17:51.500 -> RPM: 559.44
    05:17:51.547 -> pwm: 120.00
    05:17:52.502 -> RPM: 559.44
    05:17:52.549 -> pwm: 120.00
    05:17:53.504 -> RPM: 551.45
    05:17:53.551 -> pwm: 120.00
    05:17:54.506 -> RPM: 551.45
    05:17:54.553 -> pwm: 120.00
    05:17:55.509 -> RPM: 551.45
    05:17:55.556 -> pwm: 120.00
    05:17:56.511 -> RPM: 551.45
    05:17:56.558 -> pwm: 120.00
    05:17:57.514 -> RPM: 555.44
    05:17:57.561 -> pwm: 120.00
    05:17:58.516 -> RPM: 551.45
  3. without load result may like this

05:19:59.765 -> RPM: 5194.81
05:19:59.765 -> pwm: 120.00
05:20:00.768 -> RPM: 5746.25
05:20:00.768 -> pwm: 120.00
05:20:01.770 -> RPM: 5858.14
05:20:01.770 -> pwm: 120.00
05:20:02.772 -> RPM: 5778.22
05:20:02.772 -> pwm: 120.00
05:20:03.774 -> RPM: 6053.95
05:20:03.774 -> pwm: 120.00

when i put load in my hand

yes, now I'm using KP & later i use ki and kd for tuning.

You need to post your code using code tags <CODE/>

  #include <PID_v2.h>
  #include <LiquidCrystal_I2C.h>
  LiquidCrystal_I2C lcd(0x27, 16, 2);
  
  
  int hallSensorPin = 3;
  volatile int hallState = LOW;
  volatile int lastHallState = LOW;
  const int pwmPin = 11;
  const int hallSensorPulsesPerRotation = 15;
  double rpm;
  double kp = 1, Ki = 0, Kd = 0;
  
  double setpoint =70, input, output;
  
  PID myPID(&input, &output, &setpoint, kp, Ki, Kd, DIRECT);
  
  volatile unsigned long hallSensorCounter = 0;
  unsigned long previousRisingEdgeTime = 0;
  volatile unsigned long Interrupts = 0;
  volatile unsigned long timeSinceLastRisingEdge;
  unsigned long previousMillis = 0;
  
  void hallSensorInterrupt() {
    hallState = digitalRead(hallSensorPin);
  
    if (hallState == HIGH) {
      // A rising edge (north-to-south) has been detected for the first Hall sensor
      Interrupts++;
    }
  }
  void setup() {
    Serial.begin(9600);
    pinMode(hallSensorPin, INPUT_PULLUP);
    pinMode(pwmPin, OUTPUT);
    lcd.init(); // I2C
    lcd.backlight();
    lcd.clear();                                                                                                  
  
    attachInterrupt(digitalPinToInterrupt(hallSensorPin), hallSensorInterrupt, CHANGE);
  
    myPID.SetMode(AUTOMATIC);
    myPID.SetOutputLimits(0, 255);
  }
  
  void loop() {
      unsigned long currentMillis = millis();
    if ((currentMillis - previousRisingEdgeTime) > 1000) {
  
      timeSinceLastRisingEdge = currentMillis - previousRisingEdgeTime;
      previousRisingEdgeTime = currentMillis;
  
      double pulsesPerSecond = (1000.0*Interrupts) / timeSinceLastRisingEdge;
      rpm = (pulsesPerSecond*60.0)/hallSensorPulsesPerRotation;
  
      myPID.Compute();
      analogWrite(pwmPin, output);
  
      
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("RPM: ");
    lcd.print(rpm);
  
    lcd.setCursor(0, 1);
    lcd.print("pwm:");
    lcd.print(output);
    
    Serial.print("RPM: ");
  Serial.println(rpm);
  Serial.print("pwm: ");
  Serial.println(output);
  
      Interrupts = 0;
      previousRisingEdgeTime = currentMillis;
  
    }
  }

What type of speed controller do you have connected to the BLDC motor?

No separate speed controller. jkbldc driver was connected.

It could be a hardware or software problem.
In order to go any further with the debugging, you need to show a diagram of how you have everything is connected and post the operators manual for the jkbldc driver you are using.

Looks fully okey during the sircumstanses.

but, constant speed not uptrained in both load and no load condition

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