Welcome! Log In Create A New Profile

Advanced

RFC: Marlin mod: extruder pid feed forward and lag

Posted by svanteg 
RFC: Marlin mod: extruder pid feed forward and lag
June 03, 2014 05:12PM
Here is an initial crude and incomplete hack to add feed forward and lag to enable nulling out extruder temp variation from extruding plastic. The method is to calculate the amount of "new" plastic fed into the extruder per PID tick and adding the corresponding heat via feed forward with adjustable lag. I've found that about 110 * e_steps / steps_per_mm applied with a 2 second lag works well with my j-head and ABS - i.e. doing a free air extraction at 150 mm/min shows a flat temperature line and a nice extruder power "mesa" plateau in Repetier host. Existing PID C-term (FF factor) and a new L-term (lag in PID ticks) has been added to enable tuning.

I kindly request the Marlin gods to descend with benevolence onto this conceptual hack with questions, reflections and good advice for a more production level implementation.

The benefit of this thing would be a (slightly) more even extrusion especially at high speeds. Also somewhat improved will be the max possible extrusion speed.

diff -u Z:\Hack\RepRap\Marlin-Marlin_v1_Mendel90\Marlin/Configuration_adv.h ./Configuration_adv.h
--- Z:\Hack\RepRap\Marlin-Marlin_v1_Mendel90\Marlin/Configuration_adv.h	2014-03-27 10:56:54 +0100
+++ ./Configuration_adv.h	2014-06-03 02:47:35 +0200
@@ -23,7 +23,8 @@
   // if Kc is chosen well, the additional required power due to increased melting should be compensated.
   #define PID_ADD_EXTRUSION_RATE
   #ifdef PID_ADD_EXTRUSION_RATE
-    #define  DEFAULT_Kc (1) //heating power=Kc*(e_speed)
+    #define  DEFAULT_Kc (100) //heating power=Kc*(e_speed)
+    #define LPQ_MAX_LEN 50
   #endif
 #endif
 
diff -u Z:\Hack\RepRap\Marlin-Marlin_v1_Mendel90\Marlin/Marlin_main.cpp ./Marlin_main.cpp
--- Z:\Hack\RepRap\Marlin-Marlin_v1_Mendel90\Marlin/Marlin_main.cpp	2014-03-27 10:56:54 +0100
+++ ./Marlin_main.cpp	2014-06-03 02:54:55 +0200
@@ -2576,6 +2584,8 @@
 
         #ifdef PID_ADD_EXTRUSION_RATE
         if(code_seen('C')) Kc = code_value();
+        if(code_seen('L')) lpq_len = code_value();
+        if(lpq_len > LPQ_MAX_LEN) lpq_len = LPQ_MAX_LEN;
         #endif
 
         updatePID();
diff -u Z:\Hack\RepRap\Marlin-Marlin_v1_Mendel90\Marlin/temperature.cpp ./temperature.cpp
--- Z:\Hack\RepRap\Marlin-Marlin_v1_Mendel90\Marlin/temperature.cpp	2014-03-27 10:56:54 +0100
+++ ./temperature.cpp	2014-06-03 03:33:37 +0200
@@ -71,7 +71,12 @@
 #ifdef BABYSTEPPING
   volatile int babystepsTodo[3]={0,0,0};
 #endif
-  
+
+#ifdef PID_ADD_EXTRUSION_RATE
+//TODO: M301 printout
+int lpq_len = 20;
+#endif
+
 //===========================================================================
 //=============================private variables============================
 //===========================================================================
@@ -84,6 +89,12 @@
   static float pTerm[EXTRUDERS];
   static float iTerm[EXTRUDERS];
   static float dTerm[EXTRUDERS];
+#ifdef PID_ADD_EXTRUSION_RATE
+  static long last_position[EXTRUDERS];
+  static float cTerm[EXTRUDERS];
+  static long lpq[LPQ_MAX_LEN];
+  static int lpq_ptr = 0;
+#endif
   //int output;
   static float pid_error[EXTRUDERS];
   static float temp_iState_min[EXTRUDERS];
@@ -407,6 +418,7 @@
 {
   float pid_input;
   float pid_output;
+  long e_position;
 
   if(temp_meas_ready != true)   //better readability
     return; 
@@ -442,7 +454,24 @@
           //K1 defined in Configuration.h in the PID settings
           #define K2 (1.0-K1)
           dTerm[e] = (Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]);
+#ifdef PID_ADD_EXTRUSION_RATE
+          cTerm[e] = 0;
+          if(e == active_extruder) {
+            e_position = st_get_position(E_AXIS);
+            if(e_position > last_position[e]) {
+              lpq[lpq_ptr++] = e_position - last_position[e];
+              last_position[e] = e_position;
+            } else {
+              lpq[lpq_ptr++] = 0;
+            }
+            if(lpq_ptr >= lpq_len) lpq_ptr = 0;
+            cTerm[e] = (lpq[lpq_ptr] / axis_steps_per_unit[E_AXIS]) * Kc;
+          }
+
+          pid_output = constrain(pTerm[e] + iTerm[e] - dTerm[e] + cTerm[e], 0, PID_MAX);
+#else
           pid_output = constrain(pTerm[e] + iTerm[e] - dTerm[e], 0, PID_MAX);
+#endif
         }
         temp_dState[e] = pid_input;
     #else 
@@ -461,7 +490,13 @@
     SERIAL_ECHO(" iTerm ");
     SERIAL_ECHO(iTerm[e]);
     SERIAL_ECHO(" dTerm ");
+#ifndef PID_ADD_EXTRUSION_RATE
     SERIAL_ECHOLN(dTerm[e]);  
+#else
+    SERIAL_ECHO(dTerm[e]);  
+    SERIAL_ECHO(" cTerm ");
+    SERIAL_ECHOLN(cTerm[e]);  
+#endif
     #endif //PID_DEBUG
   #else /* PID off */
     pid_output = 0;
@@ -708,6 +743,9 @@
 #ifdef PIDTEMP
     temp_iState_min[e] = 0.0;
     temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki;
+#ifdef PID_ADD_EXTRUSION_RATE
+    last_position[e] = 0;
+#endif
 #endif //PIDTEMP
 #ifdef PIDTEMPBED
     temp_iState_min_bed = 0.0;
diff -u Z:\Hack\RepRap\Marlin-Marlin_v1_Mendel90\Marlin/temperature.h ./temperature.h
--- Z:\Hack\RepRap\Marlin-Marlin_v1_Mendel90\Marlin/temperature.h	2014-03-27 10:56:54 +0100
+++ ./temperature.h	2014-06-03 02:54:55 +0200
@@ -65,6 +65,10 @@
 #ifdef BABYSTEPPING
   extern volatile int babystepsTodo[3];
 #endif
+
+#ifdef PID_ADD_EXTRUSION_RATE
+extern int lpq_len;
+#endif
   
 //high level conversion routines, for use outside of temperature.cpp
 //inline so that there is no performance decrease.
Re: RFC: Marlin mod: extruder pid feed forward and lag
June 04, 2014 05:33AM
Quote
svanteg
The method is to calculate the amount of "new" plastic fed into the extruder per PID tick and adding the corresponding heat via feed forward with adjustable lag. I've found that about 110 * e_steps / steps_per_mm applied with a 2 second lag works well with my j-head and ABS - i.e. doing a free air extraction at 150 mm/min shows a flat temperature line and a nice extruder power "mesa" plateau in Repetier host. Existing PID C-term (FF factor) and a new L-term (lag in PID ticks) has been added to enable tuning.

Sounds very interesting. Why the delay, though? Others suggest such an adaptive additional heat injection should actually happen before extrusion. Calculating things in advance is always tricky, of course, but at least going without delay might be better.

One thing not to forget is, you don't measure nozzle temperature, you measure thermistor temperature. I didn't run comparisons, but likely it makes a big difference wether the thermistor is on the same side of the nozzle or on the opposite side. And getting heat from the heater to the nozzle to the thermistor takes some time, of course.

Quote
svanteg
I kindly request the Marlin gods to descend with benevolence [...]

Teacup firmware is well know for its substantial research into algorithms and well proven implementations. Can I invite you to apply this code there? Currently another guy is working on better temperature control, you might want to join efforts: Teacup Issue 74


Generation 7 Electronics Teacup Firmware RepRap DIY
     
Re: RFC: Marlin mod: extruder pid feed forward and lag
June 04, 2014 09:53PM
To see why lag is needed try a free air extrusion that takes at least 20 seconds to run. In Marlin you will want to turn on PID debugging to see the temperature updates at full speed. You will see that the temp does not change immediately - for the reason you guessed - the cooling needs to reach the temistor before it can be seen, essentially the detection delay. So you need to time the heat pulse so the contribution cancels out the termistor cooling to avoid having the PID step in and regulate. So the lag is specific to the extruder design. FF basically removes the PID cycle time.

If you could measure actual extrudate temperature (not even the extruder tip, but actual plastic) then you would see zero-ish lag. But then the PID cycle time could be cranked up so fast that I suspect FF would not be really meaningful.

In theory you would want the heat pulse to arrive at the tip just as you feed new plastic - but then the PID will start to fight the heating as it has not yet seen the cooling (at least with the same tip - heating element - termistor topology I have). Off the top of my head one could try feeding in the FF at T - [heating lag] and compensate the detected temperature by the calculated aggregated heat pulse + drop waveform seen by the termistor at T + [detection lag]. So you'd need two configurable lags plus a configurable waveform...tricky. Even more so on a limited system like the arduino.

Let me think about working on Teacup... I browsed part of the discussion and I have a few reflections and thoughts that basically boils down to:
* switch to type C PID - it's wind up free. See e.g. Types of PID algorithms
* It is tricky to attempt to clean up Process Value (PV) noise just so D can be used - worst case you're masking signal, best case you need to slow down the PID cycle time just a little since filtering adds to the real-event-to-detected-signal-delay.
* PID needs a PV sample rate that is about 10 to 100 times the total process cycle time to avoid time step induced ringing or oscillation. Pushing up the sample rate let's you get away with more and simpler filtering without killing your transient response. Note that you can have a slower CO update rate. Per above I am guessing that the process cycle time for my extruder is in the two second ballpark indicating - at least - 200ms sample rate. With e.g. ten times oversampling and averaging around 20ms is needed. Reality will bring compromises but this gives some perspective...

Design-wise (and also applicable to marlin):
* abstract the PID code away from it's controlling and controlled object and have some assignment/mapping mechanism to link these
* use a Set Point (SP) filter (to smooth changes in set point) to allow more aggressive PID parameters. Basically an agressive PID will overshoot and ring some which is a problem at turn on (zero to 245 degrees step change will cause overshoot that might kill e.g. a J-head). Limiting dSP/dT below the PID self oscillation limit bring back control and allows optimal cycle time.

...plus more that I will have to follow up on at another time.
Re: RFC: Marlin mod: extruder pid feed forward and lag
June 05, 2014 12:59PM
In Marlin there's an AUTOTEMP feature in the planner that increases the temperature SP proportionally to the highest E speed in the move buffer.

Part of the lag might be in the transfer function from the tip temperature to the thermistor temperature, but a significant part of the dead-time/process time constant is in the heater to tip/thermistor. It does seem like a feed-forward term should lead the process rather than lag it, anticipating the heat-load required by the expected disturbance, leaving the PID to clean up any discrepancies. My hotend heats pretty slow, tau=8s or so for heating. Maybe I should measure the the tau for cooling due to extrusion, which very well could be a different number so I could think about these better. I'd really suspect that the extrusion would remove the heat from the system instantaneously in the form of the hot plastic extruded and cold plastic introduced to the melt chamber, while the heat added to the system would lag depending on the conduction form the heater to the plastic.

The windup-free isn't particular to type C-PIDs--the differential forms in type A, B and C are all windup-free only as long as you constrain the CO output value to feasible values, since the integration and windup-limiting is done in the CO variable. (See the paragraph after the def of type C.) The differential forms will depend on the Ki term being tuned well,

The differential forms depend on differencing measurements of PV(k), which might be a problem with higher sampling rates and any noise--the 1/4C descretization in Teacup and in Marlin maybe 300/2^14 post-oversampling. The base ADC resolution of maybe 1/2C-per count at working temperatures in both firmwares might provide a limit on what can be resolved for the differential PID terms. With 20ms sampling in Teacup, the real, un-noisy process would need to change at rates of 12.5C/s to for the dPV and the Kp, Kd terms to be non-zero and active. With 16X oversampling, maybe Marlin might need a noise-free slope of more than 1.5C/s for non-zero dPV terms. Since at operating temperatures, the slopes might be considerably less, it seems like the integral term would do all of the work, and would require good tuning.

Wait... if the resolution of temperature and temperature slope measurement limits the effectiveness of the Kp and Kd terms, then the only thing that can un-windup the CO integration is the kI term when it overshoots the setpoint. For my slow hotend in Teacup, I think the differential C-PID could ramp up to max power based on Ki, then similarly ramp back down after overshoot.

Also, be careful to maintain the CO integral in something in high enough resolution to actually accumulate the Ki*dPV/dt terms, if it is descretized (soft_pwm in 0-127 in Marlin, pid_output 0-255 in Teacup), you would lose the small adjustments.
Re: RFC: Marlin mod: extruder pid feed forward and lag
June 06, 2014 01:35AM
Interesting, informative and I think we agree on most aspects.

Quote
DaveX
In Marlin there's an AUTOTEMP feature in the planner that increases the temperature SP proportionally to the highest E speed in the move buffer.

I have not tried this yet so I might have misunderstood. However my understanding of it is not to regulate a desired set temperature but rather change the temperature based on flow of plastic (which follows speed) to generally enable higher speeds by temporarily reducing the viscosity of plastic. So in my mind this is not internal to regulation, rather it depends on some useful level of regulation to achieve higher extrusion speed.

Quote
DaveX
It does seem like a feed-forward term should lead the process rather than lag it, anticipating the heat-load required by the expected disturbance, leaving the PID to clean up any discrepancies.

I agree - but we have to separate the ideal physics from the detectable reality from the artifacts of the PID algorithm to keep the discussion straight.

The practical physics gives that heat flux happens "immediately" at the point it is applied - as draw away by filament from the extruder whereever it contacts or as added heat at the element. This sets up a temperature gradient that propagates out at some speed. Ideally we want to modulate the filament-extruder interface area temperature to make the plastic leaving the tip to have a controlled and homogenous enough temperature. The faster we melt plastic, the higher the surface-to-core temperature gradient we need to set up in the incoming filament to balance the heat propagation speed and conduction in the plastic. At some point the filament surface will phase-change into vapour and the heat conduction will drop drastically. That's one limit. Another that might happen sooner is that we cannot melt it through fast enough so we get too much solid plastic casuing blockage - even if the average temperature would indicate melted plastic.

In practice we see this all happening through the sensor which is some distance away from both the filament-extruder interface as well as the the element. On top of that we have the PID regulation delay.

Our current best norm in regulation uses PID to control the temperature at the sensor - accepting that PID will start to regulate when it sees a change and taking some time to null that out depending on the measured physical process cycle time.

A first order improvement is to keep the strategy to regulate at the sensor, hitting it with a heat pulse from the element timed to coincide with the cooling pulse drawn away by the filament. This way the PID sees no change and does not try to regulate - and we've removed the PID regulation delay (still having the element to filament propagation delay). Depending on the sensor-element-barrel topology, the filament either gets more or less than the ideal for a brief moment. The benefits are that the PID is now free to regulate external disturbances - and if they are slower than the dTemp caused by a filament extrusion pulse we can have more aggressive regulation at the same risk of overshoot / ringing. Also we don't need to mess with the PID implementation. This is what I am currently going for.

The ideal improvement strategy is to regulate at the extruder-filament interface - which implies generating a heat pulse before moving filament. Since we're now not regulating at the sensor we will get some waveform there as the heat and cooling pulses pass. If the PID sees this it will start to regulate - essentially generating noise - so we want to hide this in some way by adding the perfectly timed inverse wave form to the sensor reading. Perhaps this is achievable but I don't think very practical since it will be much harder to calibrate and need more assets to implement.

(Thought: if one would arrange the element, the sensor and the barrel so that a heat pulse would arrive at the barrel wall at the same time as the sensor outputs it and same for a cooling pulse, one would get the ideal performance from the "first order" solution above. I am guessing that the ideal geometry places the sensor between the element and the barrel. I think this is a more practical direction to investigate than the software route.)

The sanity check is that the current scope of speeds we can practically use is primarily limited by blobbing caused by us not having a descent "Advance" solution yet. So the real world improvements by better extrudate temperature control is minor until "everyone" can practically run at ~500mm/s with excellent quality rather than the current ~50mm/s. When we're there I might consider looking at the ideal solution if my thought above does not pan out.

Also, in comparison to motion control where FF is key for optimal performance it usually involves sensing the exact positions over time so it is practical to implement the ideal. In our terms it would be similar to having a temp sensor right at the exit measuring the actual cross section average temperature with zero time lag.

Quote
DaveX
The windup-free isn't particular to type C-PIDs...

Yes, thanks for pointing that out.

Quote
DaveX
if the resolution of temperature and temperature slope measurement limits the effectiveness of the Kp and Kd terms, then the only thing that can un-windup the CO integration is the kI term when it overshoots the setpoint.

Yes, but only relevant if you have very aggressive regulation and PV step events. And I think I want to object a little to the use of "wind-up" here since it seems you're talking about events where CO doesn't hit a limit - i.e. a normal unconstrained regulation event. My understanding of "wind-up" is when CO is sitting at max or min and the integrator keeps on adding in the compensation - when the disturbance is removed the integrator has to "un-wind" all the accumulated compensation. Usually this means that the PID stays at the limit for some while before it resumes regulation. Keeping it in the CO means regulation starts immediately when the disturbance is removed regardless of how long that event was.

With sane parameters CO will come down from e.g. max before PV crosses SP so there should be no or a chosen and controlled overshoot.

Quote
DaveX
The differential forms depend on differencing measurements of PV(k), which might be a problem with higher sampling rates and any noise. ... Also, be careful to maintain the CO integral in something in high enough resolution to actually accumulate the Ki*dPV/dt terms.

A practical strategy when you have lower than desired sensor resolution and noise is to oversample and average. This increases resolution and reduces noise at the cost of higher system load - as long as faster sampling does not mean more noise... Even so you're still bound by how often you need to update CO to maintain stable regulation. The rule of thumb is that CO update rate is ten times the measured physical process cycle time. Any oversampling of the sensor is based off of that.

In your case with an 8s = 0.125Hz cycle time (i.e. fastest possible oscillation period) you would want _at least_ an 1.25Hz CO update rate. if you get 7 bits from the sensor but need 8 you must read the sensor at 2.5Hz. If this leaves you with too much noise you have to up the rate even more - I would aim for 8-16x, so 20-40 Hz sensor sample rate with a 1.25Hz CO update rate. More - up to about 12.5Hz CO with 400Hz sensor sample rate - will improve PID stability.

All internal variables must of course be stored at least at the precision of the input, internal calculations and accumulated data to provide the best possible results from the data at hand. Floats are convenient especially with a generalized PID module, otherwise fixed point or scaled integers if necessary. I.e. I would prefer keeping PID CO in a float and convert to actual CO for output.
Re: RFC: Marlin mod: extruder pid feed forward and lag
June 07, 2014 02:06PM
Quote
svanteg
Interesting, informative and I think we agree on most aspects.

Quote
DaveX
In Marlin there's an AUTOTEMP feature in the planner that increases the temperature SP proportionally to the highest E speed in the move buffer.

I have not tried this yet so I might have misunderstood. However my understanding of it is not to regulate a desired set temperature but rather change the temperature based on flow of plastic (which follows speed) to generally enable higher speeds by temporarily reducing the viscosity of plastic. So in my mind this is not internal to regulation, rather it depends on some useful level of regulation to achieve higher extrusion speed.

I've not tried it either. I think it should apply to the steady-state-steady-flow case as well, and would serve to recognize that you'd have a higher gradient between the sensor and the melting chamber in the higher flow cases.

Quote
svanteg

Quote
DaveX
It does seem like a feed-forward term should lead the process rather than lag it, anticipating the heat-load required by the expected disturbance, leaving the PID to clean up any discrepancies.

I agree - but we have to separate the ideal physics from the detectable reality from the artifacts of the PID algorithm to keep the discussion straight.

The practical physics gives that heat flux happens "immediately" at the point it is applied - as draw away by filament from the extruder whereever it contacts or as added heat at the element. This sets up a temperature gradient that propagates out at some speed. Ideally we want to modulate the filament-extruder interface area temperature to make the plastic leaving the tip to have a controlled and homogenous enough temperature. The faster we melt plastic, the higher the surface-to-core temperature gradient we need to set up in the incoming filament to balance the heat propagation speed and conduction in the plastic. At some point the filament surface will phase-change into vapour and the heat conduction will drop drastically. That's one limit. Another that might happen sooner is that we cannot melt it through fast enough so we get too much solid plastic casuing blockage - even if the average temperature would indicate melted plastic.

In practice we see this all happening through the sensor which is some distance away from both the filament-extruder interface as well as the the element. On top of that we have the PID regulation delay.

Our current best norm in regulation uses PID to control the temperature at the sensor - accepting that PID will start to regulate when it sees a change and taking some time to null that out depending on the measured physical process cycle time.

A first order improvement is to keep the strategy to regulate at the sensor, hitting it with a heat pulse from the element timed to coincide with the cooling pulse drawn away by the filament. This way the PID sees no change and does not try to regulate - and we've removed the PID regulation delay (still having the element to filament propagation delay). Depending on the sensor-element-barrel topology, the filament either gets more or less than the ideal for a brief moment. The benefits are that the PID is now free to regulate external disturbances - and if they are slower than the dTemp caused by a filament extrusion pulse we can have more aggressive regulation at the same risk of overshoot / ringing. Also we don't need to mess with the PID implementation. This is what I am currently going for.

The ideal improvement strategy is to regulate at the extruder-filament interface - which implies generating a heat pulse before moving filament. Since we're now not regulating at the sensor we will get some waveform there as the heat and cooling pulses pass. If the PID sees this it will start to regulate - essentially generating noise - so we want to hide this in some way by adding the perfectly timed inverse wave form to the sensor reading. Perhaps this is achievable but I don't think very practical since it will be much harder to calibrate and need more assets to implement.

(Thought: if one would arrange the element, the sensor and the barrel so that a heat pulse would arrive at the barrel wall at the same time as the sensor outputs it and same for a cooling pulse, one would get the ideal performance from the "first order" solution above. I am guessing that the ideal geometry places the sensor between the element and the barrel. I think this is a more practical direction to investigate than the software route.)

The sanity check is that the current scope of speeds we can practically use is primarily limited by blobbing caused by us not having a descent "Advance" solution yet. So the real world improvements by better extrudate temperature control is minor until "everyone" can practically run at ~500mm/s with excellent quality rather than the current ~50mm/s. When we're there I might consider looking at the ideal solution if my thought above does not pan out.

Also, in comparison to motion control where FF is key for optimal performance it usually involves sensing the exact positions over time so it is practical to implement the ideal. In our terms it would be similar to having a temp sensor right at the exit measuring the actual cross section average temperature with zero time lag.

If you know that you are extruding 1.08gram/cc ABS with 1.4J/gram*K as 0.4mm dia. filament at 50mm/s, or (0.5/2)^2*pi*50/10^3=0.01J/s/K, across a 240-25=215K temperature difference you should be able to add 2.1J/s or 2.1W to the idle process, which would be about 10% of a 20W heater resistor, or 25/255 PWM counts to the CO. For 500mm/s, a 20W heater wouldn't be able to keep up, since you'd have a heating load of about 21W in the extrusion. A 40W heater would need to vary its CO about 50% full scale to handle the difference between 0mm/s and 500mm/s extrusion speeds.

I'd expect some lags in the the transition from 0mm/s to full speed and back to 0, but I'd also expect the mass of the extruder, which seem to have a 2-10s time constant, to damp sub-second idle periods away. At extrudate speeds of 500mm/s, I'd expect the transition cycles to be even shorter. I guess I think that if you lag the heater behind the measured/computed/actual position of the filament already extruded, in the case of sensors on the far side of the hole, the heat pulse is doomed to lag the cooling pulse. So to get the lags right, you'd need to drive the feed forward process with the planned disturbances in the motion planning queue.

Feed forward seems like an ideal solution for this, but the first-order improvement on the existing system might just be a plain feed-forward COcounts/mm, or COcounts/mm/K parameter, without a lead or lag, that folks could calculate and apply, or merely copy. Measuring the and tuning for the lags seems ripe for mismeasurements.

Quote
svanteg


Quote
DaveX
The windup-free isn't particular to type C-PIDs...

Yes, thanks for pointing that out.

Quote
DaveX
if the resolution of temperature and temperature slope measurement limits the effectiveness of the Kp and Kd terms, then the only thing that can un-windup the CO integration is the kI term when it overshoots the setpoint.

Yes, but only relevant if you have very aggressive regulation and PV step events. And I think I want to object a little to the use of "wind-up" here since it seems you're talking about events where CO doesn't hit a limit - i.e. a normal unconstrained regulation event. My understanding of "wind-up" is when CO is sitting at max or min and the integrator keeps on adding in the compensation - when the disturbance is removed the integrator has to "un-wind" all the accumulated compensation. Usually this means that the PID stays at the limit for some while before it resumes regulation. Keeping it in the CO means regulation starts immediately when the disturbance is removed regardless of how long that event was.

With sane parameters CO will come down from e.g. max before PV crosses SP so there should be no or a chosen and controlled overshoot.


I guess I think of integrator windup when the integrator causes unexpected overshoot. If, in Marlin, the integrator winds up to its maximum, max(CO), then the integrator won't come down from max(CO) until e=SP-PV=e < 0. In Teacup, the integrator is limited by default to 384 (C/4)(s/4) or 24C*s which is easy to max-out against, (for example, more than 1 second at SP-24) but this makes it behave as a PD controller with droop above power levels above kI*384/255, or 75% in the Ki=0.5 default case. Below that level, it could wind up to 75%CO in less than a second, and not begin to come down from there until it overshoots the setpoint. I think sane, conservative tunings designed for no-overshoot will 'wind-up' to more than the steady-state process level, causing overshoot, if they are given a long enough ramp-up time.

This happens with sane-ish, zielger-nichols values in Marlin: See the overshoot and oscillations in the second graph of [numbersixreprap.blogspot.com] -- The PID started from 10C below SP, cooled because of non-bumpless transition, overshot because of windup.

In the non differential forms, with the constraint on the CO after the summing, then the only negative terms which can pull down the are from the differential term. In the velocity forms, the proportional term is negative with positive dPV/dt, which if the slope is below the limits of detection, won't get applied.

Quote
svanteg

Quote
DaveX
The differential forms depend on differencing measurements of PV(k), which might be a problem with higher sampling rates and any noise. ... Also, be careful to maintain the CO integral in something in high enough resolution to actually accumulate the Ki*dPV/dt terms.

A practical strategy when you have lower than desired sensor resolution and noise is to oversample and average. This increases resolution and reduces noise at the cost of higher system load - as long as faster sampling does not mean more noise... Even so you're still bound by how often you need to update CO to maintain stable regulation. The rule of thumb is that CO update rate is ten times the measured physical process cycle time. Any oversampling of the sensor is based off of that.

In your case with an 8s = 0.125Hz cycle time (i.e. fastest possible oscillation period) you would want _at least_ an 1.25Hz CO update rate. if you get 7 bits from the sensor but need 8 you must read the sensor at 2.5Hz. If this leaves you with too much noise you have to up the rate even more - I would aim for 8-16x, so 20-40 Hz sensor sample rate with a 1.25Hz CO update rate. More - up to about 12.5Hz CO with 400Hz sensor sample rate - will improve PID stability.

All internal variables must of course be stored at least at the precision of the input, internal calculations and accumulated data to provide the best possible results from the data at hand. Floats are convenient especially with a generalized PID module, otherwise fixed point or scaled integers if necessary. I.e. I would prefer keeping PID CO in a float and convert to actual CO for output.

If there is some level of noise in the raw signal, it can indeed add information with multiple samples since the distribution of the noise could push the signals across the descretization boundaries of the ADC and you get more or less samples on either side of the boundary. Noise levels above +/-1ADC aren't adding much information, but are passed though the PID as CO noise. With Kp or Kd values in the 20-100 COcounts/(C/s) range, a small bit of noise can produce 90% FS swings in the CO, see [forums.reprap.org] for an example.

With a time constant of 8s, I think my oscillation frequency would be about 1/(2*pi*8s) = 0.02Hz.

Teacup has a 4Hz CO update and sampling rate, and I think Marlin on a 16MHz might be 7.62Hz CO update, 122Hz sampling.

I'm more concerned with the noise-free behavior of the discretized PV signal and the relatively fast sampling rates producing mostly zeros for the velocity form's (PV(k) - PV(k)) and (PV(k)-2(PV(k-1)+PV(k-2)) terms. Without noise, those terms will be zero most of the time due to discretisation in the ADC and not affect the process. With significant noise, and a constraint on CO, they could quickly bump the integrated CO far from the 100%FS or 0%FS bounds. I saw that behavior in Teacup when I tried a backcalculation integration constraint on Teacup, as Triffid Hunter warned about.
Re: RFC: Marlin mod: extruder pid feed forward and lag
June 08, 2014 06:06PM
Quote
DaveX
For 500mm/s, a 20W heater wouldn't be able to keep up, since you'd have a heating load of about 21W in the extrusion. A 40W heater would need to vary its CO about 50% full scale to handle the difference between 0mm/s and 500mm/s extrusion speeds. ...

I guess the community will move to higher power heaters as we become more able to use the higher speeds. My J-head uses about 40% to keep 245 degrees and I _believe_ it's about 40watts so 500mm/s is achievable with the coarsest layer height. Most people would be able to use it for 0.2mm layers though. Regardless it is a bit academic at the moment.

Quote
DaveX
At extrudate speeds of 500mm/s, I'd expect the transition cycles to be even shorter. I guess I think that if you lag the heater behind the measured/computed/actual position of the filament already extruded, in the case of sensors on the far side of the hole, the heat pulse is doomed to lag the cooling pulse. So to get the lags right, you'd need to drive the feed forward process with the planned disturbances in the motion planning queue.

At 500mm/s you will spend most of your time accelerating or decelerating so most of your dynamics is goverened by jerk and acceleration limits. I agree - to get at-the-barrel heat right you need to base FF on the motion planner and, for generic extruders most probably fiddle with the sensor input. If there is a better topology that still works with the first order FF of actual extruded plastic per volume/sec I would think the community would migrate to that pretty quickly. Not sure there is a simple solution though...

Quote
DaveX
See the overshoot and oscillations in the second graph of [numbersixreprap.blogspot.com] -- The PID started from 10C below SP, cooled because of non-bumpless transition, overshot because of windup.

Integral windup is real and annoying and intrinsic to PID. Rather than trying to deal with the symptom, it's better to address the causes. Your example shows what happens when you start a PID away from equilibrium - with any kind of aggressive parameters you will overshoot.

If we treat the settling phase different from the the steady-state phase we can address the initial overshoot with set-point filtering - in addition to the external SP we have an internal SP' where we limit the amount to change over time to stay below what causes overshoot and ringing during settling. On init we set SP' = PV and when the SP = 245 comes we keep SP' at PV + 10 or so, when we approach 245 we roll SP' into SP with progressively smaller steps. That takes care of the initial step SP change and controlled PID settling into steady state. the PID tuning can then focus on the steady state dynamics.

The Marlin solution of full-on until SP - 2 (or so) and then starting the PID causes a guaranteed overshoot and is one reason I'd like to see a cleaner and complete PID implementation. With a controlled settling I'd probably run at 248 rather than 245.

In steady state we address all known and quantifiable disturbances with FF - which implies multiple FF blocks. The other is PV compensation . Right now I'm focussing on FF for the extruder heater, but (when I only had the one 12v PSU) the heat bed with bang-bang caused a steady disturbance which is possible to null out with PV comp. Turning on the fan is also a known disturbance.

The remaining noise is unpredictable and should be practically white - i.e. centered on the median of the true signal.

Quote
DaveX
With Kp or Kd values in the 20-100 COcounts/(C/s) range, a small bit of noise can produce 90% FS swings in the CO, see [forums.reprap.org] for an example.

Yes, and if you have that level of PV noise even with 16x oversampling you have the main options to scale back on the PID coefficients or re-think the sensor-to-input path on your controller. Getting a clean 10-ish bit feed from a thermistor should be a basic design requirement.

Quote
DaveX
I'm more concerned with the noise-free behavior of the discretized PV signal and the relatively fast sampling rates producing mostly zeros for the velocity form's (PV(k) - PV(k)) and (PV(k)-2(PV(k-1)+PV(k-2)) terms. Without noise, those terms will be zero most of the time due to discretisation in the ADC and not affect the process.

If we've removed cooling from extruding plastic; cooling from the fan and regular electronic disturbances - what is left that can make the PID wind up and overshoot? When can we have a noise free signal that is not changing (much) - while not being at SP?

I'm asking because my imagination fails me...
Re: RFC: Marlin mod: extruder pid feed forward and lag
June 09, 2014 03:35PM
This is what I'm imagining: You can have a noise-free signal that doesn't change very much if your process slews by maybe 0.5C/second at full power (or maybe full extrusion), and you are sampling a 0.5C/count ADC (100Kthermistor, with 4.7K pullup, operating at about 200C) with a fast 131ms/16=8ms sampling period. A perfect no-noise ADC would be changing state about once per second, so with Marlin's oversampled 131ms rate, 87% of the samples of the differences of successive samples will be 0C/s, while 13% will be 0.5C. At smaller slopes, the fractions would be smaller. With no noise and oversampling, I'd expect the step to happen somewhere along the sample, so you'd have two steps, one to an intermediate value at n/16 *0.5C, then the following one of the remainder, so 74% zeros and 26% signals of less than 0.5C at maximum heating. Perhaps the proper response would be to reduce the sampling frequency so that significant (+/-1ADC) changes in the input are more visible to the controller.



Marlin's Z-N autotune measures and suggests these values for my hotend:

 bias: 114 d: 114 min: 177.32 max: 182.57
 Ku: 55.32 Tu: 44.83
 Classic PID 
 Kp: 33.19
 Ki: 1.48
 Kd: 186.00

The maximum slope of my system is about +1C/s at room temperature, and about +0.5C/s around a 180C operating temperature. I turn off Kd because most of what it is amplifying at 186counts/(C/s) and injecting into the controlled output is noise. At slower than maximum heating rates and slower, the signal that would drive the deriviative term or the velocity form of the PID is less than the ADC resolution of the sensor.

If integral windup isn't controlled, it doesn't take particularly aggressive parameters to overshoot, just an initial condition far enough from the setpoint that the kI*integral sums up to more than the required steady-state CO. I think you can control integral windup pretty well by not integrating when the CO is at the limits. (See [github.com] and a not-yet-well-tested [github.com] that seems to work on my machine with a PID_FUNCTIONAL_RANGE of +/-300C)

From the questions and responses I see in RepRap about PID, it seems many folks appear to think slow heating in the pre-settiling regime is something that tuning the PID can fix, even though Marlin is BANG_BANG up until SP-10C by default; that noisy control output is just fine, which it is if you let the thermal mass moderate it, but it is sloppy, confusing and counterproductive; and that the overshoot is a problem with the parameters, not a problem with integral windup being partially handled by bandaids like the hard-to-tune PID_FUNCTIONAL_RANGE in Marlin, or the I_LIMIT in Teacup. Marlin has some perverse behavior if the PV *exceeds* SP+PID_FUNCTIONAL_RANGE, in that switches to BANG_BANG off mode, then when restarting the PID resets the integral to zero until the PV drops below SP and can begin accumulating an integral again. I think the CO limit in the velocity forms might have some similar behavior to the CO max limits in Marlin or I_LIMIT in Teacup, but I really haven't tried it.
Re: RFC: Marlin mod: extruder pid feed forward and lag
June 09, 2014 09:23PM
Looks like there used to be a Kc term for adding a term proportional to the extruder speed: [github.com]

But the current_block->speed_e doesn't look like it is available any more.


ETA: Duh. That's the functionality you are building off of.

Edited 1 time(s). Last edit at 06/10/2014 12:30AM by DaveX.
Re: RFC: Marlin mod: extruder pid feed forward and lag
July 17, 2014 06:27PM
This is a very interesting and informative discussion. My feedback & control theory is a bit rusty,
but I'm wondering if it might be easier to make a state-space controller that takes temperature and
feedrate as input, and generates pwm duty cycle as output than to make these complex PID systems.

Anybody tried state space yet?

-- Ralph
Adding PID_ADD_EXTRUSION_RATE to MarlinDev/master
August 30, 2015 10:37PM
Please check out [github.com] for my implementation of PID_ADD_EXTRUSION_RATE based on the example code above. It probably needs some revision, so please give your feedback on the PR, and I will try to make it as solid as possible!


|
| Lead Developer of Marlin Firmware
| Help support my work at Patreon and Elsewhere.
|
Re: Adding PID_ADD_EXTRUSION_RATE to MarlinDev/master
August 31, 2015 04:05PM
Quote
Thinkyhead
Please check out [github.com] for my implementation of PID_ADD_EXTRUSION_RATE based on the example code above. It probably needs some revision, so please give your feedback on the PR, and I will try to make it as solid as possible!

Thanks! I haven't invested the time to learn how to do the github thing so I appreciate the helping hand. Also I am honored to see some of my "code" perhaps making it into Marlin. smiling smiley

I have not reviewed all the new code related to PID vs my old version so I could be missing something. However I changed the Kc default to 100 to get the compensation needed for my hotend to null out the temp droop. As the old Kc had no meaning and was not used the old default of 1 should also be meaningless. So I think you correction is "wrong". However it might be safer to default it to 0 (zero) to have no default feed forward effect when compiled-in but uninitialized and add some comments on what values might work and how to set it up. I set this in my slic3r startup to:

M301 P20.72 I1.78 D60.42 C110 L20	; Set extruder PID 245 degrees

...which works with my standard Mendel90 J-Head. Having the delay mis-timed will exaggerate the disturbance to the PID and probably cause worse performance than standard. I would have to think about the most practical procedure to set it up right for a new user.

One thing I haven't fixed yet is the missing reset for last_position[e] when/if e_position is reset. I think there is one somewhere in the code and when it happens my code will make the CO (pid_output) hit either max or min heating for one pid cycle. The hotend is too slow to react to this appreciably and the PID nulls out the effect anyways - but it should be added before release.
Re: Adding PID_ADD_EXTRUSION_RATE to MarlinDev/master
September 04, 2015 05:35PM
Quote
svanteg
One thing I haven't fixed yet is the missing reset for last_position[e] when/if e_position is reset. I think there is one somewhere in the code...

I've done a global search for (last|e)_position to see where this might be, but I couldn't find anyplace where this should go. Maybe you can point out the line in pid_with_kc/Marlin/temperature.cpp — or maybe everything is as it should be already.

Edited 1 time(s). Last edit at 09/04/2015 05:37PM by Thinkyhead.


|
| Lead Developer of Marlin Firmware
| Help support my work at Patreon and Elsewhere.
|
Re: Adding PID_ADD_EXTRUSION_RATE to MarlinDev/master
September 06, 2015 04:07AM
Quote
Thinkyhead
Quote
svanteg
One thing I haven't fixed yet is the missing reset for last_position[e] when/if e_position is reset. I think there is one somewhere in the code...

I've done a global search for (last|e)_position to see where this might be, but I couldn't find anyplace where this should go. Maybe you can point out the line in pid_with_kc/Marlin/temperature.cpp — or maybe everything is as it should be already.

It was a TODO that I had not started to look at so in that case I think we can leave it...although I would expect some effect when that rolls over. I guess you would have to print quite a lot to have that happen. Thanks a lot for looking!

About a calibration procedure:
  • Turn on PID debugging to see updates at full speed
  • Do the free air extrusion which needs to let the PID react and settle fully - this gives rough target values for timing and Kc
  • Adjust timing and Kc and perform again until minimal PID regulation
  • (Optional: change the firmware defaults for delay and Kc)
  • (Optional: adjust max delay vector to align with chosen delay e.g. from 50 to ~20 in my case - to save on RAM)

If this sound ok, I can go ahead and detail the steps for a code paste in and a link to a post here (or perhaps a github document is better) with more details and examples.
Re: RFC: Marlin mod: extruder pid feed forward and lag
March 15, 2017 01:51PM
IMHO - and I know little to nothing about all the physics involved:
After reading this, my thought is that is requires programming a physic into Marlin. This implementation seems to be based on monitoring the plastic temp, which is near impossible, then adjusting against the wishes of the PID, creating conflict.

It seems to me the function would be better implemented based on speed and better suited for the slicer to handle, since it knows what the temp is set at and when the speed will change and can include a temp change preemptively before a speed change. This would not conflict with the PID and would be based on a variable associated with the extruder - which we may already know from PID calibration.

BTW, when I am watching my print and it speeds up, I manually change the temp to compensate to relieve the pressure on the extruder, which I think is the whole goal. But if this effort is just to maintain the set temp at the nozzle, a nozzle with a preheater might be a viable product. Then the preheater control would also be based on speed, and the slicer is still the best place to handle that.
Using the slicer to control this is fireprevention. Using Marlin is firefighting. Without preheat I think it is not possible to keep a set temp AND relieve extruder pressure.

Edited 2 time(s). Last edit at 03/15/2017 02:23PM by ruggb.
Sorry, only registered users may post in this forum.

Click here to login