Hey everyone,
I’m working on a project where I need to control the rotational speed of a BLDC motor from 0 up to 3000 RPM. I’m using a 42BLS40-24-01 motor, which is rated for up to 4000 RPM, with a phase resistance of 1.9 ohms and a maximum current of 1.8 A. The setup includes an ESP32 and a SimpleFOC Mini v1.0 driver.
I was able to get the motor running smoothly in open-loop velocity mode, but when switching to closed-loop velocity control using Hall sensors, I’ve been running into serious issues. The motor only moves in large, jerky steps and the shaftVelocity()
always reports 0 rad/s in the serial monitor.
What I’ve tried so far:
- Swapping the Hall sensor pin order (A, B, C in different combinations)
- Swapping motor phases
- Tuning the PID controller (P, I, D). This slightly improved performance and let the motor rotate at ~1 rad/s, but it’s still far from stable or usable
- Verified Hall sensor signals using an oscilloscope – they look fine and respond to movement, and if I rotate the shaft with my hand the reported speed changes.
- I’m also using a Schmitt trigger inverter to shift the Hall signals from 5 V to 3.3 V, two times to keep the same signal, and I’ve added pull-up resistors on the signal lines
In open-loop, the motor behaves as expected but obviously I can’t use it for accurate speed control. Below are a couple of the test codes I’ve been working with, but so far no luck getting reliable closed-loop behavior.
If anyone has ideas on what might be going wrong—timing, sensor configuration, PID settings, etc.—I’d really appreciate some help.
Thanks in advance!
Opoen loop code:
#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SimpleFOC.h>
// DRV8313
const int IN1 = 25;
const int IN2 = 13;
const int IN3 = 26;
const int EN_PIN = 32;
BLDCMotor motor = BLDCMotor(4);
BLDCDriver3PWM driver = BLDCDriver3PWM(IN1, IN2, IN3, EN_PIN);
void setup() {
Serial.begin(9600);
Serial.println(“Iniciando…”);
// Driver setup
pinMode(EN_PIN, OUTPUT);
digitalWrite(EN_PIN, HIGH);
driver.voltage_power_supply = 24;
driver.voltage_limit = 6.0;
driver.init();
// Motor setup
motor.linkDriver(&driver);
motor.controller = MotionControlType::velocity_openloop;
motor.voltage_limit = 6.0;
motor.init();
motor.target = 1.0; // rad/s inicial
}
void loop() {
motor.loopFOC();
motor.move();
// Aumentar gradualmente la velocidad
static float velocidad = 1.0;
static unsigned int count = 0;
count++;
if (count >= 250) {
velocidad += 5;
if (velocidad > 150) velocidad = 1.0;
motor.target = velocidad;
Serial.print("Velocidad objetivo: ");
Serial.println(velocidad*60/ (2 * PI));
count = 0;
}
delay(5);
}
Closed loop code 1:
#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SimpleFOC.h>
//DRV8313
const int IN1 = 25;
const int IN2 = 13;
const int IN3 = 26;
const int EN_PIN = 32;
//Hall
const int HALL_A = 4;
const int HALL_B = 16;
const int HALL_C = 17;
// Motor y driver
BLDCMotor motor = BLDCMotor(4,1.9);//Pole pairs and phase resistance
BLDCDriver3PWM driver = BLDCDriver3PWM(IN1, IN2, IN3, EN_PIN);
HallSensor sensor = HallSensor(HALL_A, HALL_B, HALL_C, 4);
void doA() { sensor.handleA(); }
void doB() { sensor.handleB(); }
void doC() { sensor.handleC(); }
void setup() {
Serial.begin(9600);
Serial.println(“Iniciando closed-loop con sensores Hall…”);
sensor.init();
sensor.enableInterrupts(doA, doB, doC);
driver.voltage_power_supply = 24;
driver.init();
motor.linkDriver(&driver);
motor.linkSensor(&sensor);
motor.current_limit = 1.8;
motor.controller = MotionControlType::velocity;
motor.PID_velocity.P = 0.2f;
motor.PID_velocity.I = 5.0f;
motor.PID_velocity.D = 0.0f;
motor.LPF_velocity.Tf = 0.02f;
motor.PID_velocity.output_ramp = 1000;
motor.init();
motor.initFOC();
motor.target = 5.0;
Serial.println(“Motor listo en closed-loop”);
}
void loop() {
motor.loopFOC();
motor.move();
float vel_rad_s = motor.shaftVelocity();
float vel_rpm = vel_rad_s * 60.0 / (2.0 * PI);
Serial.print("Sensor angle: ");
Serial.println(sensor.getAngle());
Serial.print("Sensor velocity: ");
Serial.println(sensor.getVelocity());
delay(200);
}
Closed loop code 2:
#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SimpleFOC.h>
//DRV8313
const int IN1 = 25;
const int IN2 = 13;
const int IN3 = 26;
const int EN_PIN = 32;
//Hall
const int HALL_A = 4;
const int HALL_B = 16;
const int HALL_C = 17;
// Motor y driver
BLDCMotor motor = BLDCMotor(4);
BLDCDriver3PWM driver = BLDCDriver3PWM(IN1, IN2, IN3, EN_PIN);
HallSensor sensor = HallSensor(HALL_A, HALL_B, HALL_C, 4);
void doA() { sensor.handleA(); }
void doB() { sensor.handleB(); }
void doC() { sensor.handleC(); }
void setup() {
Serial.begin(9600);
Serial.println(“Iniciando closed-loop con sensores Hall…”);
// Habilitar driver
pinMode(EN_PIN, OUTPUT);
digitalWrite(EN_PIN, HIGH);
// Inicializar sensor Hall
sensor.init();
sensor.enableInterrupts(doA, doB, doC);
// Inicializar driver
driver.voltage_power_supply = 24;
driver.voltage_limit = 12;
driver.init();
// Configurar motor
motor.linkDriver(&driver);
motor.linkSensor(&sensor);
motor.voltage_limit = 12; // Voltaje máximo de salida
motor.controller = MotionControlType::velocity;
// Parámetros PID de velocidad
motor.PID_velocity.P = 0.4f;
motor.PID_velocity.I = 0.025f;
motor.PID_velocity.D = 0.0f;
// Filtro pasa bajas y rampa de salida
motor.LPF_velocity.Tf = 0.01f;
motor.PID_velocity.output_ramp = 1000;
motor.init();
motor.initFOC();
motor.target = 2.0;
Serial.println(“Motor listo en closed-loop”);
}
void loop() {
motor.loopFOC();
motor.move();
float vel_rad_s = motor.shaftVelocity();
float vel_rpm = vel_rad_s * 60.0 / (2.0 * PI);
Serial.print("Sensor angle: ");
Serial.println(sensor.getAngle());
Serial.print("Sensor velocity: ");
Serial.println(sensor.getVelocity());
delay(200);
}