Hello everyone
When in foc_current mode with InlineCurrentSense() i am controlling a bldc motor setting the target_velocity. I wanted to achieve freewheeling when setting the target_velocity to 0, so i am using the motor.disable() function for it.
While observing the d and q currents in the serial plotter during testing, I noticed that when calling the motor.disable() the current sensing stops completely. Also, it seems that when the current sensing stops, the code saves up the last known current value and remembers it. After that, when restarting the rotation, the motor enables and the current sensing restarts. But for a brief moment after the startup, the driver still remembers the last meassured current value, that was saved up when the current sensing stoped, and uses this value for control. This value is obviously different than the actual current that flows at the startup. This makes the driver and the motor go crazy, and causes a huge overshoot of curent, either positive or negative, as the PID adjust for the actual meassured current. No PID tampering made any difference with this.
The problem exists when the motor.disable() is called at a higher velocity, when the difference between the last meassured current and the actual current is big. When velocity is lower while disableing, the difference between the last meassured and the actual current during startup is smaller, and the problem is less noticable or nonexistent.
I am not sure if that’s the way the library is set up or the problem is on my side, but i dont thinks it’s my code. I ran the same tests while using voltage mode with velocity control, and did not have this problem. Velocity sensing still continues after the motor.disable(), and the driver knows exacly what’s the actual motor velocity and regulates the motor smoothly to the newly set target.
Is there a remedy for this problem, or motor.disable() just can’t be used with current sensing?
Thanks in advance for any help.
My code:
#include <SimpleFOC.h>
#include <SimpleFOCDrivers.h>
#include <encoders/smoothing/SmoothingSensor.h>
#define _MON_TARGET 0b1000000 // monitor target value
#define _MON_VOLT_Q 0b0100000 // monitor voltage q value
#define _MON_VOLT_D 0b0010000 // monitor voltage d value
#define _MON_CURR_Q 0b0001000 // monitor current q value - if measured
#define _MON_CURR_D 0b0000100 // monitor current d value - if measured
#define _MON_VEL 0b0000010 // monitor velocity value
#define _MON_ANGLE 0b0000001 // monitor angle value
float target_velocity;
int analog_read_A0;
float analog_read_A0_filtered;
BLDCMotor motor = BLDCMotor(15);
HallSensor sensor = HallSensor(PB7, PA15, PB6, 15);
SmoothingSensor smooth(sensor, motor);
InlineCurrentSense current_sense = InlineCurrentSense(44.0, PA4, PA5, PA6);
BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PA11, PA10, PF0, PA9, PA12);
Commander command = Commander(Serial);
LowPassFilter filter = LowPassFilter(0.002);
void onTarget(char* cmd) {command.target(&motor, cmd);}
void onPid(char* cmd) {command.pid(&motor.PID_current_d, cmd);}
void onPid1(char* cmd) {command.pid(&motor.PID_current_q, cmd);}
//void onMotor(char* cmd) { command.motor(&motor,cmd);}
// channel A and B callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}
void enableSmoothing(char* cmd) {
float enable;
command.scalar(&enable, cmd);
motor.linkSensor(enable == 0 ? (Sensor*)&sensor : (Sensor*)&smooth);
}
void setup() {
pinMode(PA0, INPUT);
pinMode(PA1, INPUT);
pinMode(PA7, OUTPUT);
digitalWrite(PA7, HIGH);
Serial.begin(2000000);
analogReadResolution(12);
motor.useMonitoring(Serial);
//SimpleFOCDebug::enable(NULL);
sensor.pullup = Pullup::USE_EXTERN;
sensor.init();
sensor.enableInterrupts(doA, doB, doC);
sensor.velocity_max = 61;
smooth.phase_correction = -_PI_6;
motor.linkSensor(&smooth);
driver.voltage_power_supply = 32;
driver.pwm_frequency = 45000;
//driver.dead_zone = 0.005;
//driver.enable_active_high=true;
Serial.print("Driver init ");
if (driver.init())
Serial.println("success!");
else{Serial.println("failed!");
return;}
motor.linkDriver(&driver);
current_sense.linkDriver(&driver);
current_sense.init();
motor.linkCurrentSense(¤t_sense);
motor.voltage_sensor_align = 1;
motor.motion_downsample = 4;
motor.velocity_limit = 61;
motor.phase_resistance = 0.395; // [Ohm]
motor.KV_rating = 30;
motor.voltage_limit = 0.56*driver.voltage_power_supply;
motor.current_limit = 10;
//motor.phase_inductance = 0.002;
motor.torque_controller = TorqueControlType::foc_current;
motor.controller = MotionControlType::velocity;
motor.PID_velocity.P = 2;
motor.PID_velocity.I = 0;
motor.PID_velocity.D = 0.005;
motor.PID_velocity.output_ramp = 200;
motor.LPF_velocity.Tf = 0.03;
//motor.monitor_variables = _MON_CURR_Q | _MON_CURR_D | _MON_VEL;
motor.monitor_variables = _MON_CURR_Q | _MON_CURR_D;
motor.monitor_downsample = 50;
motor.PID_current_d.P= 0.1;
motor.PID_current_d.I = 20;
motor.PID_current_d.D = 0.0003;
motor.PID_current_q.P = 0.01;
motor.PID_current_q.I= 8;
motor.PID_current_q.D = 0.0001;
motor.LPF_current_d.Tf = 0.003;
motor.LPF_current_q.Tf = 0.003;
motor.PID_current_d.limit = motor.voltage_limit;
motor.PID_current_q.limit = motor.voltage_limit;
//motor.PID_current_q.ramp = 100000;
//motor.PID_current_d.ramp = 100000;
//motor.foc_modulation = FOCModulationType::SinePWM;
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
motor.init();
motor.initFOC();
Serial.println("Motor ready.");
command.add('T', onTarget, "target velocity");
//command.add('M', onMotor, "motor");
command.add('D', onPid,"d_current_PID");
command.add('Q', onPid1,"q_current_PID");
command.add('E', enableSmoothing, "enable smoothing");
command.decimal_places = 4;
//command.motor(&motor,"E0");
_delay(100);
}
void loop() {
motor.loopFOC();
//analog_read_A0 = analogRead(PA0);
//analog_read_A0_filtered = filter(analog_read_A0);
//target_velocity = float(map(analog_read_A0_filtered, 0, 4096, 0, 6010))/100;
target_velocity = motor.target;
if (target_velocity <= 0.5f && motor.enabled==1){
motor.disable();
}
if (target_velocity > 0.5f && motor.enabled==0){
motor.enable();
}
motor.move(target_velocity);
motor.monitor();
command.run();
}