6 CPR motor - tips on smooth operation at low speeds?

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 :grinning:) 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?

For reference, this is what the hall sensors data in open loop velocity at 20 rad/s look like:

I’m not sure, but I assume the problem here is the “step-like” response you’ll be getting from the sensor in this situation.
With Halls, the angle will only update when the next hall sensor interrupt is received. Until then, the angle will stick at the old value.
So from the point of view of the controller, it will drive the motor, not see any change in angle, increase the voltage, still not see any change, increase the voltage some more, etc… then, finally, when the interrupt arrives, the angle will change by a whole lot all at once, and the controller will go “whoa”, and back down again… and repeat.

I think the sensor value has to change more smoothly to get smooth control of the motor.

I think perhaps the modification @dekutree64 just made (see end of this thread: Programming the Lepton from start to finish - #85 by dekutree64) could be really interesting for you in this situation…

It seems like the modification is some kind of interpolation, this might indeed work if the problem is the frequency of interrupts. I will give it a try!

Is there a way to monitor the voltages to see if this is indeed the case? You’d expect to see an increase in voltage until the next interrupt is received. I tried to monitor the voltages using motor.monitor() in torque control mode, but this doesn’t show any variations in voltage.
Additionally, should it be expected to see this increase/decrease in voltage to occur 6 times per rotation? In the slow motion video (link), it seems to be 2 times per rotation. I can feel cogging torque twice per rotation when manually spinning the motor, so this could also be the problem.

Yes, in torque-voltage mode there are no PID controllers, so the Q axis voltage remains the same (at whatever you set the target to). But in velocity mode you should see the voltage reacting to the sensor via the PID. This kind of thing can be difficult to monitor, since the voltage will be adjusted once per call to motor.move(), but often you can’t output values to Serial at this speed.

So if you’re in torque-voltage mode and experiencing irregularity 2x per turn then this might just be cogging.

Yes, but it will depend on the iteration speed of the call to move() compared to the speed the motor is turning (frequency of HallSensor interrupts), and the speed at which you can output debug values… so it can be a bit tricky to check.

I managed to record the Q voltage and plotted it against the angle/velocity data.


I guess it could still be due to cogging. Any meaningful conclusions that can be drawn from the voltage data?

Is this now in Velocity mode? Because here I think you can kind of see what I was talking about, how the voltage is reacting to the velocity…

Yes indeed, this is velocity mode. Is there a chance this is still purely due to clogging torque? In that case I’m not sure if the interpolation will smooth it out much, but it’s definitely worth a try.

There is no current sensing though, so voltage-based torque control is used for the velocity mode. Also, trapezoidal 120 seemed to show the best low-rpm performance and highest RPM per volt. But reading the docs, it said that FOC current torque control requires either Sinusoidal PWM or Space vector PWM. Do you think the use of FOC current torque control will positively influence the low-rpm performance? I currently don’t have any drivers with current sensing capabilities to test this

TBH I don’t think so, but I’m not sure - I’ve never had a 1PP motor :slight_smile:

I would have said that a 1PP motor is designed to turn fast, and getting it to turn smoothly at low RPM might be a challenge… but there are many kinds of motor and I don’t know enough about it to say…

I’m not sure it will make a difference to cogging problems… do you need precise torque control for your application?

1 Like

I would say not really, the load is quite stable. It’s mostly about precise velocity control, but since this might require precise torque control… maybe. Although the voltage based velocity control seems to do a good job right now