Control BLDC use hallsensor

When I control using closeloop, I set the velocity to 5 rad/s, then change the PID parameters. Initially I gave I = 0 then changed P. I realized at motor.PID_velocity.P = 0.2; The motor started to accelerate but I noticed on the serial screen that the voltage gradually increased to 1 value and the wheel stopped rotating.
When tested with higher P values, the wheel rotates unevenly. It seems like it only rotates for a while and then spins again, causing the wheel to jerk.
Below is a picture of the voltage in the second column. When the voltage is < 0.8, the wheel still rotates, but when it is greater than 0.8V, the wheel stops.
I use esp32S3.


That sounds very similar to the problem I was having the other day when I tried 41F hall sensors. They’d sometimes flood the CPU with interrupts, preventing the main loop from running. Mine seemed related to current, not voltage. It would freeze at a certain speed when running unloaded, or at lower speed if I grabbed the rotor with my hand. I never did get to the bottom of it. Just changed back to U1881 sensors. They can retrigger the interrupt a few times as well, but not enough to cause problems.

Here’s my debugging code:

#define HISTORY_SIZE 256
int historyCursor = 0;
unsigned short irqAHistory[HISTORY_SIZE];
unsigned short irqBHistory[HISTORY_SIZE];
unsigned short irqCHistory[HISTORY_SIZE];
void doA(){sensor.handleA();irqAHistory[historyCursor]++;}
void doB(){sensor.handleB();irqBHistory[historyCursor]++;}
void doC(){sensor.handleC();irqCHistory[historyCursor]++;}

void UpdateHistory()
  if(++historyCursor >= HISTORY_SIZE)
    historyCursor = 0;
  irqAHistory[historyCursor] = 0;
  irqBHistory[historyCursor] = 0;
  irqCHistory[historyCursor] = 0;

void PrintHistory()
  for (int i = 0; i < HISTORY_SIZE; i++)
    const int index = (historyCursor + i) & (HISTORY_SIZE - 1);

Call UpdateHistory in main loop, and set up a key press to call PrintHistory. The printout shows the last 256 frames, how many times each sensor interrupted that frame. Ideally it should be at most one interrupt per frame.

Hit the print key as quickly as possible after the motor jerks, to get a readout of the data before and after it happened and see what was going on.

here is my code:

#include <SimpleFOC.h>
// #include <PciManager.h>
// #include <PciListenerImp.h>
#define pp 15

#define INH_A2 45 //PWM_A
#define INH_B2 48 //PWM_B
#define INH_C2 47 //PWM_C

#define EN_GATE2 35
#define M_PWM2 38
#define M_OC2 37
#define OC_ADJ2 36

#define HALLa2 (17)
#define HALLb2 (8)
#define HALLc2 (3)
// Motor instance
BLDCMotor motor2 = BLDCMotor(pp);
// BLDCDriver3PWM(IN1, IN2, IN3, enable(optional))
//BLDCDriver3PWM driver = BLDCDriver3PWM(PB6, PB7, PB8, PB5);
BLDCDriver3PWM driver2 = BLDCDriver3PWM(INH_A2, INH_B2, INH_C2, EN_GATE2);

// hallsensor instance

HallSensor hsensor2 = HallSensor(HALLa2, HALLb2, HALLc2, pp);
// channel A and B callbacks
void doA2(){hsensor2.handleA();}
void doB2(){hsensor2.handleB();}
void doC2(){hsensor2.handleC();}
//PciListenerImp listenC(hsensor.pinC, doC);
// angle set point variable
//float target_angle = 0;
float target_velocity1 = 0.0;
float target2 = 0.0;

// instantiate the commander
Commander command = Commander(Serial);
void doTarget2(char* cmd2) { command.scalar(&target2, cmd2); }

void setup() {
// M_PWM - enable 3pwm mode
// OC_ADJ - set the maximum overcurrent limit possible
// Better option would be to use voltage divisor to set exact value

// M_PWM - enable 3pwm mode
// OC_ADJ - set the maximum overcurrent limit possible
// Better option would be to use voltage divisor to set exact value
// initialize sensor hardware
// check if you need internal pullups
hsensor2.pullup = Pullup::USE_EXTERN;
// hardware interrupt enable
hsensor2.enableInterrupts(doA2, doB2, doC2);

// link the motor to the sensor
// driver config
// power supply voltage [V]

driver2.pwm_frequency = 20000;

//driver1.voltage_power_supply = 24;
//driver1.voltage_limit = 12;
driver2.voltage_power_supply = 36;
//driver2.voltage_limit = 12;

// link the motor and the driver
// aligning voltage [V]
// motor1.voltage_sensor_align = 3;
motor2.voltage_sensor_align = 3;

// motor2.torque_controller = TorqueControlType::voltage;

motor2.controller = MotionControlType::velocity;

// contoller configuration
// default parameters in defaults.h

// // velocity PI controller parameters
motor2.PID_velocity.P = 0.01;
motor2.PID_velocity.I = 0;
//motor2.PID_velocity.D = 0.01;
// the lower the less filtered
motor2.LPF_velocity.Tf = 0.08;

//motor.PID_velocity.limit = 0;

// motor.PID_velocity.I = 50;
// default voltage_power_supply
//motor1.voltage_limit = 2;
motor2.voltage_limit = 4;
motor2.velocity_limit = 40; //rad/s

// use monitoring with serial
// comment out if not needed

//motor1.monitor_downsample = 30; // default 10
motor2.monitor_downsample = 50; // default 10

// initialize motor

// align encoder and start FOC
motor2.zero_electric_angle = 0.00; // rad
motor2.sensor_direction = Direction::CW; // CW or CCW
// Serial.println(motor2.zero_electric_angle);

// add target command T
command.add(‘t’, doTarget1, “target angle”);
command.add(‘u’, doTarget2, “target angle”);

Serial.println(F(“Motor ready.”));
Serial.println(F(“Set the target angle using serial terminal:”));

void loop() {

motor2.PID_velocity.I = target2;


// Serial.print(hsensor2.getAngle());;


Do you need to open so many threads?

Sorry, because every time I encounter the same problem

Same problem should be in same thread…
How can people help you if you share information in 3 different threads ?

Sorry, I will learn from it. Thank you

thank you my friend, the problem is in the pins of the controller chip

1 Like