//! @file //! @date Jun 10, 2019 //! @author Marek Bel //! @brief First layer (Z offset) calibration #include "first_lay_cal.h" #include "Configuration_var.h" #include "Marlin.h" #include "messages.h" #include "cmdqueue.h" #include "mmu2.h" #include #include //! @brief Count extrude length //! //! @param layer_height layer height in mm //! @param extrusion_width extrusion width in mm //! @param extrusion_length extrusion length in mm //! @return filament length in mm which needs to be extruded to form line static constexpr float __attribute__((noinline)) count_e(float layer_height, float extrusion_width, float extrusion_length, float filament_diameter=1.75f) { return (extrusion_length * ((M_PI * pow(layer_height, 2)) / 4 + layer_height * (extrusion_width - layer_height))) / ((M_PI * pow(filament_diameter, 2)) / 4); } //! @brief Extrusion spacing //! //! @param layer_height layer height in mm //! @param extrusion_width extrusion width in mm //! @return filament length in mm which needs to be extruded to form line static constexpr float spacing(float layer_height, float extrusion_width, float overlap_factor=1.f) { return extrusion_width - layer_height * (overlap_factor - M_PI/4); } // Common code extracted into one function to reduce code size static void lay1cal_common_enqueue_loop(const char * const * cmd_sequence, const uint8_t steps) { for (uint8_t i = 0; i < steps; ++i) { void * pgm_ptr = pgm_read_ptr(cmd_sequence + i); // M702 is currently only used with MMU enabled if (pgm_ptr == MSG_M702 && !MMU2::mmu2.Enabled()) { continue; } enquecommand_P(static_cast(pgm_ptr)); } } static const char extrude_fmt_X[] PROGMEM = "G1X%gE%g"; static const char extrude_fmt_Y[] PROGMEM = "G1Y%gE%g"; static const char zero_extrusion[] PROGMEM = "G92E0"; #ifndef NEW_FIRST_LAYER_CAL int8_t invert = 1; const float short_length = 20; #else int8_t invert = -1; const float short_length = 13; #endif //NEW_FIRST_LAYER_CAL const float square_width = 20; const float long_length = 150; //! @brief Wait for preheat void lay1cal_wait_preheat() { static const char preheat_cmd_2[] PROGMEM = "M190"; static const char preheat_cmd_3[] PROGMEM = "M109"; static const char preheat_cmd_4[] PROGMEM = "G28"; static const char * const preheat_cmd[] PROGMEM = { MSG_M107, preheat_cmd_2, preheat_cmd_3, preheat_cmd_4, zero_extrusion }; lay1cal_common_enqueue_loop(preheat_cmd, sizeof(preheat_cmd)/sizeof(preheat_cmd[0])); } //! @brief Load filament //! @param cmd_buffer character buffer needed to format gcodes //! @param filament filament to use (applies for MMU only) //! @returns true if extra purge distance is needed in case of MMU prints (after a toolchange), otherwise false bool lay1cal_load_filament(uint8_t filament) { if (MMU2::mmu2.Enabled()) { enquecommand_P(MSG_M83); enquecommand_P(PSTR("G1Y-3F1000")); enquecommand_P(PSTR("G1Z0.4")); uint8_t currentTool = MMU2::mmu2.get_current_tool(); if(currentTool == filament ){ // already have the correct tool loaded - do nothing return false; } else if( currentTool != (uint8_t)MMU2::FILAMENT_UNKNOWN){ // some other slot is loaded, perform an unload first enquecommand_P(MSG_M702); } // perform a toolchange enquecommandf_P(PSTR("T%d"), filament); return true; } return false; } //! @brief Print intro line //! @param extraPurgeNeeded false if the first MMU-related "G1 E29" have to be skipped because the nozzle is already full of filament //! @param layer_height the height of the calibration layer //! @param extrusion_width the width of the extrusion layer void lay1cal_intro_line(bool extraPurgeNeeded, float layer_height, float extrusion_width) { static const char cmd_intro_mmu_3[] PROGMEM = "G1X55E29F1073"; static const char cmd_intro_mmu_4[] PROGMEM = "G1X5E29F1800"; static const char cmd_intro_mmu_5[] PROGMEM = "G1X55E8F2000"; static const char cmd_intro_mmu_6[] PROGMEM = "G1Z0.3F1000"; static const char cmd_intro_mmu_8[] PROGMEM = "G1X240E25F2200"; static const char cmd_intro_mmu_9[] PROGMEM = "G1Y-2F1000"; static const char cmd_intro_mmu_10[] PROGMEM = "G1X200E8F1400"; static const char cmd_intro_mmu_11[] PROGMEM = "G1Z0.2F1000"; static const char * const cmd_intro_mmu[] PROGMEM = { // first 2 items are only relevant if filament was not loaded - i.e. extraPurgeNeeded == true cmd_intro_mmu_3, cmd_intro_mmu_4, cmd_intro_mmu_5, cmd_intro_mmu_6, zero_extrusion, cmd_intro_mmu_8, cmd_intro_mmu_9, cmd_intro_mmu_10, cmd_intro_mmu_11, }; if (MMU2::mmu2.Enabled()) { for (uint8_t i = (extraPurgeNeeded ? 0 : 2); i < (sizeof(cmd_intro_mmu)/sizeof(cmd_intro_mmu[0])); ++i) { enquecommand_P(static_cast(pgm_read_ptr(&cmd_intro_mmu[i]))); } } else { enquecommandf_P(extrude_fmt_X, (float)60, count_e(layer_height, extrusion_width * 4.f, 60)); enquecommandf_P(extrude_fmt_X, (float)202.5, count_e(layer_height, extrusion_width * 8.f, 142.5)); } } //! @brief Setup for printing meander void lay1cal_before_meander() { #ifndef NEW_FIRST_LAYER_CAL static const char cmd_pre_meander_4[] PROGMEM = "G1E-1.5F2100"; static const char cmd_pre_meander_5[] PROGMEM = "G1Z5F7200"; #endif //NEW_FIRST_LAYER_CAL static const char cmd_pre_meander_6[] PROGMEM = "M204S1000"; //set acceleration static const char * const cmd_pre_meander[] PROGMEM = { zero_extrusion, MSG_G90, MSG_M83, // use relative distances for extrusion #ifndef NEW_FIRST_LAYER_CAL cmd_pre_meander_4, cmd_pre_meander_5, #endif //NEW_FIRST_LAYER_CAL cmd_pre_meander_6, }; lay1cal_common_enqueue_loop(cmd_pre_meander, (sizeof(cmd_pre_meander)/sizeof(cmd_pre_meander[0]))); } //! @brief Print meander start void lay1cal_meander_start(float layer_height, float extrusion_width) { #ifndef NEW_FIRST_LAYER_CAL enquecommand_P(PSTR("G1X50Y155")); #endif //_NEW_FIRST_LAYER_CAL static const char fmt1[] PROGMEM = "G1Z%gF7200"; enquecommandf_P(fmt1, layer_height); enquecommand_P(PSTR("G1F1080")); #ifdef NEW_FIRST_LAYER_CAL enquecommandf_P(extrude_fmt_Y, short_length, count_e(layer_height, extrusion_width, short_length)); #endif //_NEW_FIRST_LAYER_CAL enquecommand_P(PSTR("G91")); #ifndef NEW_FIRST_LAYER_CAL enquecommandf_P(extrude_fmt_X, (float)25*invert, count_e(layer_height, extrusion_width * 4.f, 25)); enquecommandf_P(extrude_fmt_X, (float)25*invert, count_e(layer_height, extrusion_width * 2.f, 25)); enquecommandf_P(extrude_fmt_X, (float)100*invert, count_e(layer_height, extrusion_width, 100)); enquecommandf_P(extrude_fmt_Y, (float)-20*invert, count_e(layer_height, extrusion_width, 20)); #else enquecommandf_P(extrude_fmt_X, long_length*invert, count_e(layer_height, extrusion_width, long_length)); enquecommandf_P(extrude_fmt_Y, -short_length*invert, count_e(layer_height, extrusion_width, short_length)); #endif //_NEW_FIRST_LAYER_CAL } //! @brief Print meander //! @param cmd_buffer character buffer needed to format gcodes void lay1cal_meander(float layer_height, float extrusion_width) { const float long_extrusion = count_e(layer_height, extrusion_width, long_length); const float short_extrusion = count_e(layer_height, extrusion_width, short_length); float x_pos = long_length; for(uint8_t i = 0; i <= 4; ++i) { enquecommandf_P(extrude_fmt_X, -x_pos*invert, long_extrusion); x_pos = -x_pos; enquecommandf_P(extrude_fmt_Y, -short_length*invert, short_extrusion); } #ifdef NEW_FIRST_LAYER_CAL enquecommandf_P(extrude_fmt_X, -(long_length/2-square_width/2), long_extrusion); //~Middle of bed X125 enquecommandf_P(extrude_fmt_Y, short_length, short_extrusion); //~Middle of bed Y105 #endif //NEW_FIRST_LAYER_CAL } //! @brief Print square //! //! This function needs to be called 4 times with step of 0,4,8,12 //! //! @param cmd_buffer character buffer needed to format gcodes //! @param i iteration void lay1cal_square(uint8_t step, float layer_height, float extrusion_width) { const float Y_spacing = spacing(layer_height, extrusion_width); const float long_extrusion = count_e(layer_height, extrusion_width, square_width); const float short_extrusion = count_e(layer_height, extrusion_width, Y_spacing); for (uint8_t i = step; i < step+4; ++i) { enquecommandf_P(extrude_fmt_X, square_width*invert, long_extrusion); enquecommandf_P(extrude_fmt_Y, -Y_spacing*invert, short_extrusion); enquecommandf_P(extrude_fmt_X, -square_width*invert, long_extrusion); enquecommandf_P(extrude_fmt_Y, -Y_spacing*invert, short_extrusion); } } void lay1cal_finish() { static const char cmd_cal_finish_1[] PROGMEM = "G1E-0.075F2100"; // Retract static const char cmd_cal_finish_2[] PROGMEM = "M140S0"; // Turn off bed heater static const char cmd_cal_finish_3[] PROGMEM = "M104S0"; // Turn off hotend heater static const char cmd_cal_finish_4[] PROGMEM = "G1Z10F1300"; // Lift Z static const char cmd_cal_finish_5[] PROGMEM = "G1X10Y180F4000"; // Go to parking position static const char * const cmd_cal_finish[] PROGMEM = { MSG_G90, // Set to Absolute Positioning MSG_M107, // Turn off printer fan cmd_cal_finish_1, // Retract cmd_cal_finish_2, // Turn off bed heater MSG_M702, // Unload filament (MMU only) cmd_cal_finish_3, // Turn off hotend heater cmd_cal_finish_4, // Lift Z cmd_cal_finish_5, // Go to parking position MSG_M84 // Disable stepper motors }; lay1cal_common_enqueue_loop(cmd_cal_finish, (sizeof(cmd_cal_finish)/sizeof(cmd_cal_finish[0]))); }