B-G431-ESC1 Closed Loop Trouble

Hi all,

I have four each of B-G431-ESC1’s, Tarot TL2955 motors and an AS5047P magnetic encoder connected in ABI mode. I managed to get open loop working, closed loop after a bit of trouble (the issue was the pole pair count) and then even managed to get it working with CAN bus. However, the CAN bus code stopped working, and after tracing my steps back, I realized that now closed loop doesn’t work either. I’m really confused as I’m not at all sure what I changed. The encoder works perfectly fine (when testing, one rotation is 6.28 radians).

In closed loop voltage mode, the motor simply stalls and doesn’t turn in torque or velocity mode, but draws current. In closed loop current mode, the motor doesn’t really draw much current, and the PWM signals are not 120 degrees apart (maybe like 30 degrees). I initially did PID tuning for voltage mode, but my values don’t work anymore, and I don’t think I can really tune it again as nothing is turning.

Below is the code I’m using for closed loop velocity. I’d appreciate any help.

#include <SimpleFOC.h>




// BLDC motor & driver instance

BLDCMotor motor = BLDCMotor(12);

BLDCDriver6PWM driver = BLDCDriver6PWM(A_PHASE_UH, A_PHASE_UL, A_PHASE_VH, A_PHASE_VL, A_PHASE_WH, A_PHASE_WL, PB11); // set your pins




// encoder instance

Encoder encoder = Encoder(PB6, PB7, 1000);

// channel A and B callbacks

void doA(){encoder.handleA();}

void doB(){encoder.handleB();}




// instantiate the commander

Commander command = Commander(Serial);

void doMotor(char* cmd) { command.motor(&motor, cmd); }

void onPID(char* cmd){ command.pid(&motor.PID_velocity, cmd); }

void onLPF(char* cmd){ command.lpf(&motor.LPF_velocity, cmd); }

void onMotion(char* cmd){ command.motion(&motor, cmd); }




float max_velocity = 100.0;                       // rad/s

float motor_frequency_hz = max_velocity / (2 * PI); // ~16 Hz

float filter_cutoff_hz = motor_frequency_hz * 5;    // ~80 Hz





static uint32_t last = micros();

//static uint32_t count = 0;*/




void setup() { 

  // use monitoring with serial 

Serial.begin(115200);

  // enable more verbose output for debugging

  // comment out if not needed

  SimpleFOCDebug::enable(&Serial);




  //added, add to documentation why

motor.PID_velocity.P = 0.144;

motor.PID_velocity.I = 1;

motor.PID_velocity.D = 0;

motor.LPF_velocity.Tf = 0.01;

motor.P_angle.P = 20;

motor.PID_velocity.output_ramp = 200;




  // Tf = 1 / (2 * PI * f_cutoff)

  //motor.LPF_velocity.Tf = 1.0 / (2.0 * PI * filter_cutoff_hz); 

motor.velocity_limit = max_velocity;

motor.voltage_limit = 2;

  // initialize encoder sensor hardware

encoder.init();

encoder.enableInterrupts(doA, doB); 

  // link the motor to the sensor

motor.linkSensor(&encoder);




  // driver config

  // power supply voltage [V]

driver.voltage_limit = 6;

driver.voltage_power_supply = 12;

  // driver init

if(!driver.init()){

Serial.println("Driver init failed!");

return;

}

  // link driver

motor.linkDriver(&driver);




  // aligning voltage

motor.voltage_sensor_align = 2;




  // set motion control loop to be used

motor.torque_controller = TorqueControlType::voltage;

motor.controller = MotionControlType::torque;




  // comment out if not needed

motor.useMonitoring(Serial);

  // initialize motor

if(!motor.init()){

Serial.println("Motor init failed!");

return;

}

  // align sensor and start FOC

if(!motor.initFOC()){

Serial.println("FOC init failed!");

return;

}




  // set the initial motor target

motor.target = 0; // Volts 




  // add target command M

command.add('M', doMotor, "Motor");




Serial.println(F("Motor ready."));

Serial.println(F("Set the target using serial terminal and command M:"));




Serial.print("P_angle.P = ");

Serial.println(motor.P_angle.P);




Serial.print("PID_velocity.P = ");

Serial.println(motor.PID_velocity.P);




Serial.print("PID_velocity.I = ");

Serial.println(motor.PID_velocity.I);




Serial.print("Velocity limit = ");

Serial.println(motor.velocity_limit);




_delay(1000);

}




void loop() {

  // main FOC algorithm function

motor.loopFOC();




  // Motion control function

motor.move();




  // user communication

command.run();

}

I think, you are choking the motorcontroller. Powersupply is 12V, but you reduce driver voltage to 6V, then cut the motorvoltage even more by limitting it to 2V. That's OK for openloop initialisation, but later you don't allow headroom for the PID. Try 12V driver-limit, 2V for motor_align and 6V motor.voltage_limit. Have some faith in FOC

Sorry, I was out on vacation last week. Thanks for your response! I tried but I only have a 3A power supply, and it just reaches that and squeals. I would think of getting a higher current power supply, but the weird thing is that it was working perfectly before with the same setup. The estimated poles that is calculated during initialization is not constant and jumps around, could that be a factor?

3 Answers

3

I tried increasing motor.voltage_limit, but it didn’t make any difference. In voltage open loop, it simply went to 3A (my power supply maximum) and then squealed. In current open loop (torque control) it simply doesn’t draw any current despite being commanded to take 1,2,3 A. I would try more current, but I don’t think that is the issue as it was working with the same setup before. Something that might be helpful is that the pole count that is generated from initialization fails, its around 14 at 1.5V initialization, and around 9 without a limit (but it hits the 3A ceiling when initializing). Also, it doesn’t spin even in simple torque mode.

Here is my current code if that helps:

#include <SimpleFOC.h>


#define   POLE_PAIRS        12

#define   PHASE_RESISTANCE  0.168

#define   KV_RATING         330

#define   INDUCTANCE_Q      NOT_SET   // optional - can be left as NOT_SET for basic use


BLDCMotor motor = BLDCMotor(POLE_PAIRS, PHASE_RESISTANCE, KV_RATING, INDUCTANCE_Q);

// TODO instance driver

BLDCDriver6PWM driver = BLDCDriver6PWM(A_PHASE_UH, A_PHASE_UL, A_PHASE_VH, A_PHASE_VL, A_PHASE_WH, A_PHASE_WL); // set your pins



// TODO instance sensor

Encoder encoder = Encoder(PB6, PB7, 1000);

void doA(){encoder.handleA();}

void doB(){encoder.handleB();}

static uint32_t last = micros();


Commander command = Commander(Serial);

void doMotor(char* cmd) { command.motor(&motor, cmd); }


void setup() {

Serial.begin(115200);

SimpleFOCDebug::enable(&Serial);

encoder.init();

encoder.enableInterrupts(doA, doB);

motor.linkSensor(&encoder);


driver.voltage_power_supply = 12; // set voltage [V]

driver.init();

motor.linkDriver(&driver);

motor.voltage_sensor_align = 1.5;

// Estimated current control

motor.controller = MotionControlType::torque;

motor.torque_controller = TorqueControlType::estimated_current;

motor.updateCurrentLimit(3.0); // A

motor.target = 0.0;            // A - zero torque command to start


if(!motor.init()) { Serial.println("Motor init failed"); return; }

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


command.add('M', doMotor, "Motor");

_delay(1000);

}




void loop() {

motor.loopFOC();

motor.move();

command.run();

}

40xx motors are usually 11pp, so double check that yours actually has 24 rotor magnets.

I’d go opposite from o_lampe and use low motor.voltage_limit until you get it to move reliably so you can use TorqueControlType::voltage which is the simplest and most reliable. estimated_current can be fairly tricky to get running well, and there’s no need for it when you have current sense. But no point complicating things with current sense if voltage mode won’t spin.

Make sure open loop velocity still spins. If not, it’s probably a physical problem rather than software.

Thanks for your response. On the data sheet it says that there are 24 rotor magnets, and when I originally set it up, moving from 11 to 12 was what made it work. In open loop, 12 works better than 11 too.

I understand that using TorqueControlType::voltage and setting motor.controller to torque mode is the simplest, and the motor should simply spin and have that amount of torque. However, my motor doesn’t spin, it rotates a little and freezes. Open loop velocity still spins until around 20 rad/s where it hits the current limit. Is there a way I can debug why it doesn’t spin in voltage torque control?