Boat thruster with B-G431B-ESC1

Hello from Germany,

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 :slight_smile: ).

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 :frowning:

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);
}

Hi, and welcome to our forums, @skthrow !

A few points about your setup:

  • 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.

See what happens with these changes.

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”? :smiley:

:slight_smile: 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:

driver.voltage_limit = 2;
motor.voltage_limit = 0.5 * driver.voltage_limit;

you can then play with those values, but don’t go too high!

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.

So i added

driver.voltage_limit = 2;

now i am back to:

  • 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 :face_with_peeking_eye:, 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 :slight_smile:

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 :face_with_monocle:

in platformio.ini
lib_archive = false

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.

Yeah good find, I didn’t look at the platformio.ini

That setting is required.

That also explains why the analogRead was working - you’ll have to remove it or the current sensing

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… :no_mouth:

EDIT:
Where in this code should i insert my max. velocity (motor.velocity_limit)?

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);

As with this value the velocity range goes [0,140]? Shouldnt the max value be 500 (instead of 1400)?

You can change it a later time also…

I’m not exactly sure why scaling the voltage limit with the target velocity is helpful in this case though…

Another note about your code is that motor.loopFOC() is only needed in closed loop modes. Leave it out when using open loop.

For a limit of 50, the value ist 500, yes(i divide by 10 to get finer control)
Code is in the loop(x and target voltage declared before setup)

Voltage_limit is scaled, because in openloop with 0 velocity, the current draw is higher with higher voltage_limit.

1 Like