i bought a B-G431B-ESC1 to do some fine tuning to get it to work sensorless underwater (motor will be placed inside oil, so no sensor possible). The motor is an old EMAX CF 2822 (just for testing currently becaus im afraid something will produce smoke ).
I have the following problem with the code below:
At low velocity values the motor stutters but starts after i increase it
the motor spins but with little to no torque (grabbing it will stop it easily)
At medium revs it stops sometimes
At a bit higher revs it immediately stops and does not spin again until i start from 0 velocity
Setting the motor.voltage_limit will:
at lower values work better, but even less torque
at higher values the motor wont spin and make screeching noises (really ear hurting)
Im sure i am doing something wrong, because even my cheap FVT LittleBee ESCs work better…
Second: The G431 is getting extremely hot after seconds! Even at this low speed and torque
Thank you!
Specs:
B-G431B-ESC1 Revision AU3/C-01 (V3, the newest)
EMAX CF 2822
14 poles, 7 pole pairs if counted correct
Unknown phase resistance (how do i measure this, is this necessary?)
Should be 1200kv
platformio.ini
[env:disco_b_g431b_esc1]
platform = ststm32
board = disco_b_g431b_esc1
framework = arduino
monitor_speed = 115200
upload_protocol = stlink
build_flags =
#-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC not a good idea for G431
-D PIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF
-D HAL_OPAMP_MODULE_ENABLED # needed?
lib_archive = false
lib_deps =
askuric/Simple FOC@^2.2.2
SPI
Wire
main.cpp (including update)
#include <Arduino.h>
//#define _STM32_DEF_
#include <SimpleFOC.h>
// - pp - pole pair number (count of poles/2)
// - R - phase resistance value - optional
// - KV - motor KV rating [rpm/V] - optional
BLDCMotor motor = BLDCMotor(7);
// MUST USE 6PWM FOR B-G431 DRIVER
BLDCDriver6PWM driver = BLDCDriver6PWM(A_PHASE_UH, A_PHASE_UL, A_PHASE_VH, A_PHASE_VL, A_PHASE_WH, A_PHASE_WL);
void setup() {
Serial2.begin(115200);
SimpleFOCDebug::enable(&Serial2);
_delay(3000);
Serial2.println("Start");
// driver config
// power supply voltage [V]
driver.voltage_power_supply = 12;
driver.voltage_limit = 2;
// https://docs.simplefoc.com/bldcdriver6pwm#low-side-current-sensing-considerations-1
//driver.pwm_frequency = 20000;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);
// limiting motor movements
// Open-loop specific?
//motor.current_limit = 2.0f; // [Amps] - if phase resistance defined
motor.voltage_limit = 0.5 * driver.voltage_limit; // [V] - if phase resistance not defined
motor.velocity_limit = 50.0f; // [rad/s]
motor.controller = MotionControlType::velocity_openloop;
motor.useMonitoring(Serial2);
// Useful for fast MCUs
motor.monitor_downsample = 100;
motor.motion_downsample = 4;
// init motor hardware
motor.init();
motor.initFOC(); // Only needed with sensor?
_delay(1000);
}
void loop() {
motor.loopFOC(); // only needed if initFOC or not?
motor.move(analogRead(A_POTENTIOMETER)); // Set target velocity
delayMicroseconds(50);
}
the FOC loop is very time sensitive - you should not print to serial in the loop like this. You could introduce a counter and only to the println every 1000 or 10000 iterations. that will be fine…
on the other hand open-loop mode is a bit sensitive to the loop speed. On a fast MCU like the STM32G431 you should introduce a short delay, like delayMicroseconds(250); Your serial printing was actually causing a delay, probably, but its not a good way to do it because it won’t be very controlled.
open loop mode is quite inefficient compared to FOC control. Without the sensor the controller has no way to detect problems like stall, it doesn’t know the position of the motor. So when you hold the motor it can’t develop much torque
for the same reason, it produces a lot of heat - inefficiency = heat
For a fast MCU also set motor.motion_downsample = 4;
and motor.monitoring_downsample = 100;
You should set the motor.voltage_limit = 0.5 * driver.voltage_limit;
Values around 0.5 should work well.
Thank you for the tips, i updated my code accordingly (also edited the original post).
Now the motor is screeching even when motor.move(0) is executed and it is uncontrollable, it spins randomly with me turning the potentiometer slowly up and down.
Is there any variable which i can adjust a bit and test it with? By the explanation the motor.voltage_limit value should be alright and not for fine adjustments?
EDIT:
Also, i understand that a sensorless is setup is not ideal, but other (e.g. boat, plane, …) escs also get the torque “to” the motor, so a basic usecase like this should be possible, or am i on the “wrong boat”?
no, you’re right in principle… but other ESCs in this domain are normally not doing FOC, just 6-step commutation. They also don’t tend to do well when stalled.
In terms of the screeching, you can definately play with the loop times:
delayMicroseconds(250);
try values between 50 and 1000…
Another thought: do you actually set driver.voltage_limit? you need to set that before setting motor.voltage_limit, like:
I will comment though that for your particular use-case, if you don’t intend to use the CAN-bus or other features of a ESC with a powerful MCU, and you don’t plan to add a sensor for FOC control, then the benefits of SimpleFOC and a configurable ESC might not be that high for you?
In this case an ESC from the RC-driving world, some of which are even water-proof (though I don’t know to what degree) might better suit your purposes? You can typically control that with a simple PWM signal.
Starts ok (still a short stall on very low values, but this is normal i guess)
Freezes at around 1/4 to 1/3 of the potentiometer with noises and shivering
Next i will try to play around with the delay times.
Yes i know , the main idea was that i have more control over the parameters and prevent stalling better with this setup, the other ESCs i have tried were quiet stuttery and stopped mid-thrust for no reason. My last opportunity would be to shrink the thruster propellers quite a bit, which i’m trying to avoid.
Waterproofing is not a problem as the ESCs will be inside a up to 16 bar pressure resistant body. I guess cooling 6 of these bad boys inside a closed container will be another story
EDIT: I forgot to mention, that a CAN or a generic bus integration is also a plus on my list, this will make the wiring easier.
So i tried many values, general i observed this behavior:
Shorter delays (down to 0): The motor spins better but has minimal less torque.
Longer delays (up 750): The motor spins worse, relatively not usable but could a have a bit more torque from my feeling.
Delay up to 1000: Unusable, the motor shows the same behavior like with the Serial.prints
So i dont know where i should go from this, how could it be that such a simple test setup is not working
and for B-G431B-ESC1 delete
-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC (this enables usb on the stm32g431, you dont want that, because one of the pwm pins would be a usb data line).
and you cant use analogRead when you use currenSense. Someone in the forum posted a fix for that, but I didnt get it to work.
I would disable currentSense for a start.
I removed the current sensing completely for now and changed the platformio.ini
This helped a lot! Now it starts really smooth and is really quiet.
The only problem which persists is that it just instantly stops after i turn the potentiometer to around 1/4 and just humms.
Has this maybe something to do with the motor.velocity_limit? I increased it to 50.0f but this didnt changed anything. Or should i get rid of the potentiometer control and use the current sensing instead?
I never used open loop control, just as a quick test.
is 50 your desired velocity?
then map the analogRead value to that.
Just a side question: Did you try the openloop velocity example with serial control?
you can add motor.monitor(); to the loop, and see the target velocity and voltage via serial. Slowly increase target velocity and voltage limit with T and L commands, to see where the limits are (Or use simplefocStudio for that).
Then you can map the potentiometer value like that
x = analogRead(A_POTENTIOMETER);
target_velocity = float(map(x, 1023, 0, 0, 1400))/10;
motor.voltage_limit = (map(x, 1023, 0, 0, 12));
motor.move(target_velocity);
just as example, every motor is different.
I think thats all you can do with openloop control
Shouldnt motor.voltage_limit only be set at the setup phase?
Is there another loop without a sensor that i could try? Sorry but im still not understanding why a basic 0% - 100% without any load is impossible, which a normal ESC can do without problems, there MUST be somthing wrong with what i am trying…
EDIT:
Where in this code should i insert my max. velocity (motor.velocity_limit)?