From 85649a4549bc0a3613f675149997210ad5ab26da Mon Sep 17 00:00:00 2001 From: Filip Mulier Date: Wed, 6 Aug 2014 19:30:57 -0500 Subject: [PATCH] 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. --- Marlin/Configuration.h | 30 +++++++++++ Marlin/Marlin.h | 10 ++++ Marlin/Marlin_main.cpp | 84 ++++++++++++++++++++++++++++- Marlin/pins.h | 16 ++++++ Marlin/planner.cpp | 31 +++++++++++ Marlin/temperature.cpp | 117 ++++++++++++++++++++++++++++++++++++++--- Marlin/temperature.h | 8 +++ 7 files changed, 289 insertions(+), 7 deletions(-) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 46d6b96dd..45c6ea486 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -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" diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 062b6d43c..3fb6ec553 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.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]; diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index b373e2213..48d867c83 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -157,6 +157,10 @@ // M400 - Finish all moves // M401 - Lower z-probe if present // M402 - Raise z-probe if present +// M404 - N 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 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(); diff --git a/Marlin/pins.h b/Marlin/pins.h index c3644a086..1ec236a07 100644 --- a/Marlin/pins.h +++ b/Marlin/pins.h @@ -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 diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp index 5b20f86f9..fefae6e18 100644 --- a/Marlin/planner.cpp +++ b/Marlin/planner.cpp @@ -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 diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index a10c255af..467b6dbdb 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -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_measMEASURED_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< 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< -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; diff --git a/Marlin/temperature.h b/Marlin/temperature.h index df2b5deac..ca4efabec 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -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];