Real-time filament diameter measurement and control

This feature allows the printer to read the filament diameter
automatically and adjust the printer in real time.  Added code to read
an analog voltage that represents a filament diameter measurement.  This
measurement is delayed in a ring buffer to compensate for sensors that
are a distance away from the extruder.  The measurement is used to
adjust the volumetric_multiplier for the extruder.  Some additional g
codes (M404, M405, M406, M407) are used to set parameters and turn
on/off the control. g code M221 is updated.  Pins for RAMPS1.4, RAMBO,
and Printrboard are identified for analog input.  The configuration file
is updated with relevant user parameters.
master
Filip Mulier 10 years ago
parent 1d0fe035f3
commit 85649a4549

@ -755,6 +755,36 @@ const bool Z_MAX_ENDSTOP_INVERTING = true; // set to true to invert the logic of
//#define SERVO_ENDSTOPS {-1, -1, 0} // Servo index for X, Y, Z. Disable with -1
//#define SERVO_ENDSTOP_ANGLES {0,0, 0,0, 70,0} // X,Y,Z Axis Extend and Retract angles
/**********************************************************************\
* Support for a filament diameter sensor
* Also allows adjustment of diameter at print time (vs at slicing)
* Single extruder only at this point (extruder 0)
*
* Motherboards
* 34 - RAMPS1.4 - uses Analog input 5 on the AUX2 connector
* 81 - Printrboard - Uses Analog input 2 on the Aux 2 connector
* 301 - Rambo - uses Analog input 3
* Note may require analog pins to be defined for different motherboards
**********************************************************************/
#define FILAMENT_SENSOR
#define FILAMENT_SENSOR_EXTRUDER_NUM 0 //The number of the extruder that has the filament sensor (0,1,2)
#define MEASUREMENT_DELAY_CM 14 //measurement delay in cm. This is the distance from filament sensor to middle of barrel
#define DEFAULT_NOMINAL_FILAMENT_DIA 3.0 //Enter the diameter (in mm) of the filament generally used (3.0 mm or 1.75 mm). Used for sensor reading validation
#define MEASURED_UPPER_LIMIT 3.30 //upper limit factor used for sensor reading validation in mm
#define MEASURED_LOWER_LIMIT 1.90 //lower limit factor for sensor reading validation in mm
#define MAX_MEASUREMENT_DELAY 20 //delay buffer size in bytes (1 byte = 1cm)- limits maximum measurement delay allowable (must be larger than MEASUREMENT_DELAY_CM and lower number saves RAM)
//defines used in the code
#define DEFAULT_MEASURED_FILAMENT_DIA DEFAULT_NOMINAL_FILAMENT_DIA //set measured to nominal initially
#define STANDARD_DIA 1.12837915 //The diameter of filament that has a cross sectional area of 1 square mm. This dia should be used in the slicer software settings
#include "Configuration_adv.h"
#include "thermistortables.h"

@ -229,6 +229,16 @@ extern int EtoPPressure;
extern unsigned char fanSpeedSoftPwm;
#endif
#ifdef FILAMENT_SENSOR
extern volatile float filament_width_nominal; //holds the theoretical filament diameter ie., 3.00 or 1.75
extern volatile bool filament_sensor; //indicates that filament sensor readings should control extrusion
extern float filament_width_meas; //holds the filament diameter as accurately measured
extern signed char measurement_delay[]; //ring buffer to delay measurement
extern int delay_index1, delay_index2; //index into ring buffer
extern float delay_dist; //delay distance counter
extern int meas_delay_cm; //delay distance
#endif
#ifdef FWRETRACT
extern bool autoretract_enabled;
extern bool retracted[EXTRUDERS];

@ -157,6 +157,10 @@
// M400 - Finish all moves
// M401 - Lower z-probe if present
// M402 - Raise z-probe if present
// M404 - N<dia in mm> Enter the nominal filament width (3mm, 1.75mm ) or will display nominal filament width without parameters
// M405 - Turn on Filament Sensor extrusion control. Optional D<delay in cm> to set delay in centimeters between sensor and extruder
// M406 - Turn off Filament Sensor extrusion control
// M407 - Displays measured filament diameter
// M500 - stores parameters in EEPROM
// M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
// M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to.
@ -296,6 +300,18 @@ int EtoPPressure=0;
bool cancel_heatup = false ;
#ifdef FILAMENT_SENSOR
//Variables for Filament Sensor input
volatile float filament_width_nominal=DEFAULT_NOMINAL_FILAMENT_DIA; //Set nominal filament width, can be changed with M404
volatile bool filament_sensor=false; //M405 turns on filament_sensor control, M406 turns it off
float filament_width_meas=DEFAULT_MEASURED_FILAMENT_DIA; //Stores the measured filament diameter
signed char measurement_delay[MAX_MEASUREMENT_DELAY+1]; //ring buffer to delay measurement store extruder factor after subtracting 100
int delay_index1=0;
int delay_index2=0; //index into ring buffer
float delay_dist=0; //delay distance counter
int meas_delay_cm = MEASUREMENT_DELAY_CM; //distance delay setting
#endif
//===========================================================================
//=============================Private Variables=============================
//===========================================================================
@ -2317,7 +2333,13 @@ void process_commands()
}
} else {
//reserved for setting filament diameter via UFID or filament measuring device
break;
if(active_extruder == FILAMENT_SENSOR_EXTRUDER_NUM){
radius = analog2widthFil() * 0.5;
area = M_PI * pow(radius, 2);
}else{
area = 1.0;
}
}
tmp_extruder = active_extruder;
if(code_seen('T')) {
@ -2771,6 +2793,66 @@ void process_commands()
}
break;
#endif
#ifdef FILAMENT_SENSOR
case 404: //M404 Enter the nominal filament width (3mm, 1.75mm ) N<3.0> or display nominal filament width
{
#if (FILWIDTH_PIN > -1)
if(code_seen('N')) filament_width_nominal=code_value();
else{
SERIAL_PROTOCOLPGM("Filament dia (nominal mm):");
SERIAL_PROTOCOLLN(filament_width_nominal);
}
#endif
}
break;
case 405: //M405 Turn on filament sensor for control
{
if(code_seen('D')) meas_delay_cm=code_value();
if(meas_delay_cm> MAX_MEASUREMENT_DELAY)
meas_delay_cm = MAX_MEASUREMENT_DELAY;
filament_sensor = true ;
int temp_ratio = widthFil_to_size_ratio();
for (delay_index1=0; delay_index1<(MAX_MEASUREMENT_DELAY+1); ++delay_index1 ){
measurement_delay[delay_index1]=temp_ratio-100; //subtract 100 to scale within a signed byte
}
delay_index1=0;
delay_index2=0;
//SERIAL_PROTOCOLPGM("Filament dia (measured mm):");
//SERIAL_PROTOCOL(filament_width_meas);
//SERIAL_PROTOCOLPGM("Extrusion ratio(%):");
//SERIAL_PROTOCOL(extrudemultiply);
}
break;
case 406: //M406 Turn off filament sensor for control
{
filament_sensor = false ;
}
break;
case 407: //M407 Display measured filament diameter
{
filament_width_meas = code_value();
SERIAL_PROTOCOLPGM("Filament dia (measured mm):");
SERIAL_PROTOCOLLN(filament_width_meas);
}
break;
#endif
case 500: // M500 Store settings in EEPROM
{
Config_StoreSettings();

@ -558,6 +558,15 @@
#define E1_DIR_PIN 34
#define E1_ENABLE_PIN 30
#if MOTHERBOARD == 34 //FMM added for Filament Extruder
#ifdef FILAMENT_SENSOR
//define analog pin for the filament width sensor input
//Use the RAMPS 1.4 Analog input 5 on the AUX2 connector
#define FILWIDTH_PIN 5
#endif
#endif
#if MOTHERBOARD == 68
#define E2_STEP_PIN 23
#define E2_DIR_PIN 25
@ -1692,6 +1701,9 @@
#define Z_STOP_PIN 36
#define TEMP_0_PIN 1 // Extruder / Analog pin numbering
#define TEMP_BED_PIN 0 // Bed / Analog pin numbering
#ifdef FILAMENT_SENSOR
#define FILWIDTH_PIN 2
#endif //FILAMENT_SENSOR
#endif
#define TEMP_1_PIN -1
@ -2326,6 +2338,10 @@ DaveX plan for Teensylu/printrboard-type pinouts (ref teensylu & sprinter) for a
#endif
#endif //ULTRA_LCD
#ifdef FILAMENT_SENSOR
//Filip added pin for Filament sensor analog input
#define FILWIDTH_PIN 3
#endif //FILAMENT_SENSOR
#endif

@ -117,6 +117,10 @@ static long x_segment_time[3]={MAX_FREQ_TIME + 1,0,0}; // Segment times (in
static long y_segment_time[3]={MAX_FREQ_TIME + 1,0,0};
#endif
#ifdef FILAMENT_SENSOR
static char meas_sample; //temporary variable to hold filament measurement sample
#endif
// Returns the index of the next block in the ring buffer
// NOTE: Removed modulo (%) operator, which uses an expensive divide and multiplication.
static int8_t next_block_index(int8_t block_index) {
@ -737,6 +741,33 @@ block->steps_y = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-positi
block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0
block->nominal_rate = ceil(block->step_event_count * inverse_second); // (step/sec) Always > 0
#ifdef FILAMENT_SENSOR
//FMM update ring buffer used for delay with filament measurements
if(filament_sensor && (extruder==0)) //only for extruder 0
{
delay_dist = delay_dist + delta_mm[E_AXIS]; //increment counter with next move in e axis
if (delay_dist> (10*(MAX_MEASUREMENT_DELAY+1))) //check if counter is over max buffer size in mm
delay_dist = delay_dist - 10*(MAX_MEASUREMENT_DELAY+1); //loop around the buffer
if(delay_dist<0)
delay_dist = delay_dist + 10*(MAX_MEASUREMENT_DELAY+1); //loop around the buffer
delay_index1=delay_dist/10; //calculate index
if(delay_index1 != delay_index2) //moved index
{
meas_sample=widthFil_to_size_ratio()-100; //subtract off 100 to reduce magnitude - to store in a signed char
}
while( delay_index1 != delay_index2)
{
delay_index2 = delay_index2 + 1;
if(delay_index2>MAX_MEASUREMENT_DELAY)
delay_index2=delay_index2-(MAX_MEASUREMENT_DELAY+1); //loop around buffer when incrementing
measurement_delay[delay_index2]=meas_sample;
}
}
#endif
// Calculate and limit speed in mm/sec for each axis
float current_speed[4];
float speed_factor = 1.0; //factor <=1 do decrease speed

@ -71,7 +71,10 @@ unsigned char soft_pwm_bed;
#ifdef BABYSTEPPING
volatile int babystepsTodo[3]={0,0,0};
#endif
#ifdef FILAMENT_SENSOR
int current_raw_filwidth = 0; //Holds measured filament diameter - one extruder only
#endif
//===========================================================================
//=============================private variables============================
//===========================================================================
@ -158,6 +161,9 @@ unsigned long watchmillis[EXTRUDERS] = ARRAY_BY_EXTRUDERS(0,0,0);
#define SOFT_PWM_SCALE 0
#endif
#ifdef FILAMENT_SENSOR
static int meas_shift_index; //used to point to a delayed sample in buffer for filament width sensor
#endif
//===========================================================================
//============================= functions ============================
//===========================================================================
@ -601,6 +607,21 @@ void manage_heater()
}
#endif
#endif
//code for controlling the extruder rate based on the width sensor
#ifdef FILAMENT_SENSOR
if(filament_sensor)
{
meas_shift_index=delay_index1-meas_delay_cm;
if(meas_shift_index<0)
meas_shift_index = meas_shift_index + (MAX_MEASUREMENT_DELAY+1); //loop around buffer if needed
//get the delayed info and add 100 to reconstitute to a percent of the nominal filament diameter
//then adjust as a factor to the Standard Diameter (has an area of 1mm squared)
//then square it to get an area
volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM] = pow((float)(100+measurement_delay[meas_shift_index])/filament_width_nominal*STANDARD_DIA/100.0,2);
}
#endif
}
#define PGM_RD_W(x) (short)pgm_read_word(&x)
@ -702,6 +723,40 @@ static void updateTemperaturesFromRawValues()
CRITICAL_SECTION_END;
}
// For converting raw Filament Width to milimeters
#ifdef FILAMENT_SENSOR
float analog2widthFil() {
return current_raw_filwidth/16383.0*5.0;
//return current_raw_filwidth;
}
// For converting raw Filament Width to an volumetric ratio
int widthFil_to_size_ratio() {
float temp;
#if (FILWIDTH_PIN > -1) //check if a sensor is supported
filament_width_meas=current_raw_filwidth/16383.0*5.0;
#endif
temp=filament_width_meas;
if(filament_width_meas<MEASURED_LOWER_LIMIT)
temp=filament_width_nominal; //assume sensor cut out
else if (filament_width_meas>MEASURED_UPPER_LIMIT)
temp= MEASURED_UPPER_LIMIT;
return(filament_width_nominal/temp*100);
}
#endif
void tp_init()
{
#if (MOTHERBOARD == 80) && ((TEMP_SENSOR_0==-1)||(TEMP_SENSOR_1==-1)||(TEMP_SENSOR_2==-1)||(TEMP_SENSOR_BED==-1))
@ -797,6 +852,17 @@ void tp_init()
#endif
#endif
//Added for Filament Sensor
#ifdef FILAMENT_SENSOR
#if defined(FILWIDTH_PIN) && (FILWIDTH_PIN > -1)
#if FILWIDTH_PIN < 8
DIDR0 |= 1<<FILWIDTH_PIN;
#else
DIDR2 |= 1<<(FILWIDTH_PIN - 8);
#endif
#endif
#endif
// Use timer0 for temperature measurement
// Interleave temperature interrupt with millies interrupt
OCR0B = 128;
@ -1109,7 +1175,7 @@ ISR(TIMER0_COMPB_vect)
static unsigned long raw_temp_1_value = 0;
static unsigned long raw_temp_2_value = 0;
static unsigned long raw_temp_bed_value = 0;
static unsigned char temp_state = 8;
static unsigned char temp_state = 10;
static unsigned char pwm_count = (1 << SOFT_PWM_SCALE);
static unsigned char soft_pwm_0;
#if (EXTRUDERS > 1) || defined(HEATERS_PARALLEL)
@ -1122,6 +1188,10 @@ ISR(TIMER0_COMPB_vect)
static unsigned char soft_pwm_b;
#endif
#if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1)
static unsigned long raw_filwidth_value = 0; //added for filament width sensor
#endif
if(pwm_count == 0){
soft_pwm_0 = soft_pwm[0];
if(soft_pwm_0 > 0) {
@ -1248,10 +1318,39 @@ ISR(TIMER0_COMPB_vect)
#if defined(TEMP_2_PIN) && (TEMP_2_PIN > -1)
raw_temp_2_value += ADC;
#endif
temp_state = 0;
temp_count++;
temp_state = 8;//change so that Filament Width is also measured
break;
case 8: //Startup, delay initial temp reading a tiny bit so the hardware can settle.
case 8: //Prepare FILWIDTH
#if defined(FILWIDTH_PIN) && (FILWIDTH_PIN> -1)
#if FILWIDTH_PIN>7
ADCSRB = 1<<MUX5;
#else
ADCSRB = 0;
#endif
ADMUX = ((1 << REFS0) | (FILWIDTH_PIN & 0x07));
ADCSRA |= 1<<ADSC; // Start conversion
#endif
lcd_buttons_update();
temp_state = 9;
break;
case 9: //Measure FILWIDTH
#if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1)
//raw_filwidth_value += ADC; //remove to use an IIR filter approach
if(ADC>102) //check that ADC is reading a voltage > 0.5 volts, otherwise don't take in the data.
{
raw_filwidth_value= raw_filwidth_value-(raw_filwidth_value>>7); //multipliy raw_filwidth_value by 127/128
raw_filwidth_value= raw_filwidth_value + ((unsigned long)ADC<<7); //add new ADC reading
}
#endif
temp_state = 0;
temp_count++;
break;
case 10: //Startup, delay initial temp reading a tiny bit so the hardware can settle.
temp_state = 0;
break;
// default:
@ -1260,7 +1359,7 @@ ISR(TIMER0_COMPB_vect)
// break;
}
if(temp_count >= OVERSAMPLENR) // 8 * 16 * 1/(16000000/64/256) = 131ms.
if(temp_count >= OVERSAMPLENR) // 10 * 16 * 1/(16000000/64/256) = 164ms.
{
if (!temp_meas_ready) //Only update the raw values if they have been read. Else we could be updating them during reading.
{
@ -1276,6 +1375,12 @@ ISR(TIMER0_COMPB_vect)
#endif
current_temperature_bed_raw = raw_temp_bed_value;
}
//Add similar code for Filament Sensor - can be read any time since IIR filtering is used
#if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1)
current_raw_filwidth = raw_filwidth_value>>10; //need to divide to get to 0-16384 range since we used 1/128 IIR filter approach
#endif
temp_meas_ready = true;
temp_count = 0;

@ -31,6 +31,14 @@
void tp_init(); //initialize the heating
void manage_heater(); //it is critical that this is called periodically.
#ifdef FILAMENT_SENSOR
// For converting raw Filament Width to milimeters
float analog2widthFil();
// For converting raw Filament Width to an extrusion ratio
int widthFil_to_size_ratio();
#endif
// low level conversion routines
// do not use these routines and variables outside of temperature.cpp
extern int target_temperature[EXTRUDERS];

Loading…
Cancel
Save