Prusa-Firmware/Firmware/first_lay_cal.cpp

269 lines
9.9 KiB
C++

//! @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 <avr/pgmspace.h>
#include <math.h>
//! @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<char*>(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<char*>(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 enqueues 4 lines of the square, so it needs to be called multiple times
//!
//! @param cmd_buffer character buffer needed to format gcodes
void lay1cal_square(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 = 0; i < 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
cmd_cal_finish_4, // Lift Z
cmd_cal_finish_5, // Go to parking position
MSG_M702, // Unload filament (MMU only)
cmd_cal_finish_3, // Turn off hotend heater
MSG_M84 // Disable stepper motors
};
lay1cal_common_enqueue_loop(cmd_cal_finish, (sizeof(cmd_cal_finish)/sizeof(cmd_cal_finish[0])));
}