Hi everyone, I’ve been trying to solve this issue for weeks and would like to gather some thoughts from you.
Setup:
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:
set torque (current.q to 0.5)
change the set point for current.d from default 0 to -0.4
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)?
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.
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.
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…
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?