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(); } }