From 189171b6be4d3a762e8432321014e9d315b87fa3 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Fri, 27 Feb 2026 22:34:41 +0000 Subject: [PATCH 1/4] hall_filament_width_sensor: Toggle for flow compensation Adds a toggle to enable or disable flow compensation based on the filament width sensor readings without disabling the sensor entirely. Useful on printers where the hall effect sensor which is too inaccurate to helpfully adjust the extrusion multiplier, but is good enough to act as a filament runout sensor. Includes commands to enable and disable flow compensation, and to query the state. Also includes updates to the relevant doc pages. Signed-off-by: Ben Lye ben@lye.co.nz --- docs/Config_Reference.md | 4 ++ docs/G-Codes.md | 17 ++++++- docs/Hall_Filament_Width_Sensor.md | 21 ++++++++ docs/Status_Reference.md | 1 + klippy/extras/hall_filament_width_sensor.py | 56 +++++++++++++++++---- 5 files changed, 88 insertions(+), 11 deletions(-) diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md index 7bc54e42d..f0ca2dce2 100644 --- a/docs/Config_Reference.md +++ b/docs/Config_Reference.md @@ -5083,6 +5083,10 @@ adc2: #enable: False # Sensor enabled or disabled after power on. The default is to # disable. +#enable_flow_compensation: True +# Flow compensation enabled or disabled. If set to False, the sensor +# will not modify the extrusion multiplier and will only trigger +# runout events. The default is True. #measurement_interval: 10 # The approximate distance (in mm) between sensor readings. The # default is 10mm. diff --git a/docs/G-Codes.md b/docs/G-Codes.md index a4dd89fe4..144fd2f84 100644 --- a/docs/G-Codes.md +++ b/docs/G-Codes.md @@ -784,11 +784,11 @@ and [Hall Filament Width Sensor](Hall_Filament_Width_Sensor.md)): #### RESET_FILAMENT_WIDTH_SENSOR `RESET_FILAMENT_WIDTH_SENSOR`: Clear all sensor readings. Helpful -after filament change. +after filament change. Resets flow rate to 100%. #### DISABLE_FILAMENT_WIDTH_SENSOR `DISABLE_FILAMENT_WIDTH_SENSOR`: Turn off the filament width sensor -and stop using it for flow control. +and stop using it for flow control. Resets flow rate to 100%. #### ENABLE_FILAMENT_WIDTH_SENSOR `ENABLE_FILAMENT_WIDTH_SENSOR`: Turn on the filament width sensor and @@ -804,6 +804,19 @@ and RAW sensor value for calibration points. #### DISABLE_FILAMENT_WIDTH_LOG `DISABLE_FILAMENT_WIDTH_LOG`: Turn off diameter logging. +#### ENABLE_FILAMENT_WIDTH_COMPENSATION +`ENABLE_FILAMENT_WIDTH_COMPENSATION`: Turn on flow compensation based +on filament width sensor readings. + +#### DISABLE_FILAMENT_WIDTH_COMPENSATION +`DISABLE_FILAMENT_WIDTH_COMPENSATION`: Turn off flow compensation based +on filament width sensor readings. Does not disable the sensor itself or +the filament runout switch. Resets flow rate to 100%. + +#### QUERY_FILAMENT_WIDTH_COMPENSATION +`QUERY_FILAMENT_WIDTH_COMPENSATION`: Query the state of filament width sensor +flow compensation. + ### [heaters] The heaters module is automatically loaded if a heater is defined in diff --git a/docs/Hall_Filament_Width_Sensor.md b/docs/Hall_Filament_Width_Sensor.md index 9992ef730..11c7d5cc1 100644 --- a/docs/Hall_Filament_Width_Sensor.md +++ b/docs/Hall_Filament_Width_Sensor.md @@ -56,6 +56,27 @@ By default, the sensor is disabled at power-on. To enable the sensor, issue **ENABLE_FILAMENT_WIDTH_SENSOR** command or set the `enable` parameter to `true`. +## Use as a runout switch only + +By default, the sensor measures filament diameter and adjusts extrusion multiplier +to compensate for variations. + +If you want to use the sensor as a runout switch only, set the `enable_flow_compensation` +config parameter to `false`. In this mode, the sensor will only trigger runout +events when filament is not detected, it will not modify the extrusion multiplier. + +This is useful for printers where the filament sensor is not accurate enough for +flow compensation but can reliably detect filament runout, or when printing with +flexible filaments which have unstable diameter characteristics. + +Issue **ENABLE_FILAMENT_WIDTH_COMPENSATION** to enable flow compensation +or **DISABLE_FILAMENT_WIDTH_COMPENSATION** to disable it. + +Note that disabling filament width compensation automatically resets the extrusion +multiplier to 100%. + +**QUERY_FILAMENT_WIDTH_COMPENSATION** returns the current state of flow compensation. + ## Logging By default, diameter logging is disabled at power-on. diff --git a/docs/Status_Reference.md b/docs/Status_Reference.md index 1f6704acc..913bf10a8 100644 --- a/docs/Status_Reference.md +++ b/docs/Status_Reference.md @@ -248,6 +248,7 @@ object: - all items from [filament_switch_sensor](Status_Reference.md#filament_switch_sensor) - `is_active`: Returns True if the sensor is currently active. +- `flow_compensation_enabled`: Returns True if flow compensation is enabled. - `Diameter`: The last reading from the sensor in mm. - `Raw`: The last raw ADC reading from the sensor. diff --git a/klippy/extras/hall_filament_width_sensor.py b/klippy/extras/hall_filament_width_sensor.py index 6c981303b..a0f458a90 100644 --- a/klippy/extras/hall_filament_width_sensor.py +++ b/klippy/extras/hall_filament_width_sensor.py @@ -33,6 +33,8 @@ class HallFilamentWidthSensor: self.runout_dia_min=config.getfloat('min_diameter', 1.0) self.runout_dia_max=config.getfloat('max_diameter', self.max_diameter) self.is_log =config.getboolean('logging', False) + self.enable_flow_compensation = config.getboolean( + 'enable_flow_compensation', True) # Use the current diameter instead of nominal while the first # measurement isn't in place self.use_current_dia_while_delay = config.getboolean( @@ -74,6 +76,18 @@ class HallFilamentWidthSensor: self.cmd_log_enable) self.gcode.register_command('DISABLE_FILAMENT_WIDTH_LOG', self.cmd_log_disable) + self.gcode.register_command( + 'ENABLE_FILAMENT_WIDTH_COMPENSATION', + self.cmd_flow_comp_enable, + desc=self.cmd_ENABLE_FILAMENT_WIDTH_COMPENSATION_help) + self.gcode.register_command( + 'DISABLE_FILAMENT_WIDTH_COMPENSATION', + self.cmd_flow_comp_disable, + desc=self.cmd_DISABLE_FILAMENT_WIDTH_COMPENSATION_help) + self.gcode.register_command( + 'QUERY_FILAMENT_WIDTH_COMPENSATION', + self.cmd_flow_comp_query, + desc=self.cmd_QUERY_FILAMENT_WIDTH_COMPENSATION_help) self.runout_helper = filament_switch_sensor.RunoutHelper(config) # Initialization @@ -147,15 +161,17 @@ class HallFilamentWidthSensor: self.filament_width = self.diameter elif self.firstExtruderUpdatePosition == pending_position: self.filament_width = self.nominal_filament_dia - if ((self.filament_width <= self.max_diameter) - and (self.filament_width >= self.min_diameter)): - percentage = round(self.nominal_filament_dia**2 - / self.filament_width**2 * 100) - self.gcode.run_script("M221 S" + str(percentage)) - else: - self.gcode.run_script("M221 S100") + if self.enable_flow_compensation: + if ((self.filament_width <= self.max_diameter) + and (self.filament_width >= self.min_diameter)): + percentage = round(self.nominal_filament_dia**2 + / self.filament_width**2 * 100) + self.gcode.run_script("M221 S" + str(percentage)) + else: + self.gcode.run_script("M221 S100") else: - self.gcode.run_script("M221 S100") + if self.enable_flow_compensation: + self.gcode.run_script("M221 S100") self.filament_array = [] if self.is_active: @@ -217,7 +233,9 @@ class HallFilamentWidthSensor: status.update({'Diameter': self.diameter, 'Raw':(self.lastFilamentWidthReading+ self.lastFilamentWidthReading2), - 'is_active':self.is_active}) + 'is_active':self.is_active, + 'flow_compensation_enabled':self.enable_flow_compensation + }) return status def cmd_log_enable(self, gcmd): self.is_log = True @@ -227,5 +245,25 @@ class HallFilamentWidthSensor: self.is_log = False gcmd.respond_info("Filament width logging Turned Off") + cmd_ENABLE_FILAMENT_WIDTH_COMPENSATION_help = ( + "Enable flow compensation based on filament width") + def cmd_flow_comp_enable(self, gcmd): + self.enable_flow_compensation = True + gcmd.respond_info("Filament width flow compensation Turned On") + + cmd_DISABLE_FILAMENT_WIDTH_COMPENSATION_help = ( + "Disable flow compensation based on filament width") + def cmd_flow_comp_disable(self, gcmd): + self.enable_flow_compensation = False + # Set extrude multiplier to 100% + self.gcode.run_script_from_command("M221 S100") + gcmd.respond_info("Filament width flow compensation Turned Off") + + cmd_QUERY_FILAMENT_WIDTH_COMPENSATION_help = ( + "Report filament width flow compensation status") + def cmd_flow_comp_query(self, gcmd): + gcmd.respond_info("Filament width flow compensation:"+ + (" ON" if self.enable_flow_compensation else " OFF")) + def load_config(config): return HallFilamentWidthSensor(config) From 393fc453de5d8a3a8dd010d06a426aa06cf0d8dd Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Fri, 27 Feb 2026 22:39:31 +0000 Subject: [PATCH 2/4] hall_filament_width_sensor: Add missing command descriptions Add descriptions to the existing width sensor commands. Signed-off-by: Ben Lye ben@lye.co.nz --- klippy/extras/hall_filament_width_sensor.py | 57 ++++++++++++++++----- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/klippy/extras/hall_filament_width_sensor.py b/klippy/extras/hall_filament_width_sensor.py index a0f458a90..38828d160 100644 --- a/klippy/extras/hall_filament_width_sensor.py +++ b/klippy/extras/hall_filament_width_sensor.py @@ -63,19 +63,36 @@ class HallFilamentWidthSensor: self.extrude_factor_update_event) # Register commands self.gcode = self.printer.lookup_object('gcode') - self.gcode.register_command('QUERY_FILAMENT_WIDTH', self.cmd_M407) - self.gcode.register_command('RESET_FILAMENT_WIDTH_SENSOR', - self.cmd_ClearFilamentArray) - self.gcode.register_command('DISABLE_FILAMENT_WIDTH_SENSOR', - self.cmd_M406) - self.gcode.register_command('ENABLE_FILAMENT_WIDTH_SENSOR', - self.cmd_M405) - self.gcode.register_command('QUERY_RAW_FILAMENT_WIDTH', - self.cmd_Get_Raw_Values) - self.gcode.register_command('ENABLE_FILAMENT_WIDTH_LOG', - self.cmd_log_enable) - self.gcode.register_command('DISABLE_FILAMENT_WIDTH_LOG', - self.cmd_log_disable) + self.gcode.register_command( + 'QUERY_FILAMENT_WIDTH', + self.cmd_M407, + desc=self.cmd_QUERY_FILAMENT_WIDTH_help + ) + self.gcode.register_command( + 'RESET_FILAMENT_WIDTH_SENSOR', + self.cmd_ClearFilamentArray, + desc=self.cmd_RESET_FILAMENT_WIDTH_SENSOR_help + ) + self.gcode.register_command( + 'DISABLE_FILAMENT_WIDTH_SENSOR', + self.cmd_M406, + desc=self.cmd_DISABLE_FILAMENT_WIDTH_SENSOR_help) + self.gcode.register_command( + 'ENABLE_FILAMENT_WIDTH_SENSOR', + self.cmd_M405, + desc=self.cmd_ENABLE_FILAMENT_WIDTH_SENSOR_help) + self.gcode.register_command( + 'QUERY_RAW_FILAMENT_WIDTH', + self.cmd_Get_Raw_Values, + desc=self.cmd_QUERY_RAW_FILAMENT_WIDTH_help) + self.gcode.register_command( + 'ENABLE_FILAMENT_WIDTH_LOG', + self.cmd_log_enable, + desc=self.cmd_ENABLE_FILAMENT_WIDTH_LOG_help) + self.gcode.register_command( + 'DISABLE_FILAMENT_WIDTH_LOG', + self.cmd_log_disable, + desc=self.cmd_DISABLE_FILAMENT_WIDTH_LOG_help) self.gcode.register_command( 'ENABLE_FILAMENT_WIDTH_COMPENSATION', self.cmd_flow_comp_enable, @@ -179,6 +196,7 @@ class HallFilamentWidthSensor: else: return self.reactor.NEVER + cmd_QUERY_FILAMENT_WIDTH_help = "Report the filament width in mm" def cmd_M407(self, gcmd): response = "" if self.diameter > 0: @@ -188,12 +206,15 @@ class HallFilamentWidthSensor: response += "Filament NOT present" gcmd.respond_info(response) + cmd_RESET_FILAMENT_WIDTH_SENSOR_help = "Clear all filament width readings" def cmd_ClearFilamentArray(self, gcmd): self.filament_array = [] gcmd.respond_info("Filament width measurements cleared!") # Set extrude multiplier to 100% self.gcode.run_script_from_command("M221 S100") + cmd_ENABLE_FILAMENT_WIDTH_SENSOR_help = ( + "Enable the filament width sensor") def cmd_M405(self, gcmd): response = "Filament width sensor Turned On" if self.is_active: @@ -205,6 +226,8 @@ class HallFilamentWidthSensor: self.reactor.NOW) gcmd.respond_info(response) + cmd_DISABLE_FILAMENT_WIDTH_SENSOR_help = ( + "Disable the filament width sensor") def cmd_M406(self, gcmd): response = "Filament width sensor Turned Off" if not self.is_active: @@ -220,6 +243,8 @@ class HallFilamentWidthSensor: self.gcode.run_script_from_command("M221 S100") gcmd.respond_info(response) + cmd_QUERY_RAW_FILAMENT_WIDTH_help = ( + "Report the raw filament width sensor values") def cmd_Get_Raw_Values(self, gcmd): response = "ADC1=" response += (" "+str(self.lastFilamentWidthReading)) @@ -228,6 +253,7 @@ class HallFilamentWidthSensor: str(self.lastFilamentWidthReading +self.lastFilamentWidthReading2)) gcmd.respond_info(response) + def get_status(self, eventtime): status = self.runout_helper.get_status(eventtime) status.update({'Diameter': self.diameter, @@ -237,10 +263,15 @@ class HallFilamentWidthSensor: 'flow_compensation_enabled':self.enable_flow_compensation }) return status + + cmd_ENABLE_FILAMENT_WIDTH_LOG_help = ( + "Enable filament width sensor logging") def cmd_log_enable(self, gcmd): self.is_log = True gcmd.respond_info("Filament width logging Turned On") + cmd_DISABLE_FILAMENT_WIDTH_LOG_help = ( + "Disable filament width sensor logging") def cmd_log_disable(self, gcmd): self.is_log = False gcmd.respond_info("Filament width logging Turned Off") From 8a2bfb5c9bd24de1895a794c30e6437ced18a55e Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Fri, 27 Feb 2026 22:40:34 +0000 Subject: [PATCH 3/4] hall_filament_width_sensor: Improve query outputs QUERY_FILAMENT_WIDTH - format the calculated width in mm to four decimal places. QUERY_FILAMENT_WIDTH_RAW - remove an extra space before the ADC1 value. Signed-off-by: Ben Lye ben@lye.co.nz --- klippy/extras/hall_filament_width_sensor.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/klippy/extras/hall_filament_width_sensor.py b/klippy/extras/hall_filament_width_sensor.py index 38828d160..68180a002 100644 --- a/klippy/extras/hall_filament_width_sensor.py +++ b/klippy/extras/hall_filament_width_sensor.py @@ -200,8 +200,7 @@ class HallFilamentWidthSensor: def cmd_M407(self, gcmd): response = "" if self.diameter > 0: - response += ("Filament dia (measured mm): " - + str(self.diameter)) + response += ("Filament dia (measured mm): %.4f" % (self.diameter)) else: response += "Filament NOT present" gcmd.respond_info(response) @@ -246,8 +245,7 @@ class HallFilamentWidthSensor: cmd_QUERY_RAW_FILAMENT_WIDTH_help = ( "Report the raw filament width sensor values") def cmd_Get_Raw_Values(self, gcmd): - response = "ADC1=" - response += (" "+str(self.lastFilamentWidthReading)) + response = "ADC1="+str(self.lastFilamentWidthReading) response += (" ADC2="+str(self.lastFilamentWidthReading2)) response += (" RAW="+ str(self.lastFilamentWidthReading From 8c592ee3665ff06591db9b70c5e6557ff88f3df2 Mon Sep 17 00:00:00 2001 From: Ben Lye Date: Wed, 4 Mar 2026 11:14:54 +0000 Subject: [PATCH 4/4] hall_filament_width_sensor: Add config validation to avoid possible div-by-zero exceptions Adds two checks to prevent config settings which could lead to div-by-zero errors in specific circumstances: - `raw_dia1` and `raw_dia2` must be different to prevent a possible exception in `adc2_callback` - `max_difference` must be less than `default_nominal_filament_diameter` to prevent a possible exception in `extrude_factor_update_event` Doc is also updated. Signed-off-by: Ben Lye ben@lye.co.nz --- docs/Config_Reference.md | 7 ++++--- klippy/extras/hall_filament_width_sensor.py | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md index f0ca2dce2..79f05f121 100644 --- a/docs/Config_Reference.md +++ b/docs/Config_Reference.md @@ -5064,15 +5064,16 @@ adc2: # 1.50 for cal_dia1 and 2.00 for cal_dia2. #raw_dia1: 9500 #raw_dia2: 10500 -# The raw calibration values for the sensors. The default is 9500 -# for raw_dia1 and 10500 for raw_dia2. +# The raw calibration values for the sensors. Both values must not be +# the same. The default is 9500 for raw_dia1 and 10500 for raw_dia2. #default_nominal_filament_diameter: 1.75 # The nominal filament diameter. This parameter must be provided. #max_difference: 0.200 # Maximum allowed filament diameter difference in millimeters (mm). # If difference between nominal filament diameter and sensor output # is more than +- max_difference, extrusion multiplier is set back -# to %100. The default is 0.200. +# to %100. Must be less than default_nominal_filament_diameter. +# The default is 0.200. #measurement_delay: 70 # The distance from sensor to the melting chamber/hot-end in # millimeters (mm). The filament between the sensor and the hot-end diff --git a/klippy/extras/hall_filament_width_sensor.py b/klippy/extras/hall_filament_width_sensor.py index 68180a002..b11b9d94e 100644 --- a/klippy/extras/hall_filament_width_sensor.py +++ b/klippy/extras/hall_filament_width_sensor.py @@ -35,6 +35,14 @@ class HallFilamentWidthSensor: self.is_log =config.getboolean('logging', False) self.enable_flow_compensation = config.getboolean( 'enable_flow_compensation', True) + if self.rawdia1 == self.rawdia2: + raise config.error( + "hall_filament_width_sensor: raw_dia1 and raw_dia2 must be" + " different") + if self.min_diameter <= 0: + raise config.error( + "hall_filament_width_sensor: max_difference must be less than" + " default_nominal_filament_diameter") # Use the current diameter instead of nominal while the first # measurement isn't in place self.use_current_dia_while_delay = config.getboolean(