I’m trying to control a low voltage BLDC (40V) with Simple FOC. The motor spins, but not very efficiently, and is noisy. The phases and current do not look right on the scope. Any help is greatly appreciated!
The code is essentially the same as the example “Motion Control / Torque Control / Hall Sensor / Voltage” using the pins available on the Nucleo F303RE:
#include <SimpleFOC.h>
// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(8);
BLDCDriver3PWM driver = BLDCDriver3PWM(PA8, PA9, PA10, PC10, PC11, PC12);
// hall sensor instance
HallSensor sensor = HallSensor(PA15,PB3, PB10, 8);
// Interrupt routine intialisation
// channel A and B callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}
// voltage set point variable
float target_voltage = -5;
//float target_voltage = -10;
//float target_voltage = 10;
// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_voltage, cmd); }
void setup() {
// initialize encoder sensor hardware
sensor.init();
sensor.enableInterrupts(doA, doB, doC);
// link the motor to the sensor
motor.linkSensor(&sensor);
// driver config
// power supply voltage [V]
driver.voltage_limit = 40;
driver.voltage_power_supply = 20;
driver.init();
// link driver
motor.linkDriver(&driver);
// aligning voltage
motor.voltage_sensor_align = 3;
// choose FOC modulation (optional)
//motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
//motor.foc_modulation = FOCModulationType::SinePWM;
//motor.foc_modulation = FOCModulationType::Trapezoid_120;
motor.foc_modulation = FOCModulationType::Trapezoid_150;
// set motion control loop to be used
motor.controller = MotionControlType::torque;
// 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 voltage using serial terminal:"));
motor.target = 5.0f;
_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_voltage);
static int lastMillis;
int newMillis = millis();
if(newMillis > lastMillis + 2000) {
lastMillis = newMillis;
Serial.println(motor.sensor->getVelocity() * 9.549297);
}
// user communication
command.run();
};
For FOC control, don’t use the Trapezoid150 modulation. Best is Sine or SpaceVector.
Also, your driver.voltage_limit is twice your driver.voltage_power_supply. voltage_limit should be less than (or the same as) power supply voltage, it doesn’t make sense to set it higher than the PSU voltage.
To get nicer modulation when using Sine, set motor.voltage_limit equal to 0.5 * driver.voltage_power_supply.
What motor are you using? Does it really have 8PP? It’s quite possible, but an usual number.
Could you please also post pictures of the physical setup, wiring, motor, etc?
I will post some pictures later on, the motor I’m working with is closed, I’ll hook up another one with the lid open and take a picture.
Did you make sure the pole pairs match your motor?
Yes, and they do. Also, 18 coil stators wound like this: AaABbBCcCAaABbBCcC, 3 Hall sensors at 120deg
Did you try tuning the loop?
I would be willing to try, if you point me to instructions?
Did you try other foc_modulation?
I’ve tried the 4 modulation options available, but really looking forward to using Sine or SpaceVector, for efficiency and quiet operation.
For FOC control, don’t use the Trapezoid150 modulation. Best is Sine or SpaceVector.
Yes, Sine or SpaceVector is definitely the goal, I posted the other pictures / modulations in case it helps figure out the problem.
Also, your driver.voltage_limit is twice your driver.voltage_power_supply. voltage_limit should be less than (or the same as) power supply voltage, it doesn’t make sense to set it higher than the PSU voltage.
To get nicer modulation when using Sine, set motor.voltage_limit equal to 0.5 * driver.voltage_power_supply.
I just did that, here’s the resulting SinePWM modulation on the scope:
What motor are you using? Does it really have 8PP? It’s quite possible, but an usual number.
Yes, it’s a Chinese motor for fan applications. I’ll post pictures of it later.
Those are the comments I have off-hand…
Let us know if this makes any difference!e
I appreciate any help, everything counts!
Those voltages now look a lot more like they should, one can see the commutation pattern being set to the motor.
The current waveform looks less convincing I assume this is an inline current shunt that’s being measured via a current sense amp, or using a hall-effect current sensor? (since its a single ended measurement on the scope?)
May I ask what driver you’re using? Is it possible currents are rising too high, causing over-current protection to trigger? What’s the phase resistance on this motor?
What happens if you set a fairly low motor.voltage_limit, say 5V or 3V?
I’m a little confused, why are you measuring the current from Nucleo board to the motor? In fact why is even there a phase wire from Nucleo into the motor? Do you mean one of the the phase wires from the driver? Pictures of the entire setup would be really helpful.
The picture is very poor and doesn’t show the rest of the setup, but from the very little I see, this is a high quality original ST X-NUCLEO-IHM07M1 eval board.
Why are you piping the phase wires through a ferrite core? That core is probably so oversaturated it won’t do anything, you just warm up the air and mess up your phase current.
I would say try with open loop to control the motor, get rid of the funny ferrite core, and make sure you make the motor spin smoothly open loop before you attempt anything else.
Are you sure you don’t trigger the overcurrent protection of L6230? That driver can barely drive may be 3A max before you trip it. I know you say you don’t trigger the overcurrent, just asking.
The ferrite works as choke, helps removes EMI noise, but the current shape is the same with or without it (it also helps bunch the wires together).
The power supply is limited to 3A, but I could limit it to 2A and it still wouldn’t trigger overcurrent.
The motor runs pretty well, actually I can get 600+ RPM from it, still under 2A. The problem is the current modulation is far from sinusoidal, and the motor is noisy, you can hear the click-click-click during commutation.
Please correct me if I’m wrong, since this looks like a manually wound-up custom motor, however, the number of pole pairs is usually higher than the number of windings. Here I see 18 coils, so your pole pairs should be around 11 if I’m not mistaken.
Could you please count the number of PM and divide by 2?
If you manage to run the motor smoothly open velocity with 1 pp, and it stutters when you close the loop with 8 pp, I would probably guess the number of pole pairs may have something to do with it.
Either this or the hall sensors are having problems, you may want to check the signals from the hall sensors too?