Hi,

I want to add auto tune feature for the new board and I need your help on the software side. If there is anybody who want to help me on developing auto tune feature for new gnexlab controller boards write a comment below. We can team up and develop it quickly. I copy the Marlin firmware autotune function below. This can be a good starting point. I also know there are PID auotune libs for Arduino Looking for people who has experience.

 

 


void PID_autotune(float temp, int extruder, int ncycles) {
float input = 0.0;
int cycles = 0;
bool heating = true;

millis_t temp_ms = millis(), t1 = temp_ms, t2 = temp_ms;
long t_high = 0, t_low = 0;

long bias, d;
float Ku, Tu;
float Kp = 0, Ki = 0, Kd = 0;
float max = 0, min = 10000;

#if HAS_AUTO_FAN
millis_t next_auto_fan_check_ms = temp_ms + 2500;
#endif

if (extruder >= EXTRUDERS
#if !HAS_TEMP_BED
|| extruder < 0
#endif
) {
SERIAL_ECHOLN(MSG_PID_BAD_EXTRUDER_NUM);
return;
}

SERIAL_ECHOLN(MSG_PID_AUTOTUNE_START);

disable_all_heaters(); // switch off all heaters.

if (extruder < 0)
soft_pwm_bed = bias = d = MAX_BED_POWER / 2;
else
soft_pwm[extruder] = bias = d = PID_MAX / 2;

// PID Tuning loop
for (;;) {

millis_t ms = millis();

if (temp_meas_ready) { // temp sample ready
updateTemperaturesFromRawValues();

input = (extruder < 0) ? current_temperature_bed : current_temperature[extruder]; max = max(max, input); min = min(min, input); #if HAS_AUTO_FAN if (ms > next_auto_fan_check_ms) {
checkExtruderAutoFans();
next_auto_fan_check_ms = ms + 2500;
}
#endif

if (heating && input > temp) {
if (ms > t2 + 5000) {
heating = false;
if (extruder < 0) soft_pwm_bed = (bias - d) >> 1;
else
soft_pwm[extruder] = (bias - d) >> 1;
t1 = ms;
t_high = t1 - t2;
max = temp;
}
}

if (!heating && input < temp) { if (ms > t1 + 5000) {
heating = true;
t2 = ms;
t_low = t2 - t1;
if (cycles > 0) {
long max_pow = extruder < 0 ? MAX_BED_POWER : PID_MAX; bias += (d * (t_high - t_low)) / (t_low + t_high); bias = constrain(bias, 20, max_pow - 20); d = (bias > max_pow / 2) ? max_pow - 1 - bias : bias;

SERIAL_PROTOCOLPGM(MSG_BIAS); SERIAL_PROTOCOL(bias);
SERIAL_PROTOCOLPGM(MSG_D); SERIAL_PROTOCOL(d);
SERIAL_PROTOCOLPGM(MSG_T_MIN); SERIAL_PROTOCOL(min);
SERIAL_PROTOCOLPGM(MSG_T_MAX); SERIAL_PROTOCOLLN(max);
if (cycles > 2) {
Ku = (4.0 * d) / (3.14159265 * (max - min) / 2.0);
Tu = ((float)(t_low + t_high) / 1000.0);
SERIAL_PROTOCOLPGM(MSG_KU); SERIAL_PROTOCOL(Ku);
SERIAL_PROTOCOLPGM(MSG_TU); SERIAL_PROTOCOLLN(Tu);
Kp = 0.6 * Ku;
Ki = 2 * Kp / Tu;
Kd = Kp * Tu / 8;
SERIAL_PROTOCOLLNPGM(MSG_CLASSIC_PID);
SERIAL_PROTOCOLPGM(MSG_KP); SERIAL_PROTOCOLLN(Kp);
SERIAL_PROTOCOLPGM(MSG_KI); SERIAL_PROTOCOLLN(Ki);
SERIAL_PROTOCOLPGM(MSG_KD); SERIAL_PROTOCOLLN(Kd);
/*
Kp = 0.33*Ku;
Ki = Kp/Tu;
Kd = Kp*Tu/3;
SERIAL_PROTOCOLLNPGM(" Some overshoot ");
SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
Kp = 0.2*Ku;
Ki = 2*Kp/Tu;
Kd = Kp*Tu/3;
SERIAL_PROTOCOLLNPGM(" No overshoot ");
SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
*/
}
}
if (extruder < 0) soft_pwm_bed = (bias + d) >> 1;
else
soft_pwm[extruder] = (bias + d) >> 1;
cycles++;
min = temp;
}
}
}
#define MAX_OVERSHOOT_PID_AUTOTUNE 20
if (input > temp + MAX_OVERSHOOT_PID_AUTOTUNE) {
SERIAL_PROTOCOLLNPGM(MSG_PID_TEMP_TOO_HIGH);
return;
}
// Every 2 seconds...
if (ms > temp_ms + 2000) {
int p;
if (extruder < 0) { p = soft_pwm_bed; SERIAL_PROTOCOLPGM(MSG_B); } else { p = soft_pwm[extruder]; SERIAL_PROTOCOLPGM(MSG_T); } SERIAL_PROTOCOL(input); SERIAL_PROTOCOLPGM(MSG_AT); SERIAL_PROTOCOLLN(p); temp_ms = ms; } // every 2 seconds // Over 2 minutes? if (((ms - t1) + (ms - t2)) > (10L * 60L * 1000L * 2L)) {
SERIAL_PROTOCOLLNPGM(MSG_PID_TIMEOUT);
return;
}
if (cycles > ncycles) {
SERIAL_PROTOCOLLNPGM(MSG_PID_AUTOTUNE_FINISHED);
const char* estring = extruder < 0 ? "bed" : "";
SERIAL_PROTOCOLPGM("#define DEFAULT_"); SERIAL_PROTOCOL(estring); SERIAL_PROTOCOLPGM("Kp "); SERIAL_PROTOCOLLN(Kp);
SERIAL_PROTOCOLPGM("#define DEFAULT_"); SERIAL_PROTOCOL(estring); SERIAL_PROTOCOLPGM("Ki "); SERIAL_PROTOCOLLN(Ki);
SERIAL_PROTOCOLPGM("#define DEFAULT_"); SERIAL_PROTOCOL(estring); SERIAL_PROTOCOLPGM("Kd "); SERIAL_PROTOCOLLN(Kd);
return;
}
lcd_update();
}
}