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 is too inaccurate to
helpfully adjust the extrusion multiplier, but is good enough to act as
a filament runout sensor.

The new setting defaults to true to preserve the existing sensor
behavior.

Existing width sensor G-Code commands are updated to optionally enable
and disable flow compensation and to show the state of the sensor and
command outputs are normalized.

Also includes updates to the relevant doc pages.

Signed-off-by: Ben Lye ben@lye.co.nz
This commit is contained in:
Ben Lye
2026-03-05 09:13:20 +00:00
committed by KevinOConnor
parent b0e6ca45fc
commit 4fba8e4829
5 changed files with 95 additions and 46 deletions

View File

@@ -5114,6 +5114,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.

View File

@@ -780,19 +780,22 @@ is enabled (also see [TSLl401CL Filament Width Sensor](TSL1401CL_Filament_Width_
and [Hall Filament Width Sensor](Hall_Filament_Width_Sensor.md)):
#### QUERY_FILAMENT_WIDTH
`QUERY_FILAMENT_WIDTH`: Return the current measured filament width.
`QUERY_FILAMENT_WIDTH`: Return the current measured filament width, the
state of the width sensor, the state of the filament sensor and the state
of flow compensation.
#### 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 compensation. Resets flow rate to 100%.
#### ENABLE_FILAMENT_WIDTH_SENSOR
`ENABLE_FILAMENT_WIDTH_SENSOR`: Turn on the filament width sensor and
start using it for flow control.
`ENABLE_FILAMENT_WIDTH_SENSOR [FLOW_COMPENSATION=[0|1]`: Turn on the filament
width sensor and enable or disable flow compensation. If `FLOW_COMPENSATION`
is not specified, the current flow compensation state is preserved.
#### QUERY_RAW_FILAMENT_WIDTH
`QUERY_RAW_FILAMENT_WIDTH`: Return the current ADC channel readings

View File

@@ -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 the 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_SENSOR FLOW_COMPENSATION=1** to enable flow compensation
or **ENABLE_FILAMENT_WIDTH_SENSOR FLOW_COMPENSATION=0** to disable it.
Note that disabling filament width compensation automatically resets the extrusion
multiplier to 100%.
**QUERY_FILAMENT_WIDTH** includes the current state of flow compensation in its output.
## Logging
By default, diameter logging is disabled at power-on.

View File

@@ -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.

View File

@@ -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(
@@ -147,15 +149,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:
@@ -164,12 +168,23 @@ class HallFilamentWidthSensor:
return self.reactor.NEVER
def cmd_M407(self, gcmd):
response = ""
if self.diameter > 0:
response += ("Filament dia (measured mm): "
+ str(self.diameter))
response = "Filament diameter: "
if self.is_active:
response += "%.3f mm" % (self.diameter)
else:
response += "Filament NOT present"
response += "sensor disabled"
response += "\nFilament state:"
if self.is_active:
if self.runout_helper.filament_present:
response += " present"
else:
response += " not present"
else:
response += " sensor disabled"
response += ("\nWidth sensor:"
+ (" ON" if self.is_active else " OFF"))
response += ("\nFlow compensation:"
+ (" ON" if self.enable_flow_compensation else " OFF"))
gcmd.respond_info(response)
def cmd_ClearFilamentArray(self, gcmd):
@@ -179,53 +194,58 @@ class HallFilamentWidthSensor:
self.gcode.run_script_from_command("M221 S100")
def cmd_M405(self, gcmd):
response = "Filament width sensor Turned On"
if self.is_active:
response = "Filament width sensor is already On"
else:
self.is_active = True
# Start extrude factor update timer
flow_comp = gcmd.get_int("FLOW_COMPENSATION", None, minval=0, maxval=1)
if flow_comp is not None:
self.enable_flow_compensation = flow_comp
if not flow_comp:
self.gcode.run_script_from_command("M221 S100")
was_active = self.is_active
self.is_active = True
response = ("Filament width sensor: ON"
+ "\nFlow compensation: "
+ ("ON" if self.enable_flow_compensation else "OFF"))
# Only start/restart timer if sensor was previously inactive
if not was_active:
self.reactor.update_timer(self.extrude_factor_update_timer,
self.reactor.NOW)
self.reactor.NOW)
gcmd.respond_info(response)
def cmd_M406(self, gcmd):
response = "Filament width sensor Turned Off"
if not self.is_active:
response = "Filament width sensor is already Off"
else:
self.is_active = False
# Stop extrude factor update timer
self.reactor.update_timer(self.extrude_factor_update_timer,
self.reactor.NEVER)
# Clear filament array
self.filament_array = []
# Set extrude multiplier to 100%
self.gcode.run_script_from_command("M221 S100")
response = "Filament width sensor: OFF"
self.is_active = False
# Stop extrude factor update timer
self.reactor.update_timer(self.extrude_factor_update_timer,
self.reactor.NEVER)
# Clear filament array
self.filament_array = []
# Set extrude multiplier to 100%
self.gcode.run_script_from_command("M221 S100")
gcmd.respond_info(response)
def cmd_Get_Raw_Values(self, gcmd):
response = "ADC1="
response += (" "+str(self.lastFilamentWidthReading))
response += (" ADC2="+str(self.lastFilamentWidthReading2))
response += (" RAW="+
str(self.lastFilamentWidthReading
+self.lastFilamentWidthReading2))
response = ("ADC1="+str(self.lastFilamentWidthReading))
response += (" ADC2="+str(self.lastFilamentWidthReading2))
response += (" RAW="+
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,
'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
gcmd.respond_info("Filament width logging Turned On")
gcmd.respond_info("Filament width logging: ON")
def cmd_log_disable(self, gcmd):
self.is_log = False
gcmd.respond_info("Filament width logging Turned Off")
gcmd.respond_info("Filament width logging: OFF")
def load_config(config):
return HallFilamentWidthSensor(config)