Weak Torque in Voltage based position Control using B-G431B-ESC1

I have SimpleFOC setup of

  1. 5010 BLDC Motor (7 Pole Pair, 360KV)
  2. B-G431B-ESC1 Driver
  3. AS5600 Sensor

I am trying to do Position control with Voltage Control mode.

The issue I am facing is that the motor is going to target position 6/10 times,
rest 4/10 times it just doesn’t move after entering target in the terminal and then when I give just a little push to motor with my finger, it comes to the target angle by itself.

the resisting force by motor is felt very weak on my fingers.
It is consuming so less voltage and current to apply torque to comeback to it target position while I have entered in the code that use full 12Volts.
What Should I change for it to apply more torque.

In the closeloop velocity voltage control test, the PID value were working properly was
motor.PID_velocity.P = 0.1;
motor.PID_velocity.I = 2.0;
motor.PID_velocity.D = 0.0;

Now, in close loop voltage based position control, it gives a good results than Previous values.
motor.PID_velocity.P = 1.2; ( increasing above 1.2 it start oscillating)
motor.PID_velocity.I = 40.0;
motor.PID_velocity.D = 0.0;

Increasing I value above 50 it starts little bit overshooting, but start no improvement torque.
The force I fee in fingers by motor has no difference.

I am from a mechanical background and have limited electronics/control knowledge, please correct me if I am misunderstanding something.

I have attached my code, terminal output, and a video showing the issue. Any suggestions would be greatly appreciated!

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_FULL_MODE
lib_deps = 
	https://github.com/simplefoc/Arduino-FOC
	simplefoc/SimpleFOCDrivers@^1.0.9

Main -

#include <Arduino.h>
#include <SimpleFOC.h>
#include <Wire.h>

// ---------------- I2C ----------------
TwoWire Wire1(PB7, PB8);
MagneticSensorI2C sensor(AS5600_I2C);

// ---------------- Motor ----------------
BLDCMotor motor = BLDCMotor(7, 0.21f, 360); // pole pairs, phase resistance, KV

// ---------------- Driver ----------------
BLDCDriver6PWM driver(
  A_PHASE_UH, A_PHASE_UL,
  A_PHASE_VH, A_PHASE_VL,
  A_PHASE_WH, A_PHASE_WL
);

// ---------------- Control Variables ----------------
float target = 0.0;
float zero_offset = 0.0;
bool motor_enabled = false;

// ---------------- Commander ----------------
Commander command = Commander(Serial2);

// ---------------- Debug ----------------
unsigned long lastPrint = 0;
int printInterval = 500;

// ==========================================================
// ---------------- COMMANDS ----------------
// ==========================================================

void doTarget(char* cmd) {
  float deg = atof(cmd);
  target = deg * _PI / 180.0;

  Serial2.print("Target(deg): ");
  Serial2.println(deg);
}

void doZero(char* cmd) {
  zero_offset = motor.shaftAngle();
  Serial2.println("Zero position SET!");
}

void doEnable(char* cmd) {
  motor_enabled = true;

  // Sync target → prevents jerk
  target = motor.shaftAngle() - zero_offset;

  Serial2.println("Motor ENABLED");
}

void doDisable(char* cmd) {
  motor_enabled = false;
  motor.move(0);
  Serial2.println("Motor DISABLED");
}

// Voltage = torque control
void doTorque(char* cmd) {
  command.scalar(&motor.voltage_limit, cmd);
}

// Limits
void doVelocity(char* cmd) {
  command.scalar(&motor.velocity_limit, cmd);
}

// PID tuning
void doVP(char* cmd) { command.scalar(&motor.PID_velocity.P, cmd); }
void doVI(char* cmd) { command.scalar(&motor.PID_velocity.I, cmd); }
void doVD(char* cmd) { command.scalar(&motor.PID_velocity.D, cmd); }
void doAP(char* cmd) { command.scalar(&motor.P_angle.P, cmd); }

// ==========================================================
// ---------------- SETUP ----------------
// ==========================================================

void setup() {

  Serial2.begin(115200);
  delay(1000);

  Serial2.println("==== CLEAN ACTUATOR CONTROL ====");

  // I2C
  Wire1.begin();
  sensor.init(&Wire1);
  motor.linkSensor(&sensor);

  // Driver
  driver.voltage_power_supply = 12;
  driver.pwm_frequency = 20000;

  if (!driver.init()) {
    Serial2.println("Driver init failed!");
    return;
  }

  motor.linkDriver(&driver);

  // ---------------- CONTROL MODE ----------------
  motor.torque_controller = TorqueControlType::voltage;
  motor.controller = MotionControlType::angle;

  // ---------------- LIMITS ----------------
  motor.voltage_limit = 12.0;   
  motor.velocity_limit = 25;

  // ---------------- ALIGNMENT ----------------
  motor.voltage_sensor_align = 1.5;  // voltage to apply to the motor for sensor alignment RANGE: [0, supply voltage]
  motor.sensor_direction = Direction::CCW;

  // ---------------- VELOCITY LOOP (MOST IMPORTANT) ----------------
  motor.PID_velocity.P = 1.2;
  motor.PID_velocity.I = 40.0;
  motor.PID_velocity.D = 0.02;

  // Allow fast torque response
  motor.PID_velocity.output_ramp = 1000;

  // Filtering
  motor.LPF_velocity.Tf = 0.01;

  // ---------------- ANGLE LOOP ----------------
  motor.P_angle.P = 50.0;
  motor.LPF_angle.Tf = 0.01;

  // ---------------- MONITOR ----------------
  motor.useMonitoring(Serial2);
  motor.monitor_downsample = 100;


  // ---------------- INIT ----------------
  if (!motor.init()) {
    Serial2.println("Motor init failed!");
    return;
  }

  if (!motor.initFOC()) {
    Serial2.println("FOC init failed!");
    return;
  }

  motor_enabled = false;

  // ---------------- COMMANDS ----------------
  command.add('T', doTarget);
  command.add('Z', doZero);
  command.add('E', doEnable);
  command.add('X', doDisable);

  command.add('C', doTorque);
  command.add('V', doVelocity);

  command.add('P', doVP);
  command.add('I', doVI);
  command.add('D', doVD);
  command.add('A', doAP);

  Serial2.println("====== READY ======");
  Serial2.println("Z       → set zero");
  Serial2.println("E       → enable");
  Serial2.println("X       → disable");
  Serial2.println("T <deg> → move");
  Serial2.println("C <V>   → torque");

  delay(1000);
}



void loop() {

  motor.loopFOC();

  if (motor_enabled) {
    // Correct usage (no hacks)
    motor.move(target + zero_offset);
  }

  command.run();

  // -------- Debug --------
  if (millis() - lastPrint > printInterval) {

    float angle = motor.shaftAngle() - zero_offset;

    Serial2.print("Target: ");
    Serial2.print(target * 180.0 / _PI);

    Serial2.print(" | Angle: ");
    Serial2.print(angle * 180.0 / _PI);

    Serial2.print(" | Vel: ");
    Serial2.print(motor.shaftVelocity());

    Serial2.print(" | Volt: ");
    Serial2.print(motor.voltage.q);

    Serial2.print(" | Enabled: ");
    Serial2.print(motor_enabled);

    Serial2.println();

    lastPrint = millis();
  }

  motor.monitor(); // Print target angle, Voltage, velocity, current angle
}

Outputs-

4 Answers

4

I haven’t spotted the problem yet, but watch it with that voltage limit. ESC1 can only handle about 5 amps continuously, so keep motor.voltage_limit = 1 until you get it running reliably with current sense.

And even then, 6V is the highest you can use without waveform saturation with FOCModulationType::SinePWM, or 7V with SpaceVectorPWM. The motor voltage gets multiplied by sin/cos which range -1 to +1, so 6V motor limit ranges ±6V around the power supply center.

Keep an eye (or finger) on the motor temperature too. My 620kv 5010’s resistance is 0.07 and it can only handle around 5 amps continuously without getting uncomfortably hot to touch, which equates to about 0.6V on yours when stalled or running open loop.

Thanks, dekutree64. Got it. I'll keep motor.voltage_limit below 6 and experiment with different P and I values. Initially, I increased volt_limit above 3 to get more torque, but it didn't help. The heating occurs only in closed-loop velocity control at different RPMs. The maximum current is about 0.5 A, and the motor gets hot after 10–15 minutes. But in Voltage based Position control my motor or driver never gets hot. I've seen online same motor work in volt control with a DRV8308 board. In my case it control works, but the torque is too low to overcome the motor's magnetic poles.

Why do you use voltage mode and not estimated_current?
If 0.21ohm is the REAL phase to neutral value (not phase2phase) and you’ve checked that 360kV is correct, you can set motor.current_limit to a reasonable value and try. (much safer IMHO than voltage mode)

thanks phase resistance of my motor I got from motor profiling using ST MC Workbench i.e. 0.14 but I increased till 0.21 just to see if there improvement in strength, & found that value in someone's example using same motor. I was following as per docs, so 1st trying Volt control then go to current control. I also tried current control it partial worked & then destroyed 2 ESCs trying it (will do separate post on it). So, I stepped back to volt control thinking I am doing something fundamentally wrong. I will check changing few things as per comments, will come back with any updates I found.

I am not sure PIO_FRAMEWORK_ARDUINO_ENABLE_CDC should be used for this board. It was a problem for me in the past.

Thanks Candas. I don't think PIO_FRAMEWORK_ARDUINO_ENABLE_CDC is related to weak torque in volt-based control. As I checked online it is for the USB communication between board & PC. I faced some issue with this board initially, there was nothing showing in the terminal for monitor or cannot give any input when I ran the general examples of simpleFOC. for this board It was not working with serial Serial.begin(115200); Serial.println(); but then it was working changing everywhere Serial2.begin(115200); Serial2.println(); Can share you're motor-sensor setup and reference link which I can read?

https://community.simplefoc.com/t/b-g431b-esc1-discovery-kit-info/274/81?u=candas1

Thankyou I will check trying this too.

This looks like it could easily be an electrical zeroing issue.