From 06cdfaa251c578ad9c88e6fe1cfe24f12eb85820 Mon Sep 17 00:00:00 2001 From: Michael Moon Date: Mon, 15 Mar 2010 18:27:14 +1100 Subject: [PATCH] a ton of work on the heater PID loop, it's working great now --- mendel/func.sh | 71 ++++++++++++++++++-------- mendel/gcode.c | 8 ++- mendel/machine.h | 1 + mendel/mendel.c | 5 +- mendel/temp.c | 130 ++++++++++++++++++++++++++++++++++++++--------- mendel/temp.h | 6 +++ 6 files changed, 171 insertions(+), 50 deletions(-) diff --git a/mendel/func.sh b/mendel/func.sh index 8b99f55..9ea0afd 100644 --- a/mendel/func.sh +++ b/mendel/func.sh @@ -7,21 +7,21 @@ # # and then used like this: # -# $ arduincmd G1 X100 -# $ arduinocmd M250 +# $ mendel_cmd G1 X100 +# $ mendel_cmd M250 # # {X:4200,Y:0,Z:0,E:0,F:300,c:19334400} # {X:4200,Y:0,Z:0,E:0,F:300,c:0} # Q1/1E -# $ readsym_uint8 mb_head +# $ mendel_readsym_uint8 mb_head # 1 -# $ readsym_target startpoint +# $ mendel_readsym_target startpoint # X: 2100 # Y: 0 # Z: 0 # E: 0 # F: 300 -# $ readsym_mb +# $ mendel_readsym_mb # [0] { # eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0 # flags: 0 @@ -101,13 +101,10 @@ mendel_cmd() { while [ "$REPLY" != "OK" ] do read -u 3 -# if [ "$LN" -ne 0 ] -# then - if [ "$REPLY" != "OK" ] - then - echo "$REPLY" - fi -# fi + if [ "$REPLY" != "OK" ] + then + echo "$REPLY" + fi LN=$(( $LN + 1 )) done ) 3<>/dev/arduino; @@ -123,19 +120,17 @@ mendel_cmd_hr() { while [ "$REPLY" != "OK" ] do read -u 3 -# if [ "$LN" -ne 0 ] -# then - echo "< $REPLY" -# fi + echo "< $REPLY" LN=$(( $LN + 1 )) done ) 3<>/dev/arduino; } mendel_print() { - ( IFS=$'\n' + ( for F in "$@" do + IFS=$'\n' for L in $(< $F) do mendel_cmd_hr "$L" @@ -150,14 +145,25 @@ mendel_readsym() { sym=$1 if [ -n "$sym" ] then - make mendel.sym &>/dev/null - if egrep -q '\b'$sym'\b' mendel.sym + if [[ "$sym" =~ ^(0?x?[0-9A-Fa-f]+)(:([0-9]+))?$ ]] then - ADDR=$(( $(egrep '\b'$sym'\b' mendel.sym | cut -d\ -f1) )) - SIZE=$(egrep '\b'$sym'\b' mendel.sym | cut -d+ -f2) + ADDR=$(( ${BASH_REMATCH[1]} )) + SIZE=$(( ${BASH_REMATCH[3]} )) + if [ "$SIZE" -le 1 ] + then + SIZE=1 + fi mendel_cmd "M253 S$ADDR P$SIZE" else - echo "unknown symbol: $sym" + make mendel.sym &>/dev/null + if egrep -q '\b'$sym'\b' mendel.sym + then + ADDR=$(( $(egrep '\b'$sym'\b' mendel.sym | cut -d\ -f1) )) + SIZE=$(egrep '\b'$sym'\b' mendel.sym | cut -d+ -f2) + mendel_cmd "M253 S$ADDR P$SIZE" + else + echo "unknown symbol: $sym" + fi fi else echo "what symbol?" > /dev/fd/2 @@ -243,3 +249,24 @@ mendel_readsym_mb() { printf "\n}\n"; ENDPERL } + +mendel_heater_pid() { + P=$(mendel_readsym_int16 heater_p) + I=$(mendel_readsym_int16 heater_i) + D=$(mendel_readsym_int16 heater_d) + + PF=$(mendel_readsym_int32 p_factor) + IF=$(mendel_readsym_int32 i_factor) + DF=$(mendel_readsym_int32 d_factor) + + O=$(mendel_readsym_uint8 0x27) + T=$(mendel_cmd M105 | cut -d\ -f2 | cut -d/ -f1) + + echo "P=$P pf=$PF r="$(($P * $PF)) + echo "I=$I if=$IF r="$(($I * $IF)) + echo "D=$D df=$DF r="$(($D * $DF)) + echo "R="$(( $(($P * $PF)) + $(($I * $IF)) + $(($D * $DF)) )) / 1024 + echo "R="$(( $(( $(($P * $PF)) + $(($I * $IF)) + $(($D * $DF)) )) / 1024 )) + echo "R="$(( $(( $(( $(($P * $PF)) + $(($I * $IF)) + $(($D * $DF)) )) / 1024 )) + 128 )) + echo "O=$O T=$T" +} diff --git a/mendel/gcode.c b/mendel/gcode.c index 22713bb..5f25bd6 100644 --- a/mendel/gcode.c +++ b/mendel/gcode.c @@ -528,7 +528,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) { // backup feedrate, move E very quickly then restore feedrate uint32_t f = startpoint.F; startpoint.F = FEEDRATE_FAST_E; - SpecialMoveE(E_STARTSTOP_STEPS, FEEDRATE_FAST_E); + SpecialMoveE(startpoint.E + E_STARTSTOP_STEPS, FEEDRATE_FAST_E); startpoint.F = f; } while (0); break; @@ -541,7 +541,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) { // backup feedrate, move E very quickly then restore feedrate uint32_t f = startpoint.F; startpoint.F = FEEDRATE_FAST_E; - SpecialMoveE(-E_STARTSTOP_STEPS, FEEDRATE_FAST_E); + SpecialMoveE(startpoint.E - E_STARTSTOP_STEPS, FEEDRATE_FAST_E); startpoint.F = f; } while (0); break; @@ -594,6 +594,10 @@ void process_gcode_command(GCODE_COMMAND *gcmd) { if (gcmd->seen_S) i_limit = gcmd->S; break; + // M134- save PID settings to eeprom + case 134: + temp_save_settings(); + break; // M140- echo off case 140: diff --git a/mendel/machine.h b/mendel/machine.h index 947991b..7544434 100644 --- a/mendel/machine.h +++ b/mendel/machine.h @@ -48,6 +48,7 @@ // extruder settings #define TEMP_HYSTERESIS 20 +#define TEMP_RESIDENCY_TIME 60 /* calculated values - you shouldn't need to touch these diff --git a/mendel/mendel.c b/mendel/mendel.c index af114f4..db52340 100644 --- a/mendel/mendel.c +++ b/mendel/mendel.c @@ -85,6 +85,9 @@ void init(void) { // set up clock clock_setup(); + // read PID settings from EEPROM + temp_init(); + // set up default feedrate current_position.F = startpoint.F = next_target.target.F = FEEDRATE_SLOW_Z; @@ -108,7 +111,7 @@ void clock_250ms(void) { if (steptimeout > (30 * 4)) { power_off(); } - else if (temp_get_target() == 0) + else steptimeout++; ifclock(CLOCK_FLAG_1S) { diff --git a/mendel/temp.c b/mendel/temp.c index e8983e6..2046f32 100644 --- a/mendel/temp.c +++ b/mendel/temp.c @@ -18,12 +18,15 @@ #include "temp.h" +#include + #include "machine.h" #include "pinout.h" #include "clock.h" #include "serial.h" #include "sermsg.h" #include "timer.h" +#include "dda.h" uint16_t current_temp = 0; uint16_t target_temp = 0; @@ -32,15 +35,55 @@ int16_t heater_p = 0; int16_t heater_i = 0; int16_t heater_d = 0; -int32_t p_factor = 680; -int32_t i_factor = 18; -int32_t d_factor = 200; -int16_t i_limit = 500; +#define DEFAULT_P 4096 +#define DEFAULT_I 64 +#define DEFAULT_D -12288 +#define DEFAULT_I_LIMIT 3072 +int32_t p_factor = 0; +int32_t i_factor = 0; +int32_t d_factor = 0; +int16_t i_limit = 0; + +int32_t EEMEM EE_p_factor; +int32_t EEMEM EE_i_factor; +int32_t EEMEM EE_d_factor; +int16_t EEMEM EE_i_limit; uint8_t temp_flags = 0; #define TEMP_FLAG_PRESENT 1 #define TEMP_FLAG_TCOPEN 2 +uint8_t temp_residency = 0; + +#define TH_COUNT 8 +uint16_t temp_history[TH_COUNT] __attribute__ ((__section__ (".bss"))); +uint8_t th_p = 0; + +#ifndef ABSDELTA +#define ABSDELTA(a, b) (((a) >= (b))?((a) - (b)):((b) - (a))) +#endif + +void temp_init() { + p_factor = eeprom_read_dword((uint32_t *) &EE_p_factor); + i_factor = eeprom_read_dword((uint32_t *) &EE_i_factor); + d_factor = eeprom_read_dword((uint32_t *) &EE_d_factor); + i_limit = eeprom_read_word((uint16_t *) &EE_i_limit); + + if ((p_factor == 0) && (i_factor == 0) && (d_factor == 0) && (i_limit == 0)) { + p_factor = DEFAULT_P; + i_factor = DEFAULT_I; + d_factor = DEFAULT_D; + i_limit = DEFAULT_I_LIMIT; + } +} + +void temp_save_settings() { + eeprom_write_dword((uint32_t *) &EE_p_factor, p_factor); + eeprom_write_dword((uint32_t *) &EE_i_factor, i_factor); + eeprom_write_dword((uint32_t *) &EE_d_factor, d_factor); + eeprom_write_word((uint16_t *) &EE_i_limit, i_limit); +} + uint16_t temp_read() { uint16_t temp; @@ -87,6 +130,10 @@ uint16_t temp_read() { } void temp_set(uint16_t t) { + if (t) { + steptimeout = 0; + power_on(); + } target_temp = t; } @@ -99,12 +146,8 @@ uint16_t temp_get_target() { } uint8_t temp_achieved() { - if (current_temp >= target_temp) - if ((current_temp - target_temp) < TEMP_HYSTERESIS) - return 255; - if (current_temp < target_temp) - if ((target_temp - current_temp) < TEMP_HYSTERESIS) - return 255; + if (temp_residency >= TEMP_RESIDENCY_TIME) + return 255; return 0; } @@ -146,17 +189,27 @@ void temp_print() { void temp_tick() { if (target_temp) { - uint16_t last_temp = current_temp; + steptimeout = 0; + +// uint16_t last_temp = current_temp; temp_read(); + temp_history[th_p++] = current_temp; + th_p &= (TH_COUNT - 1); + + if (ABSDELTA(current_temp, target_temp) > TEMP_HYSTERESIS) + temp_residency = 0; + else if (temp_residency < TEMP_RESIDENCY_TIME) + temp_residency++; + // if (DEBUG) - // serial_writestr_P(PSTR("T{")); + serial_writestr_P(PSTR("T{")); int16_t t_error = target_temp - current_temp; // if (DEBUG) { - // serial_writestr_P(PSTR("E:")); - // serwrite_int16(t_error); + serial_writestr_P(PSTR("E:")); + serwrite_int16(t_error); // } // PID stuff @@ -173,7 +226,27 @@ void temp_tick() { // derivative // note: D follows temp rather than error so there's no large derivative when the target changes - heater_d = (current_temp - last_temp); +// heater_d = (current_temp - last_temp); + heater_d = current_temp - temp_history[th_p]; + + serial_writestr_P(PSTR(", P:")); + serwrite_int16(heater_p); + serial_writestr_P(PSTR(" * ")); + serwrite_int32(p_factor); + serial_writestr_P(PSTR(" = ")); + serwrite_int32((int32_t) heater_p * p_factor / PID_SCALE); + serial_writestr_P(PSTR(" / I:")); + serwrite_int16(heater_i); + serial_writestr_P(PSTR(" * ")); + serwrite_int32(i_factor); + serial_writestr_P(PSTR(" = ")); + serwrite_int32((int32_t) heater_i * i_factor / PID_SCALE); + serial_writestr_P(PSTR(" / D:")); + serwrite_int16(heater_d); + serial_writestr_P(PSTR(" * ")); + serwrite_int32(d_factor); + serial_writestr_P(PSTR(" = ")); + serwrite_int32((int32_t) heater_d * d_factor / PID_SCALE); // combine factors int32_t pid_output_intermed = ( @@ -184,32 +257,39 @@ void temp_tick() { ) / PID_SCALE ); + serial_writestr_P(PSTR(" # O: ")); + serwrite_int32(pid_output_intermed); + // rebase and limit factors uint8_t pid_output; - if (pid_output_intermed > 127) +// if (pid_output_intermed > 127) +// pid_output = 255; +// else if (pid_output_intermed < -128) +// pid_output = 0; +// else +// pid_output = (pid_output_intermed + 128); + if (pid_output_intermed > 255) pid_output = 255; - else if (pid_output_intermed < -128) + else if (pid_output_intermed < 0) pid_output = 0; else - pid_output = (pid_output_intermed + 128); + pid_output = pid_output_intermed & 0xFF; // if (DEBUG) { - // serial_writestr_P(PSTR(",O:")); - // serwrite_uint8(pid_output); + serial_writestr_P(PSTR(" = ")); + serwrite_uint8(pid_output); // } #ifdef HEATER_PWM HEATER_PWM = pid_output; #else - if (pid_output >= 128) { + if (pid_output >= 8) enable_heater(); - } - else { + else disable_heater(); - } #endif // if (DEBUG) - // serial_writechar('}'); + serial_writestr_P(PSTR("}\n")); } } diff --git a/mendel/temp.h b/mendel/temp.h index 8677bdb..71902fd 100644 --- a/mendel/temp.h +++ b/mendel/temp.h @@ -27,6 +27,12 @@ typedef union { } interpret; } max6675_data_format; +// setup temperature system +void temp_init(void); + +// save PID factors to EEPROM +void temp_save_settings(void); + // read temperature from sensor uint16_t temp_read(void);