Hall sensor bldc motor does not turn

engine pp=2
volts = 24
voltage control
pp check = 2 correct
but the motor does not turn, only the sound is heard, the interruptions are 12 in a full revolution

Hi,

2 PP is a very low number of pole pairs :slight_smile:

With hall sensors, I think you only get 12 counts per revolution, this won’t give you much position accuracy.

If you share your code here, perhaps we can help to see if there are mistakes, but if you get no movement at all then it could also be an electrical problem… kindly share some more details of your setup (which driver, which MCU, maybe some pictures/diagrams of how you have connected things).

/**
 *
 * Velocity motion control example
 * Steps:
 * 1) Configure the motor and sensor
 * 2) Run the code
 * 3) Set the target velocity (in radians per second) from serial terminal
 *
 *
 *
 * NOTE :
 * > Specifically for Arduino UNO example code for running velocity motion control using a hall sensor
 * > Since Arduino UNO doesn't have enough interrupt pins we have to use software interrupt library PciManager.
 *
 * > If running this code with Nucleo or Bluepill or any other board which has more than 2 interrupt pins
 * > you can supply doC directly to the sensor.enableInterrupts(doA,doB,doC) and avoid using PciManger
 *
 */
#include <SimpleFOC.h>
// software interrupt library


// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(2);
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
// Stepper motor & driver instance
/

// hall sensor instance
HallSensor sensor = HallSensor(2, 3, 4, 2);

// Interrupt routine intialisation
// channel A and B callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}
// If no available hadware interrupt pins use the software interrupt


// velocity set point variable
float target_velocity = 0;
// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_velocity, cmd); }

void setup() {

  // initialize sensor sensor hardware
  sensor.init();
  sensor.enableInterrupts(doA, doB, doC);
  // software interrupts
  sensor.pullup = Pullup::USE_EXTERN;
  // link the motor to the sensor
  motor.linkSensor(&sensor);

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 24;
  driver.init();
  // link the motor and the driver
  motor.linkDriver(&driver);

  // aligning voltage [V]
  motor.voltage_sensor_align = 1;

  // set motion control loop to be used
  motor.controller = MotionControlType::velocity;

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

  // velocity PI controller parameters
  motor.PID_velocity.P = 0.2f;
  motor.PID_velocity.I = 2;
  motor.PID_velocity.D = 0;
  // default voltage_power_supply
  motor.voltage_limit = 12;
  // jerk control using voltage voltage ramp
  // default value is 300 volts per sec  ~ 0.3V per millisecond
  motor.PID_velocity.output_ramp = 1000;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.01f;

  // use monitoring with serial
  Serial.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial);

  // initialize motor
  motor.init();
  // align sensor and start FOC
  motor.initFOC();

  // add target command T
  command.add('T', doTarget, "target voltage");

  Serial.println(F("Motor ready."));
  Serial.println(F("Set the target velocity using serial terminal:"));
  _delay(1000);
}


void loop() {
  // main FOC algorithm function
  // the faster you run this function the better
  // Arduino UNO loop  ~1kHz
  // Bluepill loop ~10kHz
  motor.loopFOC();

  // Motion control function
  // velocity, position or voltage (defined in motor.controller)
  // this function can be run at much lower frequency than loopFOC() function
  // You can also use motor.move() and set the motor.target in the code
  motor.move(target_velocity);

  // function intended to be used with serial plotter to monitor motor variables
  // significantly slowing the execution down!!!!
  // motor.monitor();

  // user communication
  command.run();
}

this is the code

mcu card = stm32f411 re

driver card =
FOC-SimpleFOC-MotorDriveDevelopmentBoard

  • IR2103 drivers
  • 1 engine
  • 36V/20A
  • low-side current sensing

doing engine recognition
getting offset
but in speed mode the motor makes noise and does not turn.

Your code says

float target_velocity = 0;

Did you send the velocity command to the motor? If you just run the code it will stand still. You need to change the velocity.

Serial command
Target velocity=2

What’s the resistance of the motor?

You’re using 24V normally, but 1V during alignment. Maybe the currents are too high? You could try setting a lower voltage limit to see if things improve.

Are you working in ArduinoIDE or PlatformIO?

If you check the PWM outputs from the MCU to the IR2103 drivers, do they look correct? You can check them with an oscilloscope or logic analyzer…

Isn’t it supposed to be

T2

Instead of

Target velocity=2

Also you say

motor.move(target_velocity);

But I don’t see you setting this variable anywhere. It’s initialized as 0 at the beginning, then you just pass it directly without modifying it.

float target_velocity = 0;

I suggest you initialize it with

float target_velocity = 1;

and see what happens.

HI,
I’m having probrem like above…
So I want get help.
Please check if my setup is correct?

bord: Bluepill driver:3PWM motor:M5065 170KV with HallSensor(I think 7polepairs, 12slots) PB6:PWM_U PB7:PWM_V PB8:PWM_W PB3:Ena_U PB4:Ena_V PB5:Ena_W PB12:Hall_U PB13:Hall_V PB14:Hall_W

I wrote code below from SimpleFOC sckech template.

/**
 *
 * STM32 Bluepill position motion control example with encoder
 *
 * The same example can be ran with any STM32 board - just make sure that put right pin numbers.
 *
 */
#include <SimpleFOC.h>



// Motor instance
BLDCMotor motor = BLDCMotor(7,NOT_SET,170);
// BLDCDriver3PWM(IN1, IN2, IN3, enable(optional))
BLDCDriver3PWM driver = BLDCDriver3PWM(PB6, PB7, PB8, PB3, PB4, PB5);
// BLDCDriver6PWM(IN1_H, IN1_L, IN2_H, IN2_L, IN3_H, IN3_L, enable(optional))
//BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PB13, PA9, PB14, PA10, PB15, PB12);

// encoder instance
//Encoder encoder = Encoder(PA8, PA9, 8192, PA10);

/**
HallSensor class constructor
@param encA  HallSensor A pin
@param encB  HallSensor B pin
@param encC  HallSensor C pin
@param pp  pole pairs  (e.g hoverboard motor has 15pp and small gimbals often have 7pp)
@param index index pin number (optional input)
*/
HallSensor sensor = HallSensor(PB12, PB13, PB14, 7);

// Interrupt routine intialisation
// channel A and B callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}

// angle set point variable
float target_angle = 10.0f;
// instantiate the commander
Commander commander = Commander(Serial);
void doTarget(char* cmd) { commander.scalar(&target_angle, cmd); }
//void doMotor(char* cmd) {commander.motor(&motor, cmd);}

void setup() {

  // initialize encoder sensor hardware
  sensor.init();
  sensor.enableInterrupts(doA, doB, doC);

  // driver config
  // power supply voltage [V]
//  driver.pwm_frequency = 20000;
  driver.pwm_frequency = 10000;
  driver.voltage_power_supply = 24;
  driver.voltage_limit = 24;
  driver.init();

  // link the motor to the sensor
  motor.linkSensor(&sensor);
  // link the motor and the driver
  motor.linkDriver(&driver);
  
  // aligning voltage [V]
  motor.voltage_sensor_align = 3;
  // index search velocity [rad/s]
  motor.velocity_index_search = 3;

  // set motion control loop to be used
  motor.controller = MotionControlType::velocity;

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

  // velocity PI controller parameters
  motor.PID_velocity.P = 0.2f;
  motor.PID_velocity.I = 20;
  // default voltage_power_supply
  motor.voltage_limit = 24;
  // jerk control using voltage voltage ramp
  // default value is 300 volts per sec  ~ 0.3V per millisecond
  motor.PID_velocity.output_ramp = 1000;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.01f;

  // angle P controller
  motor.P_angle.P = 20;
  //  maximal velocity of the position control
  motor.velocity_limit = 10;


  // use monitoring with serial
  Serial.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial);

  /* DEBUG CODE */
  Serial.println("VolLim:");
  //Serial.println(voltage_limit);

  // initialize motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

  // add target command T
  commander.add('T', doTarget, "target angle");
//  commander.add('M', doMotor, "motor");

  Serial.println(F("Motor ready."));
  Serial.println(F("Set the target angle using serial terminal:"));
  _delay(1000);
}

void loop() {
  
  sensor.update();
  
  // main FOC algorithm function
  // the faster you run this function the better
  // Arduino UNO loop  ~1kHz
  // Bluepill loop ~10kHz
  motor.loopFOC();

  // Motion control function
  // velocity, position or voltage (defined in motor.controller)
  // this function can be run at much lower frequency than loopFOC() function
  // You can also use motor.move() and set the motor.target in the code
  motor.move(target_angle);
//  motor.move(2);

  // function intended to be used with serial plotter to monitor motor variables
  // significantly slowing the execution down!!!!
  // motor.monitor();

  // user communication
  commander.run();
}

have you checked if these pins are the correct pwm combination?

Set voltage limit much lower for initial testing, for safety. Like 1 or 2 volts. This will limit top speed, but still produce high starting torque due to the low resistance of brushless motors.

Print out sensor.hall_state and turn the motor by hand to make sure the sensors are reading correctly.

Drive the motor in open loop velocity or angle mode to make sure PWM is working correctly.

Drive in torque mode and tune the KV/phase resistance so you can use voltage-based current limiting. Then you can safely set voltage limit higher. You could also try trapezoid120 modulation rather than the default sine, but either should work. If the top speed is higher in one direction than the other, use sine modulation and adjust motor.zero_electric_angle until both directions are equal (it’s set automatically by calibration, but sometimes needs manual adjustment to correct for imperfect sensor placement)

Drive in velocity mode and tune velocity PID, and adjust KV some more if needed. You could also try changing motor.LPF_velocity.Tf. I usually set it to 0.05 with hall sensors.

Finally drive in angle mode and tune angle P, and adjust velocity PID some more if needed.

2 Likes

It won’t work the way he chose the pwm, those are wrong timer pins. He needs to assign the correct pwm timer pins. The correct pins are in his code comments, for some reason he decided to ignore those. :man_facepalming:

Thank you for reply!
I’ll try the method you told me.

Thank you for reply!
My understanding may be wrong, so let me check again.

・Does it mean that I have selected a pin that cannot output PWM?
・Are the correct pins you are talking about “PA8~PA10”, “PB13~PB15”?
・I read from the “STM32F103x8” data sheet that PB6 to PB8 are pins that can output PWM, but is that wrong? Or was it not good to try to output PWM to UVW with the same timer?

You need to please read in-depth the documentation on timers. You need to assign the phases to the same complementary timers combination of pins.

BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PB13, PA9, PB14, PA10, PB15, PB12);

Pin PB12 is enable if your driver board has an enable pin.

Please read the documentation in its entirety.

Cheers,
Valentine

Hello everyone, it has been a while.
I burned the driver and have been waiting for a new driver to try your advice.

Thanks to you, the motor is running in SimpleFOC.

I tried “MotionControlType::velocity” and “MotionControlType::velocity_openloop”.

velocity_openloop:
It rotates according to the value of the command, and it is quiet and wonderful even though it is an OpenLoop.

velocity:
Probably moves according to the command value. It seems to move according to the command value, but it is larger than OpenLoop and the current is also larger than OpenLoop.

I looked at the hall sensor waveforms for the motor I am currently using as well, and the hall sensor signal (UVW) is not evenly timed. is this why OpenLoop is turning more cleanly? If the settings are better, will it still turn good in this case?

The current code is also attached.

/**
 *
 * STM32 Bluepill position motion control example with encoder
 *
 * The same example can be ran with any STM32 board - just make sure that put right pin numbers.
 *
 */
#include <SimpleFOC.h>

#define ENCODER       (0)
#define HALLSENSOR    (1)
#define NONE          (2)
#define USESENSOR     (HALLSENSOR)

#define A_HALL1       (PA8)
#define A_HALL2       (PA9)
#define A_HALL3       (PA10)

// Motor instance
BLDCMotor motor = BLDCMotor(11);
// BLDCDriver3PWM(IN1, IN2, IN3, enable(optional))
//BLDCDriver3PWM driver = BLDCDriver3PWM(PB6, PB7, PB8, PB5);
BLDCDriver3PWM driver = BLDCDriver3PWM(PB6, PB7, PB8, PB5, PB4,PB3);
// BLDCDriver6PWM(IN1_H, IN1_L, IN2_H, IN2_L, IN3_H, IN3_L, enable(optional))
//BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PB13, PA9, PB14, PA10, PB15, PB12);

#if USESENSOR == ENCODER
  // encoder instance
  Encoder encoder = Encoder(A_HALL1, A_HALL2, 8192, A_HALL3);

  // Interrupt routine intialisation
  // channel A and B callbacks
  void doA(){encoder.handleA();}
  void doB(){encoder.handleB();}
  void doIndex(){encoder.handleIndex();}
  
#elif USESENSOR == HALLSENSOR  /* #if USESENSOR == ENCODER */

  // hallsensor instance
  HallSensor hsensor = HallSensor(A_HALL1, A_HALL2, A_HALL3, 11);

  // Interrupt routine initialization
  // channel A and B callbacks
  void doA(){hsensor.handleA();}
  void doB(){hsensor.handleB();}
  void doC(){hsensor.handleC();}

#endif  /* #if USESENSOR == ENCODER */

// angle set point variable
float target_angle = 0;
// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_angle, cmd); }


void setup() {

#if USESENSOR == ENCODER
  // initialize encoder sensor hardware
  encoder.init();
  encoder.enableInterrupts(doA, doB); 
  // link the motor to the sensor
  motor.linkSensor(&encoder);
#elif USESENSOR == HALLSENSOR  /* #if USESENSOR == ENCODER */
  // initialize sensor hardware
  hsensor.init();
  // hardware interrupt enable
  hsensor.enableInterrupts(doA, doB, doC);
  // maximal expected velocity
  hsensor.velocity_max = 1000; // 1000rad/s by default ~10,000 rp
  // link the motor to the sensor
  motor.linkSensor(&hsensor);
#endif /* #if USESENSOR == ENCODER */

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 12;
  driver.init();
  // link the motor and the driver
  motor.linkDriver(&driver);

  // aligning voltage [V]
  motor.voltage_sensor_align = 3;
  // index search velocity [rad/s]
  motor.velocity_index_search = 3;

  // set motion control loop to be used
//  motor.controller = MotionControlType::velocity;
  motor.controller = MotionControlType::velocity_openloop;

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

  // velocity PI controller parameters
  motor.PID_velocity.P = 0.2f;
  motor.PID_velocity.I = 20;
//  motor.PID_velocity.I = 50;
  // default voltage_power_supply
  motor.voltage_limit = 2;
  // jerk control using voltage voltage ramp
  // default value is 300 volts per sec  ~ 0.3V per millisecond
  motor.PID_velocity.output_ramp = 1000;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.01f;

  // angle P controller
  motor.P_angle.P = 20;
  //  maximal velocity of the position control
  motor.velocity_limit = 4;


  // use monitoring with serial
  Serial.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial);

  // initialize motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

  // add target command T
  command.add('T', doTarget, "target angle");

  Serial.println(F("Motor ready."));
  Serial.println(F("Set the target angle using serial terminal:"));
  _delay(1000);
}

void loop() {
  // main FOC algorithm function
  // the faster you run this function the better
  // Arduino UNO loop  ~1kHz
  // Bluepill loop ~10kHz
  motor.loopFOC();

  // Motion control function
  // velocity, position or voltage (defined in motor.controller)
  // this function can be run at much lower frequency than loopFOC() function
  // You can also use motor.move() and set the motor.target in the code
  motor.move(target_angle);

  // function intended to be used with serial plotter to monitor motor variables
  // significantly slowing the execution down!!!!
//  motor.monitor();

  // user communication
  command.run();
}

This would definitely explain it. The hall sensor signals should be regular if the velocity is constant…