Speed limit because of FOC?

I have a 1 pole pair BLDC motor, rated current 2A, rated voltage 24V, no load speed is 15,000RPM. power supply is as motor spec, rated current 3A.
I am using nucleo L432KC as the controller, it’s Cortex M4 @80MHz.
I don’t have inline current sense, so I use voltage as the torque control type. I noticed that in Angle control and Velocity control, I can’t reach speeds higher than 450 rad/sec which is 4300RPM.
I need 10,000RPM. the motor is not connected to any load. Shaft is free to spin, current measured externally at this 450 rad/sec speed is 0.5A. the voltage measured on the FOC studio at this speed is 4. I measure with voltmeter and I get 8.5V AC.

driver.voltage_power_supply = 24;
motor.voltage_limit = 24.0;
motor.current_limit=2;
motor.velocity_limit = 1000;

Is it because of the limitation of using voltage mode for the torque control? (because I don’t have inline current sense, only low side which is not supported by SimpleFOC)

image

EDIT ==> strangely, increasing the current limit to 3A increases the speed to apprx 680 rad/sec.
However, it is more than the motor’s rated current which is not good.
And then, some other thing happens after a couple of seconds, the current rises to 2-3.5A and the motor decelerates to a stop while still consuming this current constantly!
I really don’t know what is going on here… My only command was M900 at velocity mode

1 Like

Hi, and welcome to SimpleFOC!

Two separate issues. Firstly, the speed:

  1. Yes, the 80MHz CPU speed will eventually limit the max RPM. The frequency of the control loop executing loopFOC() function will determine the maximum speed you can attain since you’re not updating the phase currents faster than this.

  2. You’re using closed-loop mode, the speed at which you can obtain sensor data will probably be the limiting factor. To update the phase currents to a new value you also need new sensor values on which to base the calculations. If the sensor is not fast enough, or the sensor-read speed is not fast enough this will also limit your max. velocity.

  3. 680rad/sec is quite fast for FOC control with SimpleFOC! :smiley: You’re doing well. Probably if you upgrade to a faster MCU you might make it to 10000RPM, if your sensor is fast enough.

  4. If you increase the current, the speed can increase because the motor will move a little more between each iteration of loopFOC().

Second, the “stopping problem”:

This is a separate issue, I think. It is a known bug with magnetic sensors - are you using a magnetic sensor? If so, this problem will be fixed in the next release of the library.

Thank you runger, yes the MA730 is able to reach speeds of 60,000RPM and still maintain its characteristics (according to MPS) so I am not worried about it.
What I do worry about, is the BUG of the high current consumption and stopping abruptly. Yes the MA730 is the magnetic sensor. Is there any way you can share how I can solve this bug? or what lines of code can I change in the library? This is really important. Thanks!

Unfortunately the change will not be contained to just a few lines.

For today, I can suggest the following: you can take a look here: https://github.com/simplefoc/Ardunio-FOC-drivers/blob/master/src/encoders/as5048a/PreciseMagneticSensorAS5048A.cpp
This class will not have the problem, but it is for the AS5048A sensor. Maybe you can copy & modify it for MA730.

I will try to implement the fix within the library ASAP, and report back to you here.

1 Like

thank you runger, I will try to implement it for the MA730

I had about the same requirements when I stumbled upon SimpleFOC.
I downloaded the code and had a look at it, and then thought “this will not work”.
Because when studying what FOC is, I realised what needs to be done.
You can brute-force the motorspeed to anything you want by just using a faster cpu, but the thing is SimpleFOC is not that efficient.
You need a hardware solution, a microcontroller that is designed for motor-control.
What SimpleFOC does is all software-based.
At the core is a loop that reads a position-sensor and calculates the required voltages for getting to the next position.
But by the time it has done so, the rotor-position has advanced so much that the current is no longer generating maximum torque ( which is the single goal of FOC ).
You could compensate for this delay in software, but when you have to do so you might as well use the faster 6-step commutation algorithm.

Are you telling me 80Mhz MCU is not enough to calculate 1 motor’s voltages in real time?

It would be more than enough in other situations. It is just that SimpleFOC was designed for controlling gimbal motors at low speeds. It is not an ESC. ESC’s do better at high speeds.
What you want to do dictates the software you will need and if that software doesn’t exist then you have to write it yourself or adapt something that almost meets your needs.

It’s more than enough :slight_smile: but it depends on what speed you want to go…

Different sensors have different timings - and don’t forget that even if a sensor can do 60000RPM, you might be reading it via SPI at 1MHz, and this will limit the speed at which the MCU can get data from the sensor.

And the MCU, depending on its speed and whether there is an ALU for floating point accelleration, will require different amounts of time for computing the phase currents in the loopFOC function, and the target values in the move() function.

So on an 80MHz MCU, just as an example, maybe you can expect 3kHz on the main loop? So you won’t be able to update the motor’s currents more than 3000x per second. For a 7 pole motor, there are 7 electrical revolutions per turn, and you probably want to hit at least 6 updates (really, more) per electrical revolution, so that’s minimum of 42 updates per turn - 3000updates/s at 42 per turn makes for 71 turns/second, or 4260RPM maximum motor speed for this example MCU…

I’m sure the control theory experts have a much clearer and better way of looking at this, but this is how I think about it.

Thanks runger, my motor has only 1 pole pair (2 poles)
I need to reach 14,000 RPM (1465 rad/ sec)
my encoder is the MA730
How can I decrease the number of updates necessary to achieve this speed?
although technically with 3Khz, 6 updates per turn (6X1), 3000/5 = 500 revs/ sec which is more than 2 times of what I need… right?

Hey, yes, with such a motor it becomes easier, I think!

Do you have access to a logic analyser or oscilloscope? If so, you could time your main loop precisely: I use some unused output pin, toggle this pin in the main loop before the call to loopFOC() and before the call to main(). Then I can see the frequency of the loop in the logic analyser:

In this way you could check your main loop speed, and also check how long the sensor reads are taking, etc… then you will know if it is a MCU speed problem, or due to some other issue (like sensor lag, back EMF, etc…)

Hi Runger
thank you for your offer. it looks quite logical.
Right now I have a strange behavior:
I am using voltage mode as my torque controller. I measure the current externally.
I can reach -1400 rad/sec (CCW direction) , current draw is approx 0.8A (motor is rated for 2A max)
oddly, I had to set the current limit at 4.5A to reach this speed. the higher the current limit, the faster I can go. (velocity limit is 1600, voltage limit is 6V)
in CW direction, I reach 1400 but the current draw is doubled! I measure 1.6A!
same settings. this is very weird.

I need more current to rotate CW than CCW?

Any ideas why this could happen? There is nothing connected to the shaft, the motor is new, and free to spin in any direction.

Thanks
highspeed

One explanation can be a (small) misalignment on the motor electrical zero. This would explain the asymmetrical error.
You could test this by modifying the electrical zero found during alignment by a small amount in either direction, and seeing if this improves the behaviour.

This is expected, of course. The more amps, the faster the motor can go. At some point the marginal gains begin to decrease because of the back-EMF.

I work at my university on methods of optimizing FOC for high speeds. I have written an article that could solve certain issues discussed on this forum. New Method of Vector Control in PMSM Motors | IEEE Journals & Magazine | IEEE Xplore

3 Likes

Thanks for posting this! That is great to decouple the phase shift/amplitude calculation from the PWM duty update.

Rather than making the theta-FOC update conditional, I think it would be best if we could get it to where the PWM update (motor.loopFOC) is called at a fixed frequency, and the velocity/angle PID update (motor.move) and theta-FOC update are done in a separate thread that uses whatever CPU time is remaining. Right now we have a downsampling counter for motor.move, so for example it can be called once for every 4 PWM updates, but it’s not ideal because that causes a periodic delay to the PWM update rather than distributing the additional processing across those 4 updates.

But I don’t think it’s possible to get such multi-threading behavior within the Arduino library… you’d need nested interrupts so the PWM update can be triggered via interrupt without blocking detection of encoder/hall sensor pulses. I suppose a jerry-rigged solution would be to have an interrupt set a flag saying it’s time for a PWM update, and scatter checks for it throughout the other update functions so one of them will run relatively soon after the flag is set.

At the very least, we could have it alternately do motor.move and theta-FOC update between PWM updates.

Kryzsiek, if you are still here, I think we could really use your help on some of the fundamentals, especially on producing good documentation of the fundamentals. I think there are a lot of aspects that are not as well understood by most of us as they should be. For instance, I recently discovered that I could get way way higher energy efficiency by using current optimization, although it has other practical downsides.

Sensorless drive also appears to be largely mysterious to any of us, if I may say so. Certainly to me. But we could really use something in that department, sensors are kind of complicated and expensive, when you factor in all the mounting and calibration and additional error sources and stuff that they introduce.

If we could come together as a community and make some simple well commented, modular pieces of code even as a reference design that I think would be enormously useful to a lot of people.

edit: I looked at the document, and it appears to be remarkably similar to what I did with my fan. However the difference between sine wave and FOC control remains slightly mysterious and that’s a barrier to understanding here…

Huh… in the process of writing down my understanding, it turns out it’s almost the same as our existing foc_current mode. The only difference is the PID_current_d would output an angle offset rather than the d current, so you’d use it like setPhaseVoltage(amplitude, 0, electrical_angle + theta); (amplitude being the output of PID_current_q, as in Fig.10 of the paper).

But what advantage does that have? We could already run the current sense update less often, so setPhaseVoltage is called several times with the same voltage.q and voltage.d but updated electrical_angle so the stator field continues moving. The paper shows it going straight from theta and amplitude regulators to PWM update, but how do you turn an angle and amplitude into PWM duties without the inverse Park+Clarke transform?

1 Like

I find it kind of confusing as things collapse to nearly trivial stuff. Like, to determine the angle and amplitude, you are just using a lookup table, basically. 255 elements, 2pi radians, just map linearly one to the other. To increase amplitude, multiply all duty cycles by X. One of the currents is basically always zero anyway, so you don’t need anything except a sine wave lookup table really. I know there are rare cases when you may wish to have a non zero D current (the useless kind of current), however you can arrange for something very similar just by adjusting theta, the angle between the rotor and magnetic field. You can’t know exactly how much D current you are going to get but that has a pretty minor impact…

I mean, bottom line the average voltage caused by the PWM output is always a 3 phase sine wave (or modified sine wave), but it’s never distorted, is it? Like does it ever get squished to the right or left? I don’t think so.

I guess it’s confusing because the complications often seem to have vanishingly little purpose. Some authors skip over them or ignore them entirely, while others seem to think they are worth distinguishing.

In other FOC control schemes, for instance, the current is measured all the time at the actual terminals of he inverter. This would theoretically give some correction for errors and the influence of inductance and other more minor factors at higher RPMs, which I don’t think is provided for here. In some cases, this would imply changing the time vs voltage graph away from an ideal 3 phase sine wave.

Ah, I think you’re right. Rather than doing sin/cos lookup on the angle followed by inverse Park+Clarke on the d,q current, Kryzsiek’s approach of using amplitude and phase offset would allow you to do a direct lookup of the 3 PWM duties for electrical_angle+theta and then multiply by amplitude.

From what I can tell, the foc_current mode only offsets the phase, not the magnitude, since the PIDs are trying to get q current to setpoint and d current to 0. But there is this proposal from dzid26 which looks to modify the magnitude when adding some d current to compensate for inductance [FEATURE] Include motor inductance in voltage control. · Issue #246 · simplefoc/Arduino-FOC · GitHub
I’m sure it would be possible to calculate the equivalent amplitude/angle offset, but at that point I wonder if it would still be computationally cheaper than the inverse Park+Clarke…