Hi all, I’d like to start off by saying thanks for all the amazing work put into this project. Everything is explained well and getting a motor turning has been made easy.
For the past couple of days I have been trying to get a 1 pp (yes, very low ) 12V BLDC with 3 hall sensors (so 6 CPR) running. I’m using an STM32G071RB Nucleo-64 in combination with the SimpleFOCMini. Velocity open loop works good at low speeds - the motor is able to spin smoothly at 1 rad/s or lower, but not great at high speeds.
To test the closed loop behaviour, I started with the Torque control loop in voltage mode. This works good at high speeds, but it’s not smooth at low speeds (20 rad/s, at roughly 0.2V) and below that the motor doesn’t spin. I captured the approx. 20 rad/s behaviour in slow-motion (link), in which it can be seen that it has a varying velocity and it seems like it slows down twice per rotation (most likely due to cogging). I plotted the angle and velocity data here:
Closer look at the first rotation (2π rad):
and the code:
#include <SimpleFOC.h>
// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(1);
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 10, 11, 8);
// hall sensor instance
HallSensor sensor = HallSensor(2, 3, 4, 1);
// Interrupt routine intialisation
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}
// voltage set point variable
float target = 0;
// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target, cmd); }
void setup() {
// power supply voltage [V]
driver.voltage_power_supply = 12;
driver.voltage_limit = 12;
driver.init();
motor.linkDriver(&driver);
motor.voltage_limit = 6;
// initialize sensor hardware
sensor.pullup = Pullup::USE_EXTERN;
sensor.init();
sensor.enableInterrupts(doA, doB, doC);
// link the motor to the sensor
motor.linkSensor(&sensor);
// aligning voltage
motor.voltage_sensor_align = 1;
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
// set motion control loop to be used
motor.controller = MotionControlType::torque;
// initialize motor
motor.init();
// align sensor and start FOC
motor.initFOC(0, Direction::CW);
// use monitoring with serial
Serial.begin(115200);
// comment out if not needed
motor.useMonitoring(Serial);
// add target command T
command.add('T', doTarget, "target voltage");
Serial.println(F("Motor ready."));
Serial.println(F("Set the target voltage using serial terminal:"));
_delay(1000);
}
void loop() {
motor.loopFOC();
motor.move(target);
//motor.monitor();
command.run();
}
I experimented with SpaceVector, Sine, and Trapezoidal modulation, but none of which show a big influence on the performance at low speeds. Closed loop velocity control with PID tuning works nicely, but the same applies here (as expected); not smooth at low speeds, and increasing the motor.LPF_velocity.Tf
made performance worse. Adding the phase resistance of 4.8 Ohm did not result in improvement.
To be honest, with a CPR of 6 I wasn’t expecting amazing performance at low speeds, but I was hoping to get some tips on possibly improving the smoothness at low RPM. Would switching to 6x PWM and/or current sensing help?