Magnetic Filament Monitor for Automatic E-Step Calibration
-
@timschneider this is great! Thanks for sharing it
-
@T3P3Tony
I was even able to push it a little further. The most pain four our customers is the non-linear-extrusion calibration.And what should I say, it is even possible to do that with the MFM
non_linear_extrusion_calibration.gcode
if exists(global.nlecalibration) set global.nlecalibration = true else global nlecalibration = true G10 P0 S235 ; sets the temperature M140 P0 S90 ; set bed temp M107 ; fan off M144 P0 S1 ; activate bed 1 heater T0 ; select tool 0 M98 P"0:/sys/meltingplot/home_if_necessary" ; check homing G29 S1 ; load stored hight map M83 ; use relative distances for extrusion G90 ; use absolute coordinates G21 ; set units to millimeters M116 ; wait for all heaters G11 ; unretract G1 Z300 ; raise z=20mm G53 G1 X50 Y50 F14400 ; move printhead to center G92 E0 ; reset e-steps M572 D0 S0.0 ; disable pressure advance M592 D0 A0.0 B0.0 ; disable non-linear-extrusion M591 D0 P3 C"e1stop" S0 R98:102 E0.2 L25.3 ; enable MFM, but do not trigger event G4 S5 ; wait for restart of MFM G91 ; relative moves ; 15mm G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 ; the mfm should be calibrated now if sensors.filamentMonitors[0].calibrated == null echo "Cannot calibrate filament monitor within 15mm - error!" M99 G4 S1 ; wait for filament monitor send timeout var totalCommandedBase = move.extruders[0].rawPosition var totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F60 G1 X50 E50 F60 G4 S1 ; wait for filament monitor send timeout echo "F60 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F90 G1 X50 E50 F90 G4 S1 ; wait for filament monitor send timeout echo "F90 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F120 G1 X50 E50 F120 G4 S1 ; wait for filament monitor send timeout echo "F120 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F150 G1 X50 E50 F150 G4 S1 ; wait for filament monitor send timeout echo "F150 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X-50 E50 F180 G1 X-50 E50 F180 G4 S1 ; wait for filament monitor send timeout echo "F180 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X-50 E50 F210 G1 X-50 E50 F210 G4 S1 ; wait for filament monitor send timeout echo "F210 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X-50 E50 F240 G1 X-50 E50 F240 G4 S1 ; wait for filament monitor send timeout echo "F240 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X-50 E50 F270 G1 X-50 E50 F270 G4 S1 ; wait for filament monitor send timeout echo "F270 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F300 G1 X50 E50 F300 G4 S1 ; wait for filament monitor send timeout echo "F300 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F330 G1 X50 E50 F330 G4 S1 ; wait for filament monitor send timeout echo "F330 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F360 G1 X50 E50 F360 G4 S1 ; wait for filament monitor send timeout echo "F360 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G10 ; retract G10 P0 R0 S0 ; disable hotend M140 S0 R0 ; set bed heater to 0° M140 P0 S-273.1 ; disable bed heater T-1 ; unselect tool set global.nlecalibration = false
The variable
nlecalibration
is for further use.non_linear_extrusion_check.gcode
if exists(global.nlecheck) set global.nlecheck= true else global nlecheck= true G10 P0 S235 ; sets the temperature M140 P0 S90 ; set bed temp M107 ; fan off M144 P0 S1 ; activate bed 1 heater T0 ; select tool 0 M98 P"0:/sys/meltingplot/home_if_necessary" ; check homing G29 S1 ; load stored hight map M83 ; use relative distances for extrusion G90 ; use absolute coordinates G21 ; set units to millimeters M116 ; wait for all heaters G11 ; unretract G1 Z300 ; raise z=20mm G53 G1 X50 Y50 F14400 ; move printhead to center G92 E0 ; reset e-steps M572 D0 S0.0 ; disable pressure advance M592 D0 A0.003 B0.011 L0.2 ; enable non-linear-extrusion M591 D0 P3 C"e1stop" S0 R98:102 E0.2 L25.3 ; enable MFM, but do not trigger event G4 S5 ; wait for restart of MFM G91 ; relative moves ; 15mm G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 ; the mfm should be calibrated now if sensors.filamentMonitors[0].calibrated == null echo "Cannot calibrate filament monitor within 15mm - error!" M99 G4 S1 ; wait for filament monitor send timeout var totalCommandedBase = move.extruders[0].rawPosition var totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F60 G1 X50 E50 F60 G4 S1 ; wait for filament monitor send timeout echo "F60 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F90 G1 X50 E50 F90 G4 S1 ; wait for filament monitor send timeout echo "F90 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F120 G1 X50 E50 F120 G4 S1 ; wait for filament monitor send timeout echo "F120 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F150 G1 X50 E50 F150 G4 S1 ; wait for filament monitor send timeout echo "F150 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X-50 E50 F180 G1 X-50 E50 F180 G4 S1 ; wait for filament monitor send timeout echo "F180 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X-50 E50 F210 G1 X-50 E50 F210 G4 S1 ; wait for filament monitor send timeout echo "F210 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X-50 E50 F240 G1 X-50 E50 F240 G4 S1 ; wait for filament monitor send timeout echo "F240 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X-50 E50 F270 G1 X-50 E50 F270 G4 S1 ; wait for filament monitor send timeout echo "F270 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F300 G1 X50 E50 F300 G4 S1 ; wait for filament monitor send timeout echo "F300 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F330 G1 X50 E50 F330 G4 S1 ; wait for filament monitor send timeout echo "F330 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G1 X50 E50 F360 G1 X50 E50 F360 G4 S1 ; wait for filament monitor send timeout echo "F360 " ^ {(1.0-((sensors.filamentMonitors[0].calibrated.totalDistance-var.totalDistanceBase)/(move.extruders[0].rawPosition-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = sensors.filamentMonitors[0].calibrated.totalDistance G10 ; retract G10 P0 R0 S0 ; disable hotend M140 S0 R0 ; set bed heater to 0° M140 P0 S-273.1 ; disable bed heater T-1 ; unselect tool set global.nlecheck = false
We have a tool which takes the values from that script and will aproximate the A and B factors of the non-linear-extrusion - but it can be done with excel as well. It will safe you alot of measurements
-
ok, the above code is not correct.
I thought that
sensors.filamentMonitors[0].calibrated.totalDistance
is the total measured distance, but in fact, it is just the total commanded distance and the difference betweensensors.filamentMonitors[0].calibrated.totalDistance
andmove.extruders[0].rawPosition
is for example the non linear extrusion correction.I think it is possible to get the current measured distance in mm with the following line:
(sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev)
and the new code looks like the following:
0:/gcodes/non_linear_extrusion_calibration.gcodeif exists(global.nlecalibration) set global.nlecalibration = true else global nlecalibration = true G10 P0 S235 ; sets the temperature M140 P0 S90 ; set bed temp M107 ; fan off M144 P0 S1 ; activate bed 1 heater T0 ; select tool 0 M98 P"0:/sys/meltingplot/home_if_necessary" ; check homing G29 S1 ; load stored hight map M83 ; use relative distances for extrusion G90 ; use absolute coordinates G21 ; set units to millimeters M116 ; wait for all heaters G11 ; unretract G1 Z300 F3600 ; raise z=20mm G53 G1 X50 Y50 F14400 ; move printhead to center G92 E0 ; reset e-steps M572 D0 S0.0 ; disable pressure advance M592 D0 A0.0 B0.0 ; disable non-linear-extrusion M591 D0 P3 C"e1stop" S0 R98:102 E0.2 L25.3 ; enable MFM, but do not trigger event G4 S5 ; wait for restart of MFM G91 ; relative moves ; 15mm G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 ; the mfm should be calibrated now if sensors.filamentMonitors[0].calibrated == null echo "Cannot calibrate filament monitor within 15mm - error!" M99 G4 S1 ; wait for filament monitor send timeout ; sensors.filamentMonitors[0].calibrated.totalDistance is including extrusion correction like pressure advance, non linear extrusion and so on ... ; move.extruders[0].rawPosition is the extrusion without correction values ; sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev is the number of measured revolutions var totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance var totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F60 G1 X50 E50 F60 G4 S1 ; wait for filament monitor send timeout var currentCommanded = sensors.filamentMonitors[0].calibrated.totalDistance var currentMeasured = (var.currentCommanded / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F60 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance set var.totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F90 G1 X50 E50 F90 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = sensors.filamentMonitors[0].calibrated.totalDistance set var.currentMeasured = (var.currentCommanded / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F90 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance set var.totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F120 G1 X50 E50 F120 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = sensors.filamentMonitors[0].calibrated.totalDistance set var.currentMeasured = (var.currentCommanded / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F120 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance set var.totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F150 G1 X50 E50 F150 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = sensors.filamentMonitors[0].calibrated.totalDistance set var.currentMeasured = (var.currentCommanded / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F150 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance set var.totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F180 G1 X-50 E50 F180 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = sensors.filamentMonitors[0].calibrated.totalDistance set var.currentMeasured = (var.currentCommanded / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F180 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance set var.totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F210 G1 X-50 E50 F210 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = sensors.filamentMonitors[0].calibrated.totalDistance set var.currentMeasured = (var.currentCommanded / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F210 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance set var.totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F240 G1 X-50 E50 F240 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = sensors.filamentMonitors[0].calibrated.totalDistance set var.currentMeasured = (var.currentCommanded / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F240 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance set var.totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F270 G1 X-50 E50 F270 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = sensors.filamentMonitors[0].calibrated.totalDistance set var.currentMeasured = (var.currentCommanded / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F270 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance set var.totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F300 G1 X50 E50 F300 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = sensors.filamentMonitors[0].calibrated.totalDistance set var.currentMeasured = (var.currentCommanded / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F300 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance set var.totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F330 G1 X50 E50 F330 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = sensors.filamentMonitors[0].calibrated.totalDistance set var.currentMeasured = (var.currentCommanded / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F330 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance set var.totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F360 G1 X50 E50 F360 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = sensors.filamentMonitors[0].calibrated.totalDistance set var.currentMeasured = (var.currentCommanded / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F360 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = sensors.filamentMonitors[0].calibrated.totalDistance set var.totalDistanceBase = (var.totalCommandedBase / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G10 ; retract G10 P0 R0 S0 ; disable hotend M140 S0 R0 ; set bed heater to 0° M140 P0 S-273.1 ; disable bed heater T-1 ; unselect tool set global.nlecalibration = false
The output looks like the following:
So i was able to correct the extrusion up to F300 with 2.85mm filament or up to 31.9mm³/s.
-
and the code of
0:/gcodes/non_linear_extrusion_check.gcode
if exists(global.nlecheck) set global.nlecheck = true else global nlecheck = true G10 P0 S240 ; sets the temperature M140 P0 S90 ; set bed temp M107 ; fan off M144 P0 S1 ; activate bed 1 heater T0 ; select tool 0 M98 P"0:/sys/meltingplot/home_if_necessary" ; check homing G29 S1 ; load stored hight map M83 ; use relative distances for extrusion G90 ; use absolute coordinates G21 ; set units to millimeters M116 ; wait for all heaters G11 ; unretract G1 Z300 F3600 ; raise z=20mm G53 G1 X50 Y50 F14400 ; move printhead to center G92 E0 ; reset e-steps M572 D0 S0.0 ; disable pressure advance M592 D0 A0.0 B0.0035 L0.2 ; enable non-linear-extrusion M591 D0 P3 C"e1stop" S0 R98:102 E0.2 L25.3 ; enable MFM, but do not trigger event G4 S5 ; wait for restart of MFM G91 ; relative moves ; 15mm G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 ; the mfm should be calibrated now if sensors.filamentMonitors[0].calibrated == null echo "Cannot calibrate filament monitor within 15mm - error!" M99 G4 S1 ; wait for filament monitor send timeout ; sensors.filamentMonitors[0].calibrated.totalDistance is including extrusion correction like pressure advance, non linear extrusion and so on ... ; move.extruders[0].rawPosition is the extrusion without correction values ; sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev is the number of measured revolutions var totalCommandedBase = move.extruders[0].rawPosition var totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F60 G1 X50 E50 F60 G4 S1 ; wait for filament monitor send timeout var currentCommanded = move.extruders[0].rawPosition var currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F60 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F90 G1 X50 E50 F90 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = move.extruders[0].rawPosition set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F90 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F120 G1 X50 E50 F120 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = move.extruders[0].rawPosition set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F120 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F150 G1 X50 E50 F150 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = move.extruders[0].rawPosition set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F150 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F180 G1 X-50 E50 F180 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = move.extruders[0].rawPosition set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F180 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F210 G1 X-50 E50 F210 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = move.extruders[0].rawPosition set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F210 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F240 G1 X-50 E50 F240 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = move.extruders[0].rawPosition set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F240 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F270 G1 X-50 E50 F270 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = move.extruders[0].rawPosition set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F270 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F300 G1 X50 E50 F300 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = move.extruders[0].rawPosition set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F300 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F330 G1 X50 E50 F330 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = move.extruders[0].rawPosition set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F330 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F360 G1 X50 E50 F360 G4 S1 ; wait for filament monitor send timeout set var.currentCommanded = move.extruders[0].rawPosition set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F360 " ^ {(1.0-((var.currentMeasured-var.totalDistanceBase)/(var.currentCommanded-var.totalCommandedBase)))*100.0} ^ "% error." set var.totalCommandedBase = move.extruders[0].rawPosition set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G10 ; retract G10 P0 R0 S0 ; disable hotend M140 S0 R0 ; set bed heater to 0° M140 P0 S-273.1 ; disable bed heater T-1 ; unselect tool set global.nlecheck = false
-
@timschneider
Nice work
The only issue I can imagine is if at higher speeds the change in the extrusion is due to the extruder skipping steps rather than just changes in extrusion efficiency that M592 is attempting to compensate for.
That problem exists no matter if you measure with a tape or using the filament monitor, but I think using your automatic system users are less likely to pay close attention and will just accept the readings on face value.
It probably doesn't matter as you'll get bad results when printing above the extruders max flow rate.
Maybe just a warning to the user if the error rate is above X% that the max flow rate may have been exceeded or the nozzle is jammed?
I've always wondered on the value of the MFM because I see a few people struggling with them, but this has me thinking it's time to throw out my simple switch -
Over at the simpleFOC forum, we also use the 'AS5xxx' mag sensors a lot and there we struggle with a dead-zone around the turning point (0-360°) where the sensor has an hiccup.
I wonder if RRF has the same issue and found a way to deal with it?
In simpleFOC dev-branch we are experimenting with an interpolating smoothingSensor module, also because the I2C sensor is pretty slow /lags behind.
That's maybe not so relevant for slow extruder moves, though. -
@OwenD said in Magnetic Filament Monitor for Automatic E-Step Calibration:
The only issue I can imagine is if at higher speeds the change in the extrusion is due to the extruder skipping steps rather than just changes in extrusion efficiency that M592 is attempting to compensate for.
That is exactly what happened with the F360 values. My rule of thumb is: try to compensate up to about 10%, because that means the extruder has to push at least 10% more, but in reality it's more like 15-20% more.
As for your other thoughts. I use a different technique to make the sensor more robust, as explained here
-
The above code will only work in standalone mode firmware 3.4.6.
It seems that the G4 S1 is somehow breaking the var scope from time to time (it will stop working at F150 for the first time with unknown variable ) @dc42
so I use global variables for sbc setup.
if exists(global.nlecheck) set global.nlecheck = true else global nlecheck = true G10 P0 S245 ; sets the temperature M140 P0 S90 ; set bed temp M107 ; fan off M144 P0 S1 ; activate bed 1 heater T0 ; select tool 0 M98 P"0:/sys/meltingplot/home_if_necessary" ; check homing G29 S1 ; load stored hight map M83 ; use relative distances for extrusion G90 ; use absolute coordinates G21 ; set units to millimeters M116 ; wait for all heaters G11 ; unretract G1 Z300 F3600 ; raise z=20mm G53 G1 X50 Y50 F14400 ; move printhead to center G92 E0 ; reset e-steps M572 D0 S0.0 ; disable pressure advance M592 D0 A0 B0 ; disable non-linear-extrusion M591 D0 P3 C"io3.in" S0 R98:102 E0.2 L25.3 ; enable MFM, but do not trigger event G4 S5 ; wait for restart of MFM G91 ; relative moves ; 15mm G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 ; the mfm should be calibrated now if sensors.filamentMonitors[0].calibrated == null echo "Cannot calibrate filament monitor within 15mm - error!" M99 M400 G4 S1 ; wait for filament monitor send timeout ; sensors.filamentMonitors[0].calibrated.totalDistance is including extrusion correction like pressure advance, non linear extrusion and so on ... ; move.extruders[0].rawPosition is the extrusion without correction values ; sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev is the number of measured revolutions global totalCommandedBase = move.extruders[0].rawPosition global totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F60 G1 X50 E50 F60 M400 G4 S1 ; wait for filament monitor send timeout global currentCommanded = move.extruders[0].rawPosition global currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F60 " ^ {(1.0-((global.currentMeasured-global.totalDistanceBase)/(global.currentCommanded-global.totalCommandedBase)))*100.0} ^ "% error." set global.totalCommandedBase = move.extruders[0].rawPosition set global.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F90 G1 X50 E50 F90 M400 G4 S1 ; wait for filament monitor send timeout set global.currentCommanded = move.extruders[0].rawPosition set global.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F90 " ^ {(1.0-((global.currentMeasured-global.totalDistanceBase)/(global.currentCommanded-global.totalCommandedBase)))*100.0} ^ "% error." set global.totalCommandedBase = move.extruders[0].rawPosition set global.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F120 G1 X50 E50 F120 M400 G4 S1 ; wait for filament monitor send timeout set global.currentCommanded = move.extruders[0].rawPosition set global.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F120 " ^ {(1.0-((global.currentMeasured-global.totalDistanceBase)/(global.currentCommanded-global.totalCommandedBase)))*100.0} ^ "% error." set global.totalCommandedBase = move.extruders[0].rawPosition set global.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F150 G1 X50 E50 F150 M400 G4 S1 ; wait for filament monitor send timeout set global.currentCommanded = move.extruders[0].rawPosition set global.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F150 " ^ {(1.0-((global.currentMeasured-global.totalDistanceBase)/(global.currentCommanded-global.totalCommandedBase)))*100.0} ^ "% error." set global.totalCommandedBase = move.extruders[0].rawPosition set global.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F180 G1 X-50 E50 F180 M400 G4 S1 ; wait for filament monitor send timeout set global.currentCommanded = move.extruders[0].rawPosition set global.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F180 " ^ {(1.0-((global.currentMeasured-global.totalDistanceBase)/(global.currentCommanded-global.totalCommandedBase)))*100.0} ^ "% error." set global.totalCommandedBase = move.extruders[0].rawPosition set global.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F210 G1 X-50 E50 F210 M400 G4 S1 ; wait for filament monitor send timeout set global.currentCommanded = move.extruders[0].rawPosition set global.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F210 " ^ {(1.0-((global.currentMeasured-global.totalDistanceBase)/(global.currentCommanded-global.totalCommandedBase)))*100.0} ^ "% error." set global.totalCommandedBase = move.extruders[0].rawPosition set global.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F240 G1 X-50 E50 F240 M400 G4 S1 ; wait for filament monitor send timeout set global.currentCommanded = move.extruders[0].rawPosition set global.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F240 " ^ {(1.0-((global.currentMeasured-global.totalDistanceBase)/(global.currentCommanded-global.totalCommandedBase)))*100.0} ^ "% error." set global.totalCommandedBase = move.extruders[0].rawPosition set global.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X-50 E50 F270 G1 X-50 E50 F270 M400 G4 S1 ; wait for filament monitor send timeout set global.currentCommanded = move.extruders[0].rawPosition set global.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F270 " ^ {(1.0-((global.currentMeasured-global.totalDistanceBase)/(global.currentCommanded-global.totalCommandedBase)))*100.0} ^ "% error." set global.totalCommandedBase = move.extruders[0].rawPosition set global.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F300 G1 X50 E50 F300 M400 G4 S1 ; wait for filament monitor send timeout set global.currentCommanded = move.extruders[0].rawPosition set global.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F300 " ^ {(1.0-((global.currentMeasured-global.totalDistanceBase)/(global.currentCommanded-global.totalCommandedBase)))*100.0} ^ "% error." set global.totalCommandedBase = move.extruders[0].rawPosition set global.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F330 G1 X50 E50 F330 M400 G4 S1 ; wait for filament monitor send timeout set global.currentCommanded = move.extruders[0].rawPosition set global.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F330 " ^ {(1.0-((global.currentMeasured-global.totalDistanceBase)/(global.currentCommanded-global.totalCommandedBase)))*100.0} ^ "% error." set global.totalCommandedBase = move.extruders[0].rawPosition set global.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X50 E50 F360 G1 X50 E50 F360 M400 G4 S1 ; wait for filament monitor send timeout set global.currentCommanded = move.extruders[0].rawPosition set global.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "F360 " ^ {(1.0-((global.currentMeasured-global.totalDistanceBase)/(global.currentCommanded-global.totalCommandedBase)))*100.0} ^ "% error." set global.totalCommandedBase = move.extruders[0].rawPosition set global.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G10 ; retract G10 P0 R0 S0 ; disable hotend M140 S0 R0 ; set bed heater to 0° M140 P0 S-273.1 ; disable bed heater T-1 ; unselect tool set global.nlecheck = false
-
ok it took me a little longer to get this up, but this is my current version of the initial automatic filament calibration script.
It will automatically calibrate the e-steps and the non linear extrusion.It will only run in 3.5 and as a macro.
The copyright of the script is
Tim Schneider Meltingplot GmbH CC BY-SA
content of
0:/macros/meltingplot/filament-extrusion-calibration
if !exists(global.ignoreMFMevents) global ignoreMFMevents = true else set global.ignoreMFMevents = true var filamentMonitorPin = "e1stop" var filamentMonitorCircumference = 25.3 var extrusionDistance = 20 ; distance for e-step calibration ; speeds in mm/s for NLE to test var extrusionSpeeds = {0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0} M107 ; fan off T0 ; select tool 0 M98 P"0:/sys/meltingplot/home_if_necessary" ; check homing G29 S1 ; load stored hight map M83 ; use relative distances for extrusion G90 ; use absolute coordinates G21 ; set units to millimeters var currentTool = state.currentTool var currentHeater = tools[0].heaters[var.currentTool] var currentTemp = heat.heaters[var.currentHeater].active if var.currentTemp < 180 || var.currentTemp > 355 set var.currentTemp = 180 M291 P"Please set desired filament temperature" R"Filament Temp" S6 L180 H355 F{var.currentTemp} set var.currentTemp = input G10 P0 S{var.currentTemp} M116 ; wait for all heaters G11 ; unretract G1 Z300 F3600 ; raise z=20mm G53 G1 X50 Y50 F14400 ; move printhead to center G92 E0 ; reset e-steps M220 S100 ; Set speed factor override percentage M221 S100 ; Set extrude factor override percentage M572 D0 S0.0 ; disable pressure advance M592 D0 A0.0 B0.0 ; disable non-linear-extrusion M591 D0 P0 G4 S1 M591 D0 P3 C{var.filamentMonitorPin} S2 R98:102 E0.2 L{var.filamentMonitorCircumference} ; enable MFM on all moves G4 S5 ; wait for restart of MFM G91 ; relative moves ; 15mm G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 ; the mfm should be calibrated now if sensors.filamentMonitors[0].calibrated == null echo "Cannot calibrate filament monitor within 15mm - error!" set global.ignoreMFMevents = false M99 G4 S1 ; wait for filament monitor send timeout ; start e-step calibration var totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X{var.extrusionDistance} E{var.extrusionDistance} F30 G4 S1 ; wait for filament monitor send timeout var currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) var newESteps = {floor(move.extruders[0].stepsPerMm / ((var.currentMeasured-var.totalDistanceBase)/var.extrusionDistance)*100)/100} set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X{var.extrusionDistance} E{var.extrusionDistance} F30 G4 S1 ; wait for filament monitor send timeout set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) set var.newESteps = var.newESteps + {floor(move.extruders[0].stepsPerMm / ((var.currentMeasured-var.totalDistanceBase)/var.extrusionDistance)*100)/100} set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) G1 X{var.extrusionDistance} E{var.extrusionDistance} F30 G4 S1 ; wait for filament monitor send timeout set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) echo "Current E-Steps: " ^ {move.extruders[0].stepsPerMm} set var.newESteps = (var.newESteps + {floor(move.extruders[0].stepsPerMm / ((var.currentMeasured-var.totalDistanceBase)/var.extrusionDistance)*100)/100}) set var.newESteps = floor(var.newESteps / 3.0 * 100)/100 echo "New E-Steps: " ^ var.newESteps echo >{"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-esteps.g"} "; calibration temperature: " ^ var.currentTemp echo >>{"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-esteps.g"} "M92 E" ^ var.newESteps M92 E{var.newESteps} ; activate new e-steps ; start non linear calibration G92 E0 ; reset e-steps ; https://www.bragitoff.com/2018/06/polynomial-fitting-c-program/ ; speed to test var x = var.extrusionSpeeds ; number of data points var N = #var.x ; degree of polynomial var n = 2 ; echo "x: " ^ var.x ; echo "N: " ^ var.N ; echo "n: " ^ var.n ; array to store the y-axis data points var y = vector(var.N, 0.0) ; gather y data points ;set var.y = {0.0, 0.0, 0.0118, 0.0207, 0.0247, 0.0356, 0.0507, 0.0613, 0.0751, 0.0922, 0.1234, 0.1438} M591 D0 P0 G4 S1 M591 D0 P3 C{var.filamentMonitorPin} S2 R98:102 E0.2 L{var.filamentMonitorCircumference} ; enable MFM on all moves G4 S5 ; wait for restart of MFM G91 ; relative moves ; 15mm G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 G1 X1 E1 F30 ; the mfm should be calibrated now if sensors.filamentMonitors[0].calibrated == null echo "Cannot calibrate filament monitor within 15mm - error!" set global.ignoreMFMevents = false M99 G4 S1 ; wait for filament monitor send timeout ; sensors.filamentMonitors[0].calibrated.totalDistance is including extrusion correction like pressure advance, non linear extrusion and so on ... ; move.extruders[0].rawPosition is the extrusion without correction values ; sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev is the number of measured revolutions var i = 0 var first = true var check = false var nle_a = 0 var nle_b = 0 var nn = var.n var success = false var mean_error = 0.0 var min_error = 100.0 var max_error = 0.0 var s = 0.0 while true ; gather y-values for the compensated x-values set var.i = 0 set var.n = var.nn set var.mean_error = 0.0 set var.min_error = 100.0 set var.max_error = 0.0 var errors = vector(var.N, 0.0) while {var.i < var.N} set var.totalDistanceBase = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) var comp_f = var.x[var.i] * 60 if var.check == false && var.first == false set var.comp_f = var.comp_f * (1 + var.y[var.i]) var currentCommanded = 100 G1 X{mod(var.i,2)=0?100:-100} E{var.currentCommanded} F{var.comp_f} G4 S1 ; wait for filament monitor send timeout set var.currentMeasured = (sensors.filamentMonitors[0].calibrated.totalDistance / sensors.filamentMonitors[0].calibrated.mmPerRev * sensors.filamentMonitors[0].configured.mmPerRev) var error = (1.0-((var.currentMeasured-var.totalDistanceBase)/var.currentCommanded)) set var.min_error = min(var.min_error, var.error) set var.max_error = max(var.max_error, var.error) set var.errors[var.i] = var.error echo "F" ^ {var.comp_f} ^ ": " ^ {var.error*100.0} ^ "% error." if var.comp_f < 60 && var.error >= 0.1 echo "The filament error exceeds the expected value at low speed. This may be due to grinding. Repeating!" G1 E-10 F60 ; backoff some filament G1 E15 F60 ; extrude some material to get pass the grinding continue if var.check == false set var.y[var.i] = var.error if var.y[var.i] < 0.01 if var.first == true && var.i < 1 && var.y[var.i] < -0.01 echo "Calibrate E-Steps first." M99 set var.y[var.i] = 0.01 ; if the error is larger than 10% or more than twice as the previous value - stop if var.y[var.i] > 0.1 || ( var.i > 0 && var.y[var.i-1] > 0.025 && var.y[var.i] > (var.y[var.i-1] * 2)) if var.first == true && var.i < 1 echo "Calibrate E-Steps first." M99 set var.N = var.i echo "New N: " ^ var.N break set var.i = var.i + 1 set var.first = false var k = 0 while {var.k < var.N} set var.mean_error = var.mean_error + var.errors[var.k] set var.k = var.k + 1 set var.mean_error = var.mean_error / var.N echo "mean error:" ^ var.mean_error set var.k = 0 set var.s = 0.0 while {var.k < var.N} set var.s = pow(var.errors[var.k] - var.mean_error, 2.0) set var.k = var.k + 1 set var.s = sqrt(var.s / var.N) echo "standard deviation: " ^ var.s if var.check set var.check = false if var.s <= 0.005 set var.success = true break elif var.s > 0.005 && var.s < 0.25 M592 D0 A0 B0 continue else set var.success = false break ; echo "y: " ^ var.y ; an array of size 2*n+1 for storing N, Sig xi, Sig xi^2, ... var X = vector(2*var.n+1, 0.0) ; echo "X: " ^ var.X set var.i = 0 while {var.i <= (2*var.n)} var j = 0 while {var.j < var.N} set var.X[var.i] = var.X[var.i] + pow(var.x[var.j], var.i) set var.j = var.j + 1 set var.i = var.i + 1 ; echo "X: " ^ var.X ; the normal argumented matrix var B = vector(var.n+1, vector(var.n+2, 0.0)) var Y = vector(var.n+1, 0.0) ; echo "B: " ^ var.B ; echo "Y: " ^ var.Y set var.i = 0 while {var.i <= var.n} var j = 0 while {var.j < var.N} set var.Y[var.i] = var.Y[var.i] + pow(var.x[var.j], var.i) * var.y[var.j] set var.j = var.j + 1 set var.i = var.i + 1 ; echo "Y: " ^ var.Y set var.i = 0 while {var.i <= var.n} var j = 0 while {var.j <= var.n} set var.B[var.i][var.j] = var.X[var.i+var.j] set var.j = var.j + 1 set var.i = var.i + 1 ; echo "B: " ^ var.B set var.i = 0 while {var.i <= var.n} set var.B[var.i][var.n+1] = var.Y[var.i] set var.i = var.i + 1 ; echo "B: " ^ var.B var A = vector(var.n+1, 0.0) ; echo "A: " ^ var.A ; gaussEliminationLS var m = var.n + 1 set var.n = var.n + 2 set var.i = 0 while {var.i < (var.m-1)} ;Partial Pivoting set var.k = var.i + 1 while {var.k < var.m} ;If diagonal element(absolute vallue) is smaller than any of the terms below it if abs(var.B[var.i][var.i]) < abs(var.B[var.k][var.i]) ;Swap the rows var j = 0 while {var.j < var.n} var temp = var.B[var.i][var.j] set var.B[var.i][var.j] = var.B[var.k][var.j] set var.B[var.k][var.j] = var.temp set var.j = var.j + 1 set var.k = var.k + 1 ;Begin Gauss Elimination set var.k = var.i + 1 while {var.k < var.m} var term = var.B[var.k][var.i] / var.B[var.i][var.i] var j = 0 while {var.j < var.n} set var.B[var.k][var.j] = var.B[var.k][var.j] - var.term * var.B[var.i][var.j] set var.j = var.j + 1 set var.k = var.k + 1 set var.i = var.i + 1 ;Begin Back-substitution set var.i = var.m - 1 while {var.i >= 0} set var.A[var.i] = var.B[var.i][var.n-1] var j = var.i + 1 while {var.j < (var.n - 1)} set var.A[var.i] = var.A[var.i] - var.B[var.i][var.j] * var.A[var.j] set var.j = var.j + 1 set var.A[var.i] = var.A[var.i] / var.B[var.i][var.i] set var.i = var.i - 1 set var.nle_a = var.A[1] set var.nle_b = var.A[2] M592 D0 A{var.A[1]} B{var.A[2]} L0.2 echo "Test: M592 D0 A" ^ var.nle_a ^ " B" ^ var.nle_b ^ " L0.2" set var.check = true if var.success echo "NLE calibration finished!" echo "M592 D0 A" ^ var.nle_a ^ " B" ^ var.nle_b ^ " L0.2" echo >{"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-nle.g"} "; max F" ^ var.x[var.N-1] * 60 ^ " mm/min or " ^ var.x[var.N-1] * 6.38 ^ "mm³/s" echo >>{"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-nle.g"} "; temp: " ^ var.currentTemp ^ " °C" echo >>{"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-nle.g"} "; mean error: " ^ var.mean_error echo >>{"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-nle.g"} "; min error: " ^ var.min_error echo >>{"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-nle.g"} "; max error: " ^ var.max_error echo >>{"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-nle.g"} "; standard deviation: " ^ var.s echo >>{"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-nle.g"} "M592 D0 A" ^ var.nle_a ^ " B" ^ var.nle_b ^ " L0.2" else echo "NLE calibration falied!" ; end calibration G10 ; retract G10 P0 R0 S0 ; disable hotend M140 S0 R0 ; set bed heater to 0° M144 P0 ; disable bed heater T-1 ; unselect tool M591 D0 P0 ; reset filament sensor M98 P"0:/sys/meltingplot/machine-override" ; Load Machine specific overrides set global.ignoreMFMevents = false
add the following lines to your
0:/sys/filament-error.g
if exists(global.ignoreMFMevents) && global.ignoreMFMevents == true M99
and the following to your filament config
if fileexists({"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-esteps.g"}) M98 P{"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-esteps.g"} if fileexists({"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-nle.g"}) M98 P{"0:/filaments/" ^ {move.extruders[0].filament} ^ "/config-auto-nle.g"}
the macro
M98 P"0:/sys/meltingplot/machine-override"
will reset the filament monitor to its default, so you need to adapt this.sample output
Another thing I would like to add is pressure advance calibration, as I think, it should be possible to determine the stiffness of the filament with the filament monitor and predict the pressure advance value. Maybe somesome can help here?
Btw. this script helped me to write a simple adaptive temp control in correlation to the extrusion speed, which will crank up the extrusion flow rate upto 30% and make the NLE look linear. Maybe something for the firmware @dc42
content of
daemon.g
while true if exists(global.initial_temp) == false global initial_temp = 0 if !exists(global.compensated_temp) global compensated_temp = 0 if !exists(global.is_compensated) global is_compensated = false if !exists(global.filament_extrusion_temp_compensation_factor) global filament_extrusion_temp_compensation_factor = 1 if exists(global.filament_extrusion_temp_compensation) && global.filament_extrusion_temp_compensation if ( {move.currentMove.extrusionRate} > 0 ) if global.initial_temp == 0 || global.compensated_temp != {heat.heaters[1].active} set global.initial_temp = {heat.heaters[1].active} set global.compensated_temp = global.initial_temp + min({move.currentMove.extrusionRate} * global.filament_extrusion_temp_compensation_factor, 100) G10 P0 S{global.compensated_temp} R{global.initial_temp-50} set global.is_compensated = true elif (global.initial_temp != 0 && {heat.heaters[1].active} != 0 && global.is_compensated) G10 P0 S{global.initial_temp} R{global.initial_temp-50} set global.is_compensated = false
if you want to use the temp compensation add the following to your filament config and rerun the auto filament calibration
set global.filament_extrusion_temp_compensation_factor = 8 if !exists(global.filament_extrusion_temp_compensation) global filament_extrusion_temp_compensation = true
-
-
I created this macro to use the mfm to calibrate non linear extrusion. Have done nearly no print tests to see if it actually have a print quality improvement though so feedback would also be appreciated.
; Inputs var tool = param.T var maxSpeed = exists(param.S) ? param.S : 20 var dist = exists(param.D) ? param.D : 20 var minExtrusionThreshold = exists(param.E) ? param.E : 0.85 var force = exists(param.F) ? param.F : 0 ; if > 0, will run macro without confirming with user ; Configuration var baseSpeed = 1 var debug = false ; Internal variables var originalTool = state.currentTool var speeds = {1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1} var speedInc = var.maxSpeed / #var.speeds while (iterations < #var.speeds) set var.speeds[iterations] = var.speedInc * (iterations + 1) var drive = tools[var.tool].filamentExtruder var flows = var.speeds ; must be same length as var.speeds var eMulti = var.speeds ; must be same length as var.speeds var numMeasurements = 0 ; Check with user if (var.force <= 0) var msg = "Would you like to calibrate non linear extrusion for T"^{var.tool}^"? Current coefficients: Base="^move.extruders[var.drive].factor * 100^"%, A="^move.extruders[var.drive].nonlinear.a^", B="^move.extruders[var.drive].nonlinear.b M291 S4 R{"Calibrating Extrusion: T"^var.tool} P{var.msg} K{"Yes", "No", "Reset Coefficients"} if (input == 1) M99 ; exit if (input == 2) M221 D{var.drive} S100 M592 D{var.drive} A0 B0 M99 ; exit ; Calibrate default extrusion percentage if (#var.speeds != #var.eMulti) abort "var.speeds must have the same length as var.eMulti" echo "Calibrating extrusion rate for T"^var.tool^" using filament \""^move.extruders[tools[var.tool].filamentExtruder].filament^"\"" echo "Settings: distance = "^var.dist^"mm, base speed = "^var.baseSpeed^"mm/s, min extrusion threshold = "^{var.minExtrusionThreshold * 100}^"%" echo "Speeds: "^var.speeds^" mm/s" if (sensors.filamentMonitors[var.drive].type != "rotatingMagnet") abort "Must be a rotating magnet encoder" if (sensors.filamentMonitors[var.drive].enableMode != 2) abort "Encoder mode must be S2" if (sensors.filamentMonitors[var.drive].configured.allMoves != true) abort "Encoder must be active for all moves (A2)" T-1 T{var.tool} P0 ; don't run tpre, tfree, tpost M703 if (tools[var.tool].active[0] == 0) M568 P{var.tool} S{global.defaultFilamentTemperature} M116 P{var.tool} M220 S100 ; reset speed ; M221 D{var.drive} S100 ; reset base extrusion M592 D{var.drive} A0 B0 ; reset non linear extrusion ; G1 X334 Y100 F30000 M591 D{var.drive} S2 A1 ; set magnetic encoder to record during all moves M400 G1 E{var.dist} F{var.baseSpeed * 60} M400 var flow = sensors.filamentMonitors[var.drive].lastPercentage / 100 var baseFlowModifier = {100 / var.flow} echo "Setting base extrusion factor override for drive "^var.drive^" = "^var.baseFlowModifier M221 D{var.drive} S{var.baseFlowModifier} ; Collect non linear data while iterations < #var.speeds ; clear encoder data M591 D{var.drive} S0 M591 D{var.drive} S2 G1 E{var.dist} F{var.speeds[iterations] * 60} M400 set var.flow = sensors.filamentMonitors[var.drive].lastPercentage / 100 set var.flows[iterations] = var.flow set var.eMulti[iterations] = 1 / var.flow echo "Flow at "^var.speeds[iterations]^"mm/s = "^{var.flow * 100}^"%, requires extrusion multiplier of "^{var.eMulti[iterations] * 100}^"%" set var.numMeasurements = iterations + 1 if (var.flow < var.minExtrusionThreshold) break echo "Number of measurements = "^var.numMeasurements echo "Flows: "^var.flows echo "Required extrusion multipliers: "^var.eMulti ; Quadratic regression ; https://www.statisticshowto.com/quadratic-regression/ var x = 0 var y = 1 var x2 = 0 var x3 = 0 var x4 = 0 var xy = 0 var x2y = 0 while (iterations < var.numMeasurements) set var.x = var.x + var.speeds[iterations] set var.y = var.y + var.eMulti[iterations] set var.x2 = var.x2 + (var.speeds[iterations] * var.speeds[iterations]) set var.x3 = var.x3 + (var.speeds[iterations] * var.speeds[iterations] * var.speeds[iterations]) set var.x4 = var.x4 + (var.speeds[iterations] * var.speeds[iterations] * var.speeds[iterations] * var.speeds[iterations]) set var.xy = var.xy + (var.speeds[iterations] * var.eMulti[iterations]) set var.x2y = var.x2y + (var.speeds[iterations] * var.speeds[iterations] * var.eMulti[iterations]) if var.debug echo "x = "^var.x echo "y = "^var.y echo "x2 = "^var.x2 echo "x3 = "^var.x3 echo "x4 = "^var.x4 echo "xy = "^var.xy echo "x2y = "^var.x2y ; add 100% flow at 0 speed set var.numMeasurements = var.numMeasurements + 1 ; a*var.x4 + b*var.x3 + c*var.x2 = var.x2y ; a*var.x3 + b*var.x2 + c*var.x = var.xy ; a*var.x2 + b*var.x + c*var.numMeasurements = var.y ; Because we have normalised the base extrusion multiplier with a slow extrusion rate ; c ~= 1 var c = 1 ; Therefore ; a*var.x4 + b*var.x3 = var.x2y - var.x2 ; a*var.x3 + b*var.x2 = var.xy - var.x ; a*var.x2 + b*var.x = var.y - var.numMeasurements ; a = (var.y - var.numMeasurements - b*var.x) / var.x2 ; ((var.y - var.numMeasurements - b*var.x) / var.x2)*var.x3 + b*var.x2 = var.xy - var.x ; ((var.y - var.numMeasurements - b*var.x)*var.x3 / var.x2) + b*var.x2 = var.xy - var.x var b = ((var.xy - var.x) - (((var.y - var.numMeasurements)*var.x3)/var.x2))/(var.x2 - ((var.x * var.x3)/var.x2)) var a = ((var.y - var.numMeasurements) - (var.b * var.x))/var.x2 if var.debug echo "a = "^var.a echo "b = "^var.b echo "c = "^var.c ; Note var.a and var.b are flipped because M592 uses the equation (1 + min(L, Av + Bv^2)) which has different coefficients to that uses to solve the quadratic regression echo "Setting non linear extrusion multiplier with: M592 D"^var.drive^" A"^var.b^" B"^var.a M592 D{var.drive} A{var.b} B{var.a} T-1 P0 T{var.originalTool} ; M591 D{var.drive} S1 A1 ; only monitor filament during prints
The main issue I have identified, which I don't think can easily be solved, is that it doesn't account for how much the filament expands coming out of the nozzle from die swell and foaming. So the extruder might be moving the correct quantity of filament, but the filament becomes a lower density once it leaves the nozzle which effectively produces overextrusion. I think a visual based method would be the most comprehensive way to measure this.
-
@AndyE3D
Hi, thank you for sharing this alternative method for calibrating the non-linear extrusion with the MFM based on quadratic regression. In any case, your macro looks quite clean and well thought out.It seems that the macro collects the errors only once, without reevaluating the applied coefficients. Based on my experience, I can say that this approach is insufficient to achieve good values that result in an error of less than 1% across the entire speed range. That’s why I follow this process with my macro:
- The minimum extrusion distance for the measurements should be at least twice as long as the melting zone.
- First, I collect the errors.
- I discard speeds with errors greater than 10%, as corrections would require at least a 20% adjustment, which is not feasible due to slip and grinding.
- I calculate the coefficients using least squares.
- I apply the coefficients.
- I test whether the errors are within acceptable limits.
- If the errors are within limits, I finish.
- If not, I adjust the speed values based on the corrected errors (e.g., an error of 2.5% at 2 mm/sec).
- I recollect errors with the adjusted speeds (e.g., 2.05 mm/sec).
- I recalculate the coefficients.
- I apply the coefficients again.
- I test if the errors are within limits.
- If the errors are within limits, I finish.
- If not, I drop the fastest speed and repeat the process.
Regarding your concerns about die swell or foaming, I can clarify that this is simply an extrusion multiplier in the slicer or filament profile when the non-linear extrusion is calculated using that method.
I am excited to see where the development of the MFM will lead.
Btw. you can find the latest macro of my MFM calibration at https://github.com/Meltingplot/BigPrint/blob/duet-3.5.3-sbc/duet-config/macros/meltingplot/filament-extrusion-calibration