B-G431B-ESC1 + Platform IO : help needed on soft : not driving

Hi everyone,

Been trying to get a STM Discovery board to work with SimpleFOC in sensorless (FOC or openloop) but with very little succes so far.

I’ve gone through the following :

  • Made sure that the discovery / motor / cabling is all good by driving with the STM motor development SDK ==> works a treat but I cannot find my way through the code to add the control functions I want.

  • Then got the whole VScode / PlatformIO out and followed the B-G431B-ESC1: Beginner guide + I2C guide from ultra robotics, added the board template, all the relevant files etc…

  • Managed to get some code compiling uploaded and running ont the board (just managed to get a Hello World through a Serial.println to make sure it was cycling)

===> But that’s pretty much where the fun stops, nothing seem to even drive the FETs, no significant consumption, obviously no motor rotation or even vibration, nothing…

  • Tried different codes and settled on the one below which seemed to be the closest to working… The PID does get processed when I enter it on the terminal but nothing more…

The main.cpp is as follow

#include <Arduino.h>
#include <SimpleFOC.h>
#include
#include “stm32g4xx_hal.h”

//local variable definitions
float target = 0.0; // used to change currently tested variable
int spinIt = 1; // iterator for the startup
int spinItSpeed = 1500; // rate of the startup, higher = slower
float radPerSec = 0; // driver the motor speed
int mxRads = 0; // max motor speed
int outIt = 0; //used for communication rate iteration

BLDCMotor motor = BLDCMotor(10, .1);
BLDCDriver6PWM driver = BLDCDriver6PWM(A_PHASE_UH, A_PHASE_UL, A_PHASE_VH, A_PHASE_VL, A_PHASE_WH, A_PHASE_WL);

/*controls the motor using the UART.
-g starts the motor and revs up to 300 rad/s,
-s stops the motor,
-and entering a number sets the P in pid to that number
-(currently not useful, but implemented for later tuning)
*/
void serialControl(){
static String received_chars;
while (Serial.available())
{
char inChar = (char)Serial.read();
received_chars += inChar;
if (inChar == ‘\n’)
{
float num = received_chars.toFloat();
if(received_chars == “s\n”){
radPerSec = 0;
mxRads = 0;
received_chars = “”;
Serial.println(“Stopping Motor.”);
break;
}
else if(received_chars == “g\n”){
radPerSec = 0;
mxRads = 300;
received_chars = “”;
Serial.println(“Starting Motor.”);
break;
}
else{
target = num;
Serial.print("PID.P = ");
Serial.println(target);
received_chars = “”;
}
}
}
}

void setup()
{

//initializes the psu and driver
driver.voltage_power_supply = 14.8;
driver.init();

motor.linkDriver(&driver);
motor.voltage_limit = 14.8;
motor.velocity_limit = 2212;

//Sets up openloop FOC
motor.controller = MotionControlType::velocity_openloop;
// set FOC modulation type to sinusoidal
motor.foc_modulation = FOCModulationType::SinePWM;

motor.init();

motor.initFOC();

Serial.begin(1843200);
delay(1000);

}

void loop()
{
//starts the motor moving at radPerSec
motor.loopFOC();
motor.move(radPerSec);
//this loop controls the rate at which the motor speeds up
if (spinIt%spinItSpeed == 0 && radPerSec<mxRads){
radPerSec++;
spinIt = 1;
}
else{
spinIt++;
}

//motor.PID_velocity.P = target;

serialControl();
}

And here’s the platformio.ini :

[env:disco_b_g431b_esc1]
platform = ststm32
board = disco_b_g431b_esc1
framework = arduino
monitor_speed = 115200

build_flags =
-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
-D PIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF
; -D PIO_FRAMEWORK_ARDUINO_USB_HIGHSPEED_FULLMODE

lib_deps =
askuric/Simple FOC@^2.3.4
simplefoc/SimpleFOCDrivers@^1.0.8
lib_archive = false

Thanks for the heads up if anything looks weird…

Hopefully your mosfets are still alive… the full motor.voltage_limit is applied at all times in open loop mode, so it should be much lower, like 0.5V or less. Run it with the STM SDK again to make sure the hardware is ok.

Otherwise your code looks like it should work. I’m no good with PlatformIO, but the fact that the constants passed to BLDCDriver6PWM exist and serial communication works means it’s probably set up correctly.

Once you have it running with current sense, the sensorless flux observer is the way to go for velocity control without a position sensor, although it requires some tedious tuning. Start with the kv and resistance values from the motor’s official specs, adjust the inductance until it runs, and then try adjusting the other two as well to see if you can improve it. Usually inductance is in the area of 0.00005.

Hi dekutree64,

Thanks for the feedback !
I’ve just tried and the MOS seem to have survived :slight_smile: The motor is running well under the STM SDK.

Will try running it with the sensorless flux observer you linked even though I have the feeling the problem is coming before that…

Excellent.

Don’t bother with flux observer until you have open loop working. It seems you’re not getting voltage output at all, which is good in this case since it saved your mosfets.

Try running your code again, just with the voltage limit set to 0.5. Add this to make sure it’s actually trying to output varying voltages:

static uint32_t lastPrintTime = 0;
if (millis() > lastPrintTime + 50) {
  lastPrintTime = millis();
  char string[256];
  sprintf(string, "%i, %i, %i\n", (int)(motor.Ua*1000), (int)(motor.Ub*1000), (int)(motor.Uc*1000));
  Serial.print(string);
}

For real-time output it’s generally better to use sprintf like that instead of separate calls to Serial.print for each variable, since multiple calls to Serial slows it down a lot more. But Arduino’s implementation of sprintf does not support floating point, so you have to multiply by 1000 or whatever to get enough visible precision as an integer.

-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
You have to remove that line.

Hi Dekutree64 and 2hry.

How it went so far :

I did comment (with “;” in case it has an importance) the line :
-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC

However this is one the (many) lines that I copied from a code example without understanding…
What is it supposed to do ?


As for the rest, I did :

  • set the motor.voltage_limit to 0,5
  • Added the bit for the serial communication of the varying voltages

And…

As it turns out, the voltages are not varying…
The terminal is filled with the following line repeating ad infinitum
7400,7573,7226

It does react when I enter a number (which comes back with PID=said number) but nothing else.

If I enter g which is supposed to start the motor (and printing : “Starting motor”) or s supposedly stopping it (and similarly “Stopping Motor”), I get nothing at all, no change from the motor but no feedback on the serial either…

I did comment (with “;” in case it has an importance) the line :
-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC

However this is one the (many) lines that I copied from a code example without understanding…
What is it supposed to do ?

Well, as it turns out, if I i uncomment it, the serial monitor doesn’t output anything…

OK, last update :

I now have varying voltages!
And a singing motor!

But not a rotating one…

Something is wrong in the way the “g” or “s” command is handled in serial so I just set an arbitrary radPerSec value and the voltages started varying and I could hear the motor sing. The frequency of which varies depending on the value I give to radPerSec so everything seems to have some kind of logic there…

However, the values sent on the serial are only varying somewhere between 7200 and 7500… seems a bit odd to me…

Also, the inverter only draws 100mA or else, even if the field is not “synchronized” and the motor doesn’t rotate, I would expect it to draw more than this…

Tried also while commenting the motor.loopFOC(); line in order to go full open loop (not sure about that one) but no change…

Excellent, that is working then. You can play with open loop some more if you want, or move on to flux observer tuning now.

The voltages vary around voltage_power_supply/2. I think the reason the variation is smaller than ±0.5V is because you provided the phase resistance to the BLDCMotor constructor. I forgot open loop mode does voltage-based current limiting, so it’s enforcing the default 2 amp current limit. 2 amps * 0.1 ohms = 0.2V above and below the 7.4V midpoint.

Set up the current sense as shown in the ESC1 example, give BLDCMotor the kv and inductance (try 0.00003 to start), use MotionControlType::velocity and TorqueControlType::foc_current, and see how it goes. It should be safe to increase the current limit once you’re in closed-loop with current sense. But to be cautious, I’d still keep it at 1V for now. Current limit 5 amps. That’s about all the ESC1 can handle continuously without cooling.

Even when it’s working well, velocity target 0 will vibrate slightly and make a bit of noise, so don’t worry about that. Set target 10 or 20 for testing (may need higher voltage limit for 20). If it makes a terrible screeching noise, the inductance is too high or too low. When it’s working, it should have decent torque, and vibrate strongly as it tries to restart if you stall it. If the parameters are only a little bit off, it may spin backward and choppy, or fail to start unless you give it a push by hand.

Oh, and for flux observer, you need to set motor.zero_electric_angle = 0; motor.sensor_direction = Direction::CW; before calling initFOC so it doesn’t try to run calibration.

Hi Dekutree64,

Many thanks for the guidance! It gives me hope that I can make it work !

I’ve added the following line that I’ve borrowed from the B_G431B_ESC1.ino in the examples of the SimpleFOC library :

LowsideCurrentSense currentSense = LowsideCurrentSense(0.003f, -64.0f/7.0f, A_OP1_OUT, A_OP2_OUT, A_OP3_OUT);

However, the code just won’t compile as it seems it doesnt recognize something related to HAL_OPAMP etc… I get this :

c:/users/pcdev/.platformio/packages/toolchain-gccarmnoneeabi/bin/…/lib/gcc/arm-none-eabi/12.3.1/…/…/…/…/arm-none-eabi/bin/ld.exe: .pio/build/disco_b_g431b_esc1/lib49e/Simple FOC/current_sense/hardware_specific/stm32/b_g431/b_g431_mcu.cpp.o: in function _configureOPAMP(OPAMP_HandleTypeDef*, OPAMP_TypeDef*)': b_g431_mcu.cpp:(.text._Z15_configureOPAMPP19OPAMP_HandleTypeDefP13OPAMP_TypeDef+0x22): undefined reference to HAL_OPAMP_Init’
c:/users/pcdev/.platformio/packages/toolchain-gccarmnoneeabi/bin/…/lib/gcc/arm-none-eabi/12.3.1/…/…/…/…/arm-none-eabi/bin/ld.exe: .pio/build/disco_b_g431b_esc1/lib49e/Simple FOC/current_sense/hardware_specific/stm32/b_g431/b_g431_mcu.cpp.o: in function _configureADCLowSide(void const*, int, int, int)': b_g431_mcu.cpp:(.text._Z20_configureADCLowSidePKviii+0x78): undefined reference to HAL_OPAMP_Start’
c:/users/pcdev/.platformio/packages/toolchain-gccarmnoneeabi/bin/…/lib/gcc/arm-none-eabi/12.3.1/…/…/…/…/arm-none-eabi/bin/ld.exe: b_g431_mcu.cpp:(.text._Z20_configureADCLowSidePKviii+0x7e): undefined reference to HAL_OPAMP_Start' c:/users/pcdev/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/12.3.1/../../../../arm-none-eabi/bin/ld.exe: b_g431_mcu.cpp:(.text._Z20_configureADCLowSidePKviii+0x84): undefined reference to HAL_OPAMP_Start’
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\disco_b_g431b_esc1\firmware.elf] Error 1