Motor not reaching rated speed

Hi everyone, I’ve been trying to solve this issue for weeks and would like to gather some thoughts from you.

B-G431B-ESC1 motor controller
AS5600 magnetic sensor
Eaglepower 8308 KV90
Current sensing, closed loop control (foc_current), running at 12k FOC iterations per second
12V power supply

The current loop seems to be working fine and my tests have been focusing on torque mode.

At 12V the motor is expected to run at 12V * 90 = 1080 RPM = 113 rad/s, but instead it is only running at a maximum of ~85 rad/s upon increasing current (speed starts to flatten out at ~1A). Increasing the supply voltage to 15V does not increase the speed further. Upon outputting motor.Ua, I found out that the range of Ua never really used up the whole supply voltage, but rather only from ~2V to 10V regardless of whether I supply 12V or 15V, which kind of explains why the motor is only running at 85 rad/s.

Some other posts mentioned I2C is slowing the Foc algo down but I confirmed that the loop is running at 90kHz+ after setting the I2C clock to 1MHz and editing MagneticSensorI2C::read(uint8_t angle_reg_msb) to NOT do the following everytime but rather put it in the setup code.
// wire->beginTransmission(chip_address);
// wire->write(angle_reg_msb);
// wire->endTransmission(false);

Upon some tinkering, I found out that if I do the following:

  1. set torque (current.q to 0.5)
  2. change the set point for current.d from default 0 to -0.4
  3. reduce current.q set point to 0
    The motor will achieve the rated speed. The Ua graph also shows a full utilization of the whole supply voltage range.

Are motors KV typically rated assuming field weakening (i.e. current.d < 0)?

What modulation type ?

Stupid question, but what settings have you used for voltage and current limits?

You will also hit a speed limit at some point that is imposed by the main loop speed. With an I2C sensor, the main loop speed is limited by the sensor…

In terms of the field weakening, it is not clear how the stated base speed for a motor is measured, so I would take the numbers from the Datasheet as approximate. If you’re getting within 10% of them, that’s pretty good I would say

I had basically an identical problem, torque mode, same board, same sensor. mysterious limit with the motor not speeding up past x speed. I think it was cause by motor timing errors. What happens is that the code propagation and other stuff leads to a situation where there is an error in the assumed angle between the rotor and the magnetic field (motor timing). Obvioulsy to drive the motor the field has to be advanced to pull the rotor along. But for whatever reason one catches up to the other enough that the motor can no longer accelerate.

Pretty hard to diagnose though, but you can start identifying different error sources and clobbering them one by one and see if it goes any faster.

As a diagnostic test and also as a crude hacky solution, you could try tampering with the sensor zero offset. You could add a value X to it that is proportional to RPM.

Are you sure your loop is running that fast?

Yes, it seems very fast for an I2C based sensor…

I was wondering why no one replied to that? Maybe that’s the key and all my AS5600 are suddenly interesting alternatives to the expensive AS5047/48


I hadn’t seen that one :slight_smile:

But just looking at the numbers, 1Mhz would allow you to transfer 1000000 bits per second (or is it 500k, not sure if the frequency is equal to the clock pulses or they are halved due to low and high cycles)?

Each angle is a 16bit transfer, registers 0x0E and 0x0F.

It’s true you don’t have to re-write the source register if you want to read the same one again. And you also don’t have to close the transaction.

But still, 1Mhz/16=62.5kHz, and we have not taken into account the ACK bits.
So I’m not clear how 90kHz would be possible.

It’s also not clear to me how you would switch between the 2 registers without a write in-between.

So basically I think if you are happy with 4 bit angles you could just read register 0x0E in a tight loop. But if you want the 12 bit resolution, you’d need to read both registers, and 90kHz seems quite impossible.

Or am I missing something here?

I’m terribly sorry I meant to say the look is running at 9kHz rather than 90kHz.

@Candas1 I’m using SpaceVectorPWM
The limits are

driver.voltage_power_supply = 15;
driver.voltage_limit = driver.voltage_power_supply1.0;
motor.voltage_limit = driver.voltage_power_supply
motor.current_limit = 20;

The limits may look aggressive but I have the following thermal protection in place:

if (counter1 % 100 == 0) {
temp = _readADCVoltageInline(A_TEMPERATURE, currentSense.params);
temp = Ntc2TempV(temp);
vbus = _readADCVoltageInline(A_VBUS, currentSense.params);
vbus = vbus * 10.7711;
driver.voltage_power_supply = vbus;
driver.voltage_limit = driver.voltage_power_supply;
motor.voltage_limit = driver.voltage_power_supply * 0.58;

if (temp > 60) {
  target = 0;

if ((motor.enabled==0) && (temp < 50)){


I have to spend more time to look into this. Currently I am just commenting out part of the code in the MagneticSensorI2C.cpp, and placed it at setup instead. I printed the angle to serial and the results seems to be correct.

int MagneticSensorI2C::read(uint8_t angle_reg_msb) {
// read the angle register first MSB then LSB
byte readArray[2];
uint16_t readValue = 0;
// notify the device that is aboout to be read
// wire->beginTransmission(chip_address);
// wire->write(angle_reg_msb);
// wire->endTransmission(false);

// read the data msb and lsb
wire->requestFrom(chip_address, (uint8_t)2);
for (byte i=0; i < 2; i++) {
readArray[i] = wire->read();

// depending on the sensor architecture there are different combinations of
// LSB and MSB register used bits
// AS5600 uses 0…7 LSB and 8…11 MSB
// AS5048 uses 0…5 LSB and 6…13 MSB
readValue = ( readArray[1] & lsb_mask );
readValue += ( ( readArray[0] & msb_mask ) << lsb_used );
return readValue;

By the way, it seems like the original setting for AS5600 is reading from 0x0C instead of 0x0E and 0x0F?

Ok that makes way more sense! And 9kHz would still be excellent for this sensor!

Yes you’re right about the register, the sensor has ANGLE and RAW_ANGLE registers. The difference is whether the hysteresis is applied or not. Looks like SimpleFOC is using the RAW ANGLE by default…

As you are using the magnetic sensor library, can I take the opportunity to ask feedback about this ? :sweat_smile:

Yeah, I saw it thanks so much!! I didn’t get round to commenting on it yet but it seems a quick fix that we should do…

I meant @jasonlcy could try this as pow() is also used in the magnetic sensor init.
We can have feedback with a different chip/board/use case.

#define pwrtwo(x) (1 << (x))

I tried this formula on my calculator and 1 LSH 5 is 32, not 25 as expected.
What am I doing wrong?

It’s just a bit shift
00000001 << 0 = 00000001 = 1
00000001 << 1 = 00000010 = 2
00000001 << 2 = 00000100 = 4

Only for power of 2 for integers

I know what left-shift / right shift is. But pwrtwo(x) means x^2 , right? So 5^2 is 25, but the result of 1<< 5 is 32
Maybe I get the whole define line wrong?
Am I confusing it with defining a function?

Maybe my english is bad, I haven’t learned math in english lol
It’s image

1 Like

Same here :man_facepalming: , but the coin has dropped

using either method the flash usage is the same on B-G431-ESC
cpr = pow(2, _bit_resolution);
cpr = (1 << _bit_resolution);

Hmmm weird. Are you using voltage sense?
Thanks a lot.