Hi guys,
I have a question about position control that is most likely related to PID parameters tuning. I have a fully working motor setup in closed loop angle mode. The position control works ok, it just always seems to slow down dramatically before reaching the desired position.
It makes like 80% of the entire movement rather fast and than takes about the same amount of time for the remaining 20%. It looks like this:
I tried changing both velocity PID controller parameters and angle PID (only P and low pass filter constant). I also played with output_ramp setting, but nothing seems to reslove this.
Higher P values obviously make it go to the right position quicker, but at a cost of a relatively noticeable overshoot (which is not very acceptable for me)…
The curve looks something like this (orange one):
I borrowed the graph from this post.
I would like to get as close to the blue one as possible. Ideally make it behave
similarly to the open loop position control, which works super well and looks like this:
For completeness I am posting my closed loop code
#include <SimpleFOC.h>
// --- ENCODER ---
MagneticSensorI2C sensor(AS5600_I2C);
// --- DRIVER ---
#define INH_A 6
#define INH_B 5
#define INH_C 3
#define ENABLE A1
#define M_PWM 4
#define OC_ADJ A0
BLDCDriver3PWM driver(INH_A, INH_B, INH_C, ENABLE);
// --- BLDC MOTOR ---
#define POLE_PAIRS 20
BLDCMotor motor(POLE_PAIRS);
void setup()
{
Serial.begin(115200);
SimpleFOCDebug::enable();
sensor.init();
motor.linkSensor(&sensor);
// external driver setup
pinMode(M_PWM, OUTPUT);
digitalWrite(M_PWM, HIGH);
pinMode(OC_ADJ, OUTPUT);
digitalWrite(OC_ADJ, HIGH);
// set driver voltage
driver.voltage_power_supply = 20.0f;
driver.init();
motor.linkDriver(&driver);
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
// set torque control loop type and controller
motor.controller = MotionControlType::angle;
motor.torque_controller = TorqueControlType::voltage;
motor.voltage_sensor_align = 0.6f;
motor.voltage_limit = 2.5f;
// velocity PID tuning (+ velocity limits)
motor.PID_velocity.P = 1.1f;
motor.PID_velocity.I = 6.0f;
motor.PID_velocity.D = 0.01f;
motor.PID_velocity.output_ramp = 300;
motor.LPF_velocity.Tf = 0.2f;
motor.velocity_limit = 8.0f;
// angle PID tuning
motor.P_angle.P = 4.0f;
motor.P_angle.I = 0.0f;
motor.P_angle.D = 0.0f;
motor.P_angle.output_ramp = 15;
motor.LPF_angle.Tf = 0.001f;
// foc properties obtained through torque mode
motor.sensor_direction = Direction::CW;
motor.zero_electric_angle = 1.91f;
motor.target = 0.0f;
motor.init();
motor.initFOC();
}
void loop()
{
if (Serial.available() > 0)
{
// PID tuning through serial line
char component = Serial.read();
float num = Serial.parseFloat();
switch (component)
{
case 'P':
motor.P_angle.P = num;
break;
case 'I':
motor.P_angle.I = num;
break;
case 'D':
motor.P_angle.D = num;
break;
case 'R':
motor.P_angle.output_ramp = num;
break;
case 'F':
motor.LPF_angle.Tf = num;
break;
case 'T':
motor.target = num;
break;
default:
break;
}
Serial.print("P: ");
Serial.println(motor.P_angle.P, 3);
Serial.print("I: ");
Serial.println(motor.P_angle.I, 3);
Serial.print("D: ");
Serial.println(motor.P_angle.D, 3);
Serial.print("R: ");
Serial.println(motor.P_angle.output_ramp);
Serial.print("Tf: ");
Serial.println(motor.LPF_angle.Tf, 3);
Serial.print("Target: ");
Serial.println(motor.target);
Serial.println();
}
motor.loopFOC();
motor.move();
}
What I tried before posting this:
- tuning the velocity mode separately (works very nice except changing speeds by setting motor.target. It just jerks to the new speed)
- trying various P constants for angle mode (higher than 4 makes it overshoot, which is quite low compared to examples)
- Measuring Atmega328p loops/second (I get around 700Hz with I2C set to 400kHz fast mode)
- Repositioning the sensor and checking the magnet (correct magnet positioned as precisely as possible with 0.75mm gap between magnet and sensor)
- Increasing motor’s voltage_limit
- Increasing low pass filter time constant for both angle and velocity PID controller… Makes it even less responsive
- Changing AS5600 polling time to “always on”
- Enjoying nice movement of open loop
Yeah, I tried a couple of things, but everything seems to make just worse, not better.
I would like to mention that I am using voltage_torque controller because my driver does not support current sensing right now. Could this be the issue?
I feel like this should be purely caused by the PID not being tuned correctly, but I spent more time than I am willing to admit on changing those.
Did anyone experience similar issues? I will appreciate every help now .
Thanks,
Adam!