hall_filament_width_sensor: Add new filament sensor

Signed-off-by: Denis Ignatenko <deniss979@gmail.com>
This commit is contained in:
test3210-d 2020-02-04 14:15:30 +02:00 committed by Kevin O'Connor
parent 049d8c2a94
commit 9a65a4569b
4 changed files with 320 additions and 0 deletions

View File

@ -1845,6 +1845,41 @@
# The distance from sensor to the melting chamber as mm
#measurement_delay: 100
# Hall filament width sensor (see docs/HallFilamentWidthSensor.md)
#[hall_filament_width_sensor]
#adc1: analog11
#adc2: analog12
# Analog input pins connected to the sensor. These parameters must
# be provided.
#cal_dia1: 1.50
#cal_dia2: 2.00
# The calibration values (in mm) for the sensors. The default is
# 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.
#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.
#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
# will be treated as the default_nominal_filament_diameter. Host
# module works with FIFO logic. It keeps each sensor value and
# position in an array and POP them back in correct position. This
# parameter must be provided.
#enable: False
# Sensor enabled or disabled after power on. The default is to
# disable.
#measurement_interval: 10
# The approximate distance (in mm) between sensor readings. The
# default is 10mm.
######################################################################
# Board specific hardware support

View File

@ -0,0 +1,104 @@
This document describes Filament Width Sensor host module. Hardware used for developing this host module is based on Two Hall liniar sensors (ss49e for example). Sensors in the body are located opposite sides. Principle of operation : two hall sensors work in differential mode, temperature drift same for sensor. Special temperature compensation not needed. You can find designs at [thingiverse.com](https://www.thingiverse.com/thing:4138933)
[Hall based filament width sensor assembly video](https://www.youtube.com/watch?v=TDO9tME8vp4)
## How does it work?
Sensor generates two analog output based on calculated filament width. Sum of output voltage always equals to detected filament width . Host module monitors voltage changes and adjusts extrusion multiplier. I use aux2 connector on ramps-like board analog11 and analog12 pins. You can use different pins and differenr boards
## Configuration
[hall_filament_width_sensor]
adc1: analog11
adc2: analog12
# adc1 and adc2 channels select own pins Analog input pins on 3d printer board
# Sensor power supply can be 3.3v or 5v
Cal_dia1: 1.50 # Reference diameter point 1 (mm)
Cal_dia2: 2.00 # Reference diameter point 2 (mm)
# The measurement principle provides for two-point calibration
# In calibration process you must use rods of known diameter
# I use drill rods as the base diameter.
# nominal filament diameter must be between Cal_dia1 and Cal_dia2
# Your size may differ from the indicated ones, for example 2.05
Raw_dia1:10630 # Raw sensor value for reference point 1
Raw_dia2:8300 # Raw sensor value for reference point 2
# Raw value of sensor in units
# can be readed by command QUERY_RAW_FILAMENT_WIDTH
default_nominal_filament_diameter: 1.75 # This parameter is in millimeters (mm)
max_difference: 0.15
# Maximum allowed filament diameter difference in millimeters (mm)
# If difference between nominal filament diameter and sensor output is more
# than +- max_difference, extrusion multiplier set back to %100
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 will be treated as the default_nominal_filament_diameter.
# Host module works with FIFO logic. It keeps each sensor value and position in
# an array and POP them back in correct position.
#enable:False
# Sensor enabled or disabled after power on. Disabled by default
# measurement_interval:10
# Sensor readings done with 10 mm intervals by default. If necessary you are free to change this setting
## Commands
**QUERY_FILAMENT_WIDTH** - Return the current measured filament width as result
**RESET_FILAMENT_WIDTH_SENSOR** – Clear all sensor readings. Can be used after filament change.
**DISABLE_FILAMENT_WIDTH_SENSOR** – Turn off the filament width sensor and stop using it to do flow control
**ENABLE_FILAMENT_WIDTH_SENSOR** - Turn on the filament width sensor and start using it to do flow control
**QUERY_RAW_FILAMENT_WIDTH** Return the current ADC channel values and RAW sensor value for calibration points
## Menu variables
**hall_filament_width_sensor.Diameter** current measured filament width in mm
**hall_filament_width_sensor.Raw** current raw measured filament width in units
**hall_filament_width_sensor.is_active** Sensor on or off
## Template for menu variables
[menu __filament_width_current]
type: item
name: "Dia:{0:4.2f} mm"
parameter: hall_filament_width_sensor.Diameter
[menu __filament_raw_width_current]
type: item
name: "RAW:{0:4.0f}"
parameter: hall_filament_width_sensor.Raw
[menu __filament]
type: list
name: Filament
items:
__temp __hotend0_current, __temp __hotend0_target
.__unload
.__load
.__feed
__filament_width_current
__filament_raw_width_current
## Calibration procedure
Insert first calibration rod (1.5 mm size) get first raw sensor value
To get raw sensor value you can use menu item or **QUERY_RAW_FILAMENT_WIDTH** command in terminal
Insert second calibration rod (2.0 mm size) get second raw sensor value
Save raw values in config
## How to enable sensor
After power on by default sensor disabled.
Enable sensor in start g-code by command **ENABLE_FILAMENT_WIDTH_SENSOR** or change enable parameter in config

View File

@ -67,3 +67,4 @@ communication with the Klipper developers.
- [stm32f0](stm32f0_CAN.md): Information on the STM32F0 micro-controller
port.
- [TSL1401CL filament width sensor](TSL1401CL_Filament_Width_Sensor.md)
- [Hall filament width sensor](HallFilamentWidthSensor.md)

View File

@ -0,0 +1,180 @@
# Support for filament width sensor
#
# Copyright (C) 2019 Mustafa YILDIZ <mydiz@hotmail.com>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
ADC_REPORT_TIME = 0.500
ADC_SAMPLE_TIME = 0.001
ADC_SAMPLE_COUNT = 5
class HallFilamentWidthSensor:
def __init__(self, config):
self.printer = config.get_printer()
self.reactor = self.printer.get_reactor()
self.pin1 = config.get('adc1')
self.pin2 = config.get('adc2')
self.dia1=config.getfloat('Cal_dia1', 1.5)
self.dia2=config.getfloat('Cal_dia2', 2.0)
self.rawdia1=config.getint('Raw_dia1', 9500)
self.rawdia2=config.getint('Raw_dia2', 10500)
self.MEASUREMENT_INTERVAL_MM=config.getint('measurement_interval',10)
self.nominal_filament_dia = config.getfloat(
'default_nominal_filament_diameter', above=1)
self.measurement_delay = config.getfloat('measurement_delay', above=0.)
self.measurement_max_difference = config.getfloat('max_difference', 0.2)
self.max_diameter = (self.nominal_filament_dia
+ self.measurement_max_difference)
self.min_diameter = (self.nominal_filament_dia
- self.measurement_max_difference)
self.diameter =self.nominal_filament_dia
self.is_active =config.getboolean('enable', False)
# filament array [position, filamentWidth]
self.filament_array = []
self.lastFilamentWidthReading = 0
# printer objects
self.toolhead = self.ppins = self.mcu_adc = None
self.printer.register_event_handler("klippy:ready", self.handle_ready)
# Start adc
self.ppins = self.printer.lookup_object('pins')
self.mcu_adc = self.ppins.setup_pin('adc', self.pin1)
self.mcu_adc.setup_minmax(ADC_SAMPLE_TIME, ADC_SAMPLE_COUNT)
self.mcu_adc.setup_adc_callback(ADC_REPORT_TIME, self.adc_callback)
self.mcu_adc2 = self.ppins.setup_pin('adc', self.pin2)
self.mcu_adc2.setup_minmax(ADC_SAMPLE_TIME, ADC_SAMPLE_COUNT)
self.mcu_adc2.setup_adc_callback(ADC_REPORT_TIME, self.adc2_callback)
# extrude factor updating
self.extrude_factor_update_timer = self.reactor.register_timer(
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)
# Initialization
def handle_ready(self):
# Load printer objects
self.toolhead = self.printer.lookup_object('toolhead')
# Start extrude factor update timer
self.reactor.update_timer(self.extrude_factor_update_timer,
self.reactor.NOW)
def adc_callback(self, read_time, read_value):
# read sensor value
self.lastFilamentWidthReading = round(read_value * 10000)
def adc2_callback(self, read_time, read_value):
# read sensor value
self.lastFilamentWidthReading2 = round(read_value * 10000)
def update_filament_array(self, last_epos):
# Fill array
if len(self.filament_array) > 0:
# Get last reading position in array & calculate next
# reading position
self.diameter = round((self.dia2 - self.dia1)/
(self.rawdia2-self.rawdia1)*
((self.lastFilamentWidthReading+self.lastFilamentWidthReading2)
-self.rawdia1)+self.dia1,2)
next_reading_position = (self.filament_array[-1][0] +
self.MEASUREMENT_INTERVAL_MM)
if next_reading_position <= (last_epos + self.measurement_delay):
self.filament_array.append([last_epos + self.measurement_delay,
self.diameter])
else:
# add first item to array
self.filament_array.append([self.measurement_delay + last_epos,
self.diameter])
def extrude_factor_update_event(self, eventtime):
# Update extrude factor
pos = self.toolhead.get_position()
last_epos = pos[3]
# Update filament array for lastFilamentWidthReading
self.update_filament_array(last_epos)
# Does filament exists
if self.lastFilamentWidthReading > 0.5:
if len(self.filament_array) > 0:
# Get first position in filament array
pending_position = self.filament_array[0][0]
if pending_position <= last_epos:
# Get first item in filament_array queue
item = self.filament_array.pop(0)
filament_width = item[1]
if ((filament_width <= self.max_diameter)
and (filament_width >= self.min_diameter)):
percentage = round(self.nominal_filament_dia**2
/ 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")
self.filament_array = []
return eventtime + 1
def cmd_M407(self, params):
response = ""
if self.lastFilamentWidthReading > 0:
response += ("Filament dia (measured mm): "
+ str(self.diameter))
else:
response += "Filament NOT present"
self.gcode.respond(response)
def cmd_ClearFilamentArray(self, params):
self.filament_array = []
self.gcode.respond("Filament width measurements cleared!")
# Set extrude multiplier to 100%
self.gcode.run_script_from_command("M221 S100")
def cmd_M405(self, params):
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
self.reactor.update_timer(self.extrude_factor_update_timer,
self.reactor.NOW)
self.gcode.respond(response)
def cmd_M406(self, params):
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")
self.gcode.respond(response)
def cmd_Get_Raw_Values(self, params):
response = "ADC1="
response += (" "+str(self.lastFilamentWidthReading))
response += (" ADC2="+str(self.lastFilamentWidthReading2))
response += (" RAW="+
str(self.lastFilamentWidthReading
+self.lastFilamentWidthReading2))
self.gcode.respond(response)
def get_status(self, eventtime):
return {'Diameter': self.diameter,
'Raw':(self.lastFilamentWidthReading+
self.lastFilamentWidthReading2),
'is_active':self.is_active}
def load_config(config):
return HallFilamentWidthSensor(config)