static void lcd_menu_first_run_bed_level_paper_center() { LED_GLOW(); if (lcd_lib_encoder_pos == ENCODER_NO_SELECTION) lcd_lib_encoder_pos = 0; if (printing_state == PRINT_STATE_NORMAL && lcd_lib_encoder_pos != 0 && movesplanned() < 4) { current_position[Z_AXIS] -= float(lcd_lib_encoder_pos) * 0.05; lcd_lib_encoder_pos = 0; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 60, 0); } if (movesplanned() > 0) lcd_info_screen(NULL, NULL, PSTR("CONTINUE")); else lcd_info_screen(lcd_menu_first_run_bed_level_paper_left, storeHomingZ_parkHeadForLeftAdjustment, PSTR("CONTINUE")); DRAW_PROGRESS_NR(8); lcd_lib_draw_string_centerP(10, PSTR("Slide a paper between")); lcd_lib_draw_string_centerP(20, PSTR("buildplate and nozzle")); lcd_lib_draw_string_centerP(30, PSTR("until you feel a")); lcd_lib_draw_string_centerP(40, PSTR("bit resistance.")); lcd_lib_update_screen(); }
static void lcd_menu_first_run_bed_level_paper_center() { LED_GLOW(); if (lcd_lib_encoder_pos == ENCODER_NO_SELECTION) lcd_lib_encoder_pos = 0; if (printing_state == PRINT_STATE_NORMAL && lcd_lib_encoder_pos != 0 && movesplanned() < 4) { current_position[Z_AXIS] -= float(lcd_lib_encoder_pos) * 0.05; lcd_lib_encoder_pos = 0; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 60, 0); } if (movesplanned() > 0) lcd_info_screen(NULL, NULL, PSTR("POKRACOVAT")); else lcd_info_screen(lcd_menu_first_run_bed_level_paper_left, parkHeadForLeftAdjustment, PSTR("POKRACOVAT")); DRAW_PROGRESS_NR_IF_NOT_DONE(8); lcd_lib_draw_string_centerP(10, PSTR("Zasunte papir mezi")); lcd_lib_draw_string_centerP(20, PSTR("trysku a podlozku,")); lcd_lib_draw_string_centerP(30, PSTR("otacejte dokud")); lcd_lib_draw_string_centerP(40, PSTR("papir neklade odpor")); lcd_lib_update_screen(); }
static void lcd_menu_first_run_bed_level_center_adjust() { LED_GLOW(); if (lcd_lib_encoder_pos == ENCODER_NO_SELECTION) lcd_lib_encoder_pos = 0; if (printing_state == PRINT_STATE_NORMAL && lcd_lib_encoder_pos != 0 && movesplanned() < 4) { current_position[Z_AXIS] -= float(lcd_lib_encoder_pos) * 0.05; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 60, 0); } lcd_lib_encoder_pos = 0; if (movesplanned() > 0) lcd_info_screen(NULL, NULL, PSTR("CONTINUE")); else lcd_info_screen(lcd_menu_first_run_bed_level_left_adjust, storeHomingZ_parkHeadForLeftAdjustment, PSTR("CONTINUE")); DRAW_PROGRESS_NR(4); lcd_lib_draw_string_centerP(10, PSTR("Rotate the button")); lcd_lib_draw_string_centerP(20, PSTR("until the nozzle is")); lcd_lib_draw_string_centerP(30, PSTR("a millimeter away")); lcd_lib_draw_string_centerP(40, PSTR("from the buildplate.")); lcd_lib_update_screen(); }
static void lcd_menu_first_run_bed_level_center_adjust() { LED_GLOW(); if (lcd_lib_encoder_pos == ENCODER_NO_SELECTION) lcd_lib_encoder_pos = 0; if (printing_state == PRINT_STATE_NORMAL && lcd_lib_encoder_pos != 0 && movesplanned() < 4) { current_position[Z_AXIS] -= float(lcd_lib_encoder_pos) * 0.05; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 60, 0); } lcd_lib_encoder_pos = 0; if (movesplanned() > 0) lcd_info_screen(NULL, NULL, PSTR("POKRACOVAT")); else lcd_info_screen(lcd_menu_first_run_bed_level_left_adjust, parkHeadForLeftAdjustment, PSTR("POKRACOVAT")); DRAW_PROGRESS_NR_IF_NOT_DONE(4); lcd_lib_draw_string_centerP(10, PSTR("Otacejte tlacitkem")); lcd_lib_draw_string_centerP(20, PSTR("dokud nebude tryska")); lcd_lib_draw_string_centerP(30, PSTR("priblizne milimetr")); lcd_lib_draw_string_centerP(40, PSTR("od tiskove podlozky.")); lcd_lib_update_screen(); }
static char* tune_item_callback(uint8_t nr) { char* c = (char*)lcd_cache; if (nr == 0) strcpy_P(c, PSTR("< RETURN")); else if (nr == 1) { if (!card.pause) { if (movesplanned() > 0) strcpy_P(c, PSTR("Pause")); else strcpy_P(c, PSTR("Can not pause")); } else { if (movesplanned() < 1) strcpy_P(c, PSTR("Resume")); else strcpy_P(c, PSTR("Pausing...")); } } else if (nr == 2) strcpy_P(c, PSTR("Speed")); else if (nr == 3) strcpy_P(c, PSTR("Temperature")); #if EXTRUDERS > 1 else if (nr == 4) strcpy_P(c, PSTR("Temperature 2")); #endif else if (nr == 3 + EXTRUDERS) strcpy_P(c, PSTR("Buildplate temp.")); else if (nr == 4 + EXTRUDERS) strcpy_P(c, PSTR("Fan speed")); else if (nr == 5 + EXTRUDERS) strcpy_P(c, PSTR("Material flow")); #if EXTRUDERS > 1 else if (nr == 6 + EXTRUDERS) strcpy_P(c, PSTR("Material flow 2")); #endif else if (nr == 5 + EXTRUDERS * 2) strcpy_P(c, PSTR("Retraction")); else if (nr == 6 + EXTRUDERS * 2) strcpy_P(c, PSTR("LED Brightness")); else if (nr == 7 + EXTRUDERS * 2) strcpy_P(c, PSTR("Babystep X")); else if (nr == 8 + EXTRUDERS * 2) strcpy_P(c, PSTR("Babystep Y")); else if (nr == 9 + EXTRUDERS * 2) strcpy_P(c, PSTR("Babystep Z")); return c; }
/* Menu implementation */ static void lcd_main_menu() { START_MENU(); MENU_ITEM(back, MSG_WATCH, lcd_status_screen); #ifdef LASER if (!(movesplanned() || IS_SD_PRINTING)) { MENU_ITEM(submenu, "Laser Functions", lcd_laser_menu); } #endif if (movesplanned() || IS_SD_PRINTING) { MENU_ITEM(submenu, MSG_TUNE, lcd_tune_menu); }else{ MENU_ITEM(submenu, MSG_PREPARE, lcd_prepare_menu); } MENU_ITEM(submenu, MSG_CONTROL, lcd_control_menu); #ifdef SDSUPPORT if (card.cardOK) { if (card.isFileOpen()) { if (card.sdprinting) MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause); else MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume); MENU_ITEM(function, MSG_STOP_PRINT, lcd_sdcard_stop); }else{ MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu); #if SDCARDDETECT < 1 MENU_ITEM(gcode, MSG_CNG_SDCARD, PSTR("M21")); // SD-card changed by user #endif } }else{ MENU_ITEM(submenu, MSG_NO_CARD, lcd_sdcard_menu); #if SDCARDDETECT < 1 MENU_ITEM(gcode, MSG_INIT_SDCARD, PSTR("M21")); // Manually initialize the SD-card via user interface #endif } #endif END_MENU(); }
////iSM static void lcd_main_menu() { START_MENU(); MENU_ITEM(back, MSG_WATCH, lcd_status_screen); if (movesplanned() || IS_SD_PRINTING) { MENU_ITEM(submenu, MSG_TUNE, lcd_tune_menu);//1 } #ifdef SDSUPPORT if (card.cardOK) { if (card.isFileOpen()) { if (card.sdprinting) //MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause); MENU_ITEM(gcode, MSG_FILAMENT_CH, PSTR("M600")); else MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume); MENU_ITEM(function, MSG_STOP_PRINT, lcd_sdcard_stop); }else{ MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu); #if SDCARDDETECT < 1 MENU_ITEM(gcode, MSG_CNG_SDCARD, PSTR("M21")); // SD-card changed by user #endif } }else{ MENU_ITEM(submenu, MSG_NO_CARD, lcd_sdcard_menu); #if SDCARDDETECT < 1 MENU_ITEM(gcode, MSG_INIT_SDCARD, PSTR("M21")); // Manually initialize the SD-card via user interface #endif } #endif if (!movesplanned() && !IS_SD_PRINTING) { MENU_ITEM(submenu, MSG_FILAMENTO, lcd_filamento_menu);//2 MENU_ITEM(submenu, MSG_PRECALENTAR, lcd_precalentar_menu);//3 MENU_ITEM(submenu, MSG_HERRAMIENTAS, lcd_herramientas_menu);//4 } END_MENU(); }
static void lcd_sdcard_pause() { card.pauseSDPrint(); if (movesplanned() > 0) { waituntilbufferavailable(); if (current_position[Z_AXIS] < Z_MAX_POS - 25) enquecommand_P(PSTR("M601 X10 Y20 Z20 L30")); else if (current_position[Z_AXIS] < Z_MAX_POS -5) enquecommand_P(PSTR("M601 X10 Y20 Z2 L30")); else enquecommand_P(PSTR("M601 X10 Y20 Z0 L30")); } }
static void lcd_laser_menu() { START_MENU(); MENU_ITEM(back, MSG_MAIN, lcd_main_menu); MENU_ITEM(submenu, "Set Focus", lcd_laser_focus_menu); MENU_ITEM(submenu, "Test Fire", lcd_laser_test_fire_menu); #ifdef LASER_PERIPHERALS if (laser_peripherals_ok()) { MENU_ITEM(function, "Turn On Pumps/Fans", action_laser_acc_on); } else if (!(movesplanned() || IS_SD_PRINTING)) { MENU_ITEM(function, "Turn Off Pumps/Fans", action_laser_acc_off); } #endif // LASER_PERIPHERALS END_MENU(); }
static void lcd_move_e() { if (blocking_enc>=millis() || LCD_CLICKED) { while (movesplanned() < 3) { current_position[E_AXIS] += 0.5; lcd_implementation_drawedit(PSTR("Extruder"), ftostr31(current_position[E_AXIS])); plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3, active_extruder); } }else{ lcd_quick_feedback(); currentMenu = lcd_move_menu_axis; encoderPosition = prevEncoderPosition; } }
static void lcd_menu_change_material_insert() { LED_GLOW(); lcd_question_screen(lcd_menu_change_material_select_material, materialInsertReady, PSTR("READY"), lcd_menu_main, cancelMaterialInsert, PSTR("CANCEL")); lcd_lib_draw_string_centerP(20, PSTR("Wait till material")); lcd_lib_draw_string_centerP(30, PSTR("comes out the nozzle")); if (movesplanned() < 2) { current_position[E_AXIS] += 0.5; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENT_INSERT_EXTRUDE_SPEED, active_extruder); } lcd_lib_update_screen(); }
static void lcd_menu_change_material_insert() { LED_GLOW(); lcd_question_screen(post_change_material_menu, materialInsertReady, PSTR("READY"), post_change_material_menu, cancelMaterialInsert, PSTR("CANCEL")); lcd_lib_draw_string_centerP(20, PSTR("Wait till material")); lcd_lib_draw_string_centerP(30, PSTR("comes out the nozzle")); if (movesplanned() < 2) { plan_set_e_position(0); plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], 0.5 / volume_to_filament_length[active_extruder], FILAMENT_INSERT_EXTRUDE_SPEED, active_extruder); } lcd_lib_update_screen(); }
static void lcd_menu_change_material_insert_wait_user() { LED_GLOW(); if (printing_state == PRINT_STATE_NORMAL && movesplanned() < 2) { current_position[E_AXIS] += 0.5; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENT_INSERT_SPEED, active_extruder); } lcd_question_screen(NULL, lcd_menu_change_material_insert_wait_user_ready, PSTR("READY"), lcd_menu_main, cancelMaterialInsert, PSTR("CANCEL")); lcd_lib_draw_string_centerP(10, PSTR("Insert new material")); lcd_lib_draw_string_centerP(20, PSTR("from the backside of")); lcd_lib_draw_string_centerP(30, PSTR("your machine,")); lcd_lib_draw_string_centerP(40, PSTR("above the arrow.")); lcd_lib_update_screen(); }
static void lcd_menu_first_run_material_load_wait() { LED_GLOW(); lcd_info_screen(lcd_menu_first_run_material_select_1, doCooldown, PSTR("CONTINUE")); DRAW_PROGRESS_NR(15); lcd_lib_draw_string_centerP(10, PSTR("Push button when")); lcd_lib_draw_string_centerP(20, PSTR("material exits")); lcd_lib_draw_string_centerP(30, PSTR("from nozzle...")); if (movesplanned() < 2) { current_position[E_AXIS] += 0.5; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENT_INSERT_EXTRUDE_SPEED, 0); } lcd_lib_update_screen(); }
static void lcd_menu_first_run_material_load_insert() { LED_GLOW(); if (movesplanned() < 2) { current_position[E_AXIS] += 0.5; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENT_INSERT_SPEED, 0); } SELECT_MAIN_MENU_ITEM(0); lcd_info_screen(lcd_menu_first_run_material_load_forward, runMaterialForward, PSTR("CONTINUE")); DRAW_PROGRESS_NR(13); lcd_lib_draw_string_centerP(10, PSTR("Insert new material")); lcd_lib_draw_string_centerP(20, PSTR("from the rear of")); lcd_lib_draw_string_centerP(30, PSTR("your Ultimaker2,")); lcd_lib_draw_string_centerP(40, PSTR("above the arrow.")); lcd_lib_update_screen(); }
/** * recalculate() needs to go over the current plan twice. * Once in reverse and once forward. This implements the reverse pass. */ void Planner::reverse_pass() { if (movesplanned() > 3) { block_t* block[3] = { NULL, NULL, NULL }; // Make a local copy of block_buffer_tail, because the interrupt can alter it CRITICAL_SECTION_START; uint8_t tail = block_buffer_tail; CRITICAL_SECTION_END uint8_t b = BLOCK_MOD(block_buffer_head - 3); while (b != tail) { b = prev_block_index(b); block[2] = block[1]; block[1] = block[0]; block[0] = &block_buffer[b]; reverse_pass_kernel(block[0], block[1], block[2]); } } }
void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t extruder) #endif // AUTO_BED_LEVELING_FEATURE { // Calculate the buffer head after we push this byte int next_buffer_head = next_block_index(block_buffer_head); // If the buffer is full: good! That means we are well ahead of the robot. // Rest here until there is room in the buffer. while (block_buffer_tail == next_buffer_head) idle(); #if ENABLED(MESH_BED_LEVELING) if (mbl.active) z += mbl.get_z(x, y); #elif ENABLED(AUTO_BED_LEVELING_FEATURE) apply_rotation_xyz(plan_bed_level_matrix, x, y, z); #endif // The target position of the tool in absolute steps // Calculate target position in absolute steps //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow long target[NUM_AXIS]; target[X_AXIS] = lround(x * axis_steps_per_unit[X_AXIS]); target[Y_AXIS] = lround(y * axis_steps_per_unit[Y_AXIS]); target[Z_AXIS] = lround(z * axis_steps_per_unit[Z_AXIS]); target[E_AXIS] = lround(e * axis_steps_per_unit[E_AXIS]); float dx = target[X_AXIS] - position[X_AXIS], dy = target[Y_AXIS] - position[Y_AXIS], dz = target[Z_AXIS] - position[Z_AXIS]; // DRYRUN ignores all temperature constraints and assures that the extruder is instantly satisfied if (marlin_debug_flags & DEBUG_DRYRUN) position[E_AXIS] = target[E_AXIS]; float de = target[E_AXIS] - position[E_AXIS]; #if ENABLED(PREVENT_DANGEROUS_EXTRUDE) if (de) { if (degHotend(extruder) < extrude_min_temp) { position[E_AXIS] = target[E_AXIS]; // Behave as if the move really took place, but ignore E part de = 0; // no difference SERIAL_ECHO_START; SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP); } #if ENABLED(PREVENT_LENGTHY_EXTRUDE) if (labs(de) > axis_steps_per_unit[E_AXIS] * EXTRUDE_MAXLENGTH) { position[E_AXIS] = target[E_AXIS]; // Behave as if the move really took place, but ignore E part de = 0; // no difference SERIAL_ECHO_START; SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP); } #endif } #endif // Prepare to set up new block block_t *block = &block_buffer[block_buffer_head]; // Mark block as not busy (Not executed by the stepper interrupt) block->busy = false; // Number of steps for each axis #if ENABLED(COREXY) // corexy planning // these equations follow the form of the dA and dB equations on http://www.corexy.com/theory.html block->steps[A_AXIS] = labs(dx + dy); block->steps[B_AXIS] = labs(dx - dy); block->steps[Z_AXIS] = labs(dz); #elif ENABLED(COREXZ) // corexz planning block->steps[A_AXIS] = labs(dx + dz); block->steps[Y_AXIS] = labs(dy); block->steps[C_AXIS] = labs(dx - dz); #else // default non-h-bot planning block->steps[X_AXIS] = labs(dx); block->steps[Y_AXIS] = labs(dy); block->steps[Z_AXIS] = labs(dz); #endif block->steps[E_AXIS] = labs(de); block->steps[E_AXIS] *= volumetric_multiplier[extruder]; block->steps[E_AXIS] *= extruder_multiplier[extruder]; block->steps[E_AXIS] /= 100; block->step_event_count = max(block->steps[X_AXIS], max(block->steps[Y_AXIS], max(block->steps[Z_AXIS], block->steps[E_AXIS]))); // Bail if this is a zero-length block if (block->step_event_count <= dropsegments) return; block->fan_speed = fanSpeed; #if ENABLED(BARICUDA) block->valve_pressure = ValvePressure; block->e_to_p_pressure = EtoPPressure; #endif // Compute direction bits for this block uint8_t db = 0; #if ENABLED(COREXY) if (dx < 0) db |= BIT(X_HEAD); // Save the real Extruder (head) direction in X Axis if (dy < 0) db |= BIT(Y_HEAD); // ...and Y if (dz < 0) db |= BIT(Z_AXIS); if (dx + dy < 0) db |= BIT(A_AXIS); // Motor A direction if (dx - dy < 0) db |= BIT(B_AXIS); // Motor B direction #elif ENABLED(COREXZ) if (dx < 0) db |= BIT(X_HEAD); // Save the real Extruder (head) direction in X Axis if (dy < 0) db |= BIT(Y_AXIS); if (dz < 0) db |= BIT(Z_HEAD); // ...and Z if (dx + dz < 0) db |= BIT(A_AXIS); // Motor A direction if (dx - dz < 0) db |= BIT(C_AXIS); // Motor B direction #else if (dx < 0) db |= BIT(X_AXIS); if (dy < 0) db |= BIT(Y_AXIS); if (dz < 0) db |= BIT(Z_AXIS); #endif if (de < 0) db |= BIT(E_AXIS); block->direction_bits = db; block->active_extruder = extruder; //enable active axes #if ENABLED(COREXY) if (block->steps[A_AXIS] || block->steps[B_AXIS]) { enable_x(); enable_y(); } #if DISABLED(Z_LATE_ENABLE) if (block->steps[Z_AXIS]) enable_z(); #endif #elif ENABLED(COREXZ) if (block->steps[A_AXIS] || block->steps[C_AXIS]) { enable_x(); enable_z(); } if (block->steps[Y_AXIS]) enable_y(); #else if (block->steps[X_AXIS]) enable_x(); if (block->steps[Y_AXIS]) enable_y(); #if DISABLED(Z_LATE_ENABLE) if (block->steps[Z_AXIS]) enable_z(); #endif #endif // Enable extruder(s) if (block->steps[E_AXIS]) { if (DISABLE_INACTIVE_EXTRUDER) { //enable only selected extruder for (int i=0; i<EXTRUDERS; i++) if (g_uc_extruder_last_move[i] > 0) g_uc_extruder_last_move[i]--; switch(extruder) { case 0: enable_e0(); g_uc_extruder_last_move[0] = BLOCK_BUFFER_SIZE * 2; #if EXTRUDERS > 1 if (g_uc_extruder_last_move[1] == 0) disable_e1(); #if EXTRUDERS > 2 if (g_uc_extruder_last_move[2] == 0) disable_e2(); #if EXTRUDERS > 3 if (g_uc_extruder_last_move[3] == 0) disable_e3(); #endif #endif #endif break; #if EXTRUDERS > 1 case 1: enable_e1(); g_uc_extruder_last_move[1] = BLOCK_BUFFER_SIZE * 2; if (g_uc_extruder_last_move[0] == 0) disable_e0(); #if EXTRUDERS > 2 if (g_uc_extruder_last_move[2] == 0) disable_e2(); #if EXTRUDERS > 3 if (g_uc_extruder_last_move[3] == 0) disable_e3(); #endif #endif break; #if EXTRUDERS > 2 case 2: enable_e2(); g_uc_extruder_last_move[2] = BLOCK_BUFFER_SIZE * 2; if (g_uc_extruder_last_move[0] == 0) disable_e0(); if (g_uc_extruder_last_move[1] == 0) disable_e1(); #if EXTRUDERS > 3 if (g_uc_extruder_last_move[3] == 0) disable_e3(); #endif break; #if EXTRUDERS > 3 case 3: enable_e3(); g_uc_extruder_last_move[3] = BLOCK_BUFFER_SIZE * 2; if (g_uc_extruder_last_move[0] == 0) disable_e0(); if (g_uc_extruder_last_move[1] == 0) disable_e1(); if (g_uc_extruder_last_move[2] == 0) disable_e2(); break; #endif // EXTRUDERS > 3 #endif // EXTRUDERS > 2 #endif // EXTRUDERS > 1 } } else { // enable all enable_e0(); enable_e1(); enable_e2(); enable_e3(); } } if (block->steps[E_AXIS]) NOLESS(feed_rate, minimumfeedrate); else NOLESS(feed_rate, mintravelfeedrate); /** * This part of the code calculates the total length of the movement. * For cartesian bots, the X_AXIS is the real X movement and same for Y_AXIS. * But for corexy bots, that is not true. The "X_AXIS" and "Y_AXIS" motors (that should be named to A_AXIS * and B_AXIS) cannot be used for X and Y length, because A=X+Y and B=X-Y. * So we need to create other 2 "AXIS", named X_HEAD and Y_HEAD, meaning the real displacement of the Head. * Having the real displacement of the head, we can calculate the total movement length and apply the desired speed. */ #if ENABLED(COREXY) float delta_mm[6]; delta_mm[X_HEAD] = dx / axis_steps_per_unit[A_AXIS]; delta_mm[Y_HEAD] = dy / axis_steps_per_unit[B_AXIS]; delta_mm[Z_AXIS] = dz / axis_steps_per_unit[Z_AXIS]; delta_mm[A_AXIS] = (dx + dy) / axis_steps_per_unit[A_AXIS]; delta_mm[B_AXIS] = (dx - dy) / axis_steps_per_unit[B_AXIS]; #elif ENABLED(COREXZ) float delta_mm[6]; delta_mm[X_HEAD] = dx / axis_steps_per_unit[A_AXIS]; delta_mm[Y_AXIS] = dy / axis_steps_per_unit[Y_AXIS]; delta_mm[Z_HEAD] = dz / axis_steps_per_unit[C_AXIS]; delta_mm[A_AXIS] = (dx + dz) / axis_steps_per_unit[A_AXIS]; delta_mm[C_AXIS] = (dx - dz) / axis_steps_per_unit[C_AXIS]; #else float delta_mm[4]; delta_mm[X_AXIS] = dx / axis_steps_per_unit[X_AXIS]; delta_mm[Y_AXIS] = dy / axis_steps_per_unit[Y_AXIS]; delta_mm[Z_AXIS] = dz / axis_steps_per_unit[Z_AXIS]; #endif delta_mm[E_AXIS] = (de / axis_steps_per_unit[E_AXIS]) * volumetric_multiplier[extruder] * extruder_multiplier[extruder] / 100.0; if (block->steps[X_AXIS] <= dropsegments && block->steps[Y_AXIS] <= dropsegments && block->steps[Z_AXIS] <= dropsegments) { block->millimeters = fabs(delta_mm[E_AXIS]); } else { block->millimeters = sqrt( #if ENABLED(COREXY) square(delta_mm[X_HEAD]) + square(delta_mm[Y_HEAD]) + square(delta_mm[Z_AXIS]) #elif ENABLED(COREXZ) square(delta_mm[X_HEAD]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_HEAD]) #else square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_AXIS]) #endif ); } float inverse_millimeters = 1.0 / block->millimeters; // Inverse millimeters to remove multiple divides // Calculate speed in mm/second for each axis. No divide by zero due to previous checks. float inverse_second = feed_rate * inverse_millimeters; int moves_queued = movesplanned(); // Slow down when the buffer starts to empty, rather than wait at the corner for a buffer refill #if ENABLED(OLD_SLOWDOWN) || ENABLED(SLOWDOWN) bool mq = moves_queued > 1 && moves_queued < BLOCK_BUFFER_SIZE / 2; #if ENABLED(OLD_SLOWDOWN) if (mq) feed_rate *= 2.0 * moves_queued / BLOCK_BUFFER_SIZE; #endif #if ENABLED(SLOWDOWN) // segment time im micro seconds unsigned long segment_time = lround(1000000.0/inverse_second); if (mq) { if (segment_time < minsegmenttime) { // buffer is draining, add extra time. The amount of time added increases if the buffer is still emptied more. inverse_second = 1000000.0 / (segment_time + lround(2 * (minsegmenttime - segment_time) / moves_queued)); #ifdef XY_FREQUENCY_LIMIT segment_time = lround(1000000.0 / inverse_second); #endif } } #endif #endif 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 #if ENABLED(FILAMENT_SENSOR) //FMM update ring buffer used for delay with filament measurements if (extruder == FILAMENT_SENSOR_EXTRUDER_NUM && delay_index2 > -1) { //only for extruder with filament sensor and if ring buffer is initialized const int MMD = MAX_MEASUREMENT_DELAY + 1, MMD10 = MMD * 10; delay_dist += delta_mm[E_AXIS]; // increment counter with next move in e axis while (delay_dist >= MMD10) delay_dist -= MMD10; // loop around the buffer while (delay_dist < 0) delay_dist += MMD10; delay_index1 = delay_dist / 10.0; // calculate index delay_index1 = constrain(delay_index1, 0, MAX_MEASUREMENT_DELAY); // (already constrained above) if (delay_index1 != delay_index2) { // moved index meas_sample = widthFil_to_size_ratio() - 100; // Subtract 100 to reduce magnitude - to store in a signed char while (delay_index1 != delay_index2) { // Increment and loop around buffer if (++delay_index2 >= MMD) delay_index2 -= MMD; delay_index2 = constrain(delay_index2, 0, MAX_MEASUREMENT_DELAY); measurement_delay[delay_index2] = meas_sample; } } } #endif // Calculate and limit speed in mm/sec for each axis float current_speed[NUM_AXIS]; float speed_factor = 1.0; //factor <=1 do decrease speed for (int i = 0; i < NUM_AXIS; i++) { current_speed[i] = delta_mm[i] * inverse_second; float cs = fabs(current_speed[i]), mf = max_feedrate[i]; if (cs > mf) speed_factor = min(speed_factor, mf / cs); } // Max segement time in us. #ifdef XY_FREQUENCY_LIMIT #define MAX_FREQ_TIME (1000000.0 / XY_FREQUENCY_LIMIT) // Check and limit the xy direction change frequency unsigned char direction_change = block->direction_bits ^ old_direction_bits; old_direction_bits = block->direction_bits; segment_time = lround((float)segment_time / speed_factor); long xs0 = axis_segment_time[X_AXIS][0], xs1 = axis_segment_time[X_AXIS][1], xs2 = axis_segment_time[X_AXIS][2], ys0 = axis_segment_time[Y_AXIS][0], ys1 = axis_segment_time[Y_AXIS][1], ys2 = axis_segment_time[Y_AXIS][2]; if ((direction_change & BIT(X_AXIS)) != 0) { xs2 = axis_segment_time[X_AXIS][2] = xs1; xs1 = axis_segment_time[X_AXIS][1] = xs0; xs0 = 0; } xs0 = axis_segment_time[X_AXIS][0] = xs0 + segment_time; if ((direction_change & BIT(Y_AXIS)) != 0) { ys2 = axis_segment_time[Y_AXIS][2] = axis_segment_time[Y_AXIS][1]; ys1 = axis_segment_time[Y_AXIS][1] = axis_segment_time[Y_AXIS][0]; ys0 = 0; } ys0 = axis_segment_time[Y_AXIS][0] = ys0 + segment_time; long max_x_segment_time = max(xs0, max(xs1, xs2)), max_y_segment_time = max(ys0, max(ys1, ys2)), min_xy_segment_time = min(max_x_segment_time, max_y_segment_time); if (min_xy_segment_time < MAX_FREQ_TIME) { float low_sf = speed_factor * min_xy_segment_time / MAX_FREQ_TIME; speed_factor = min(speed_factor, low_sf); } #endif // XY_FREQUENCY_LIMIT // Correct the speed if (speed_factor < 1.0) { for (unsigned char i = 0; i < NUM_AXIS; i++) current_speed[i] *= speed_factor; block->nominal_speed *= speed_factor; block->nominal_rate *= speed_factor; } // Compute and limit the acceleration rate for the trapezoid generator. float steps_per_mm = block->step_event_count / block->millimeters; long bsx = block->steps[X_AXIS], bsy = block->steps[Y_AXIS], bsz = block->steps[Z_AXIS], bse = block->steps[E_AXIS]; if (bsx == 0 && bsy == 0 && bsz == 0) { block->acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 } else if (bse == 0) { block->acceleration_st = ceil(travel_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 } else { block->acceleration_st = ceil(acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 } // Limit acceleration per axis unsigned long acc_st = block->acceleration_st, xsteps = axis_steps_per_sqr_second[X_AXIS], ysteps = axis_steps_per_sqr_second[Y_AXIS], zsteps = axis_steps_per_sqr_second[Z_AXIS], esteps = axis_steps_per_sqr_second[E_AXIS]; if ((float)acc_st * bsx / block->step_event_count > xsteps) acc_st = xsteps; if ((float)acc_st * bsy / block->step_event_count > ysteps) acc_st = ysteps; if ((float)acc_st * bsz / block->step_event_count > zsteps) acc_st = zsteps; if ((float)acc_st * bse / block->step_event_count > esteps) acc_st = esteps; block->acceleration_st = acc_st; block->acceleration = acc_st / steps_per_mm; block->acceleration_rate = (long)(acc_st * 16777216.0 / (F_CPU / 8.0)); #if 0 // Use old jerk for now // Compute path unit vector double unit_vec[3]; unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters; unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters; unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters; // Compute maximum allowable entry speed at junction by centripetal acceleration approximation. // Let a circle be tangent to both previous and current path line segments, where the junction // deviation is defined as the distance from the junction to the closest edge of the circle, // colinear with the circle center. The circular segment joining the two paths represents the // path of centripetal acceleration. Solve for max velocity based on max acceleration about the // radius of the circle, defined indirectly by junction deviation. This may be also viewed as // path width or max_jerk in the previous grbl version. This approach does not actually deviate // from path, but used as a robust way to compute cornering speeds, as it takes into account the // nonlinearities of both the junction angle and junction velocity. double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles. if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) { // Compute cosine of angle between previous and current path. (prev_unit_vec is negative) // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity. double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS] - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS] - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ; // Skip and use default max junction speed for 0 degree acute junction. if (cos_theta < 0.95) { vmax_junction = min(previous_nominal_speed,block->nominal_speed); // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds. if (cos_theta > -0.95) { // Compute maximum junction velocity based on maximum acceleration and junction deviation double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive. vmax_junction = min(vmax_junction, sqrt(block->acceleration * junction_deviation * sin_theta_d2/(1.0-sin_theta_d2)) ); } } } #endif // Start with a safe speed float vmax_junction = max_xy_jerk / 2; float vmax_junction_factor = 1.0; float mz2 = max_z_jerk / 2, me2 = max_e_jerk / 2; float csz = current_speed[Z_AXIS], cse = current_speed[E_AXIS]; if (fabs(csz) > mz2) vmax_junction = min(vmax_junction, mz2); if (fabs(cse) > me2) vmax_junction = min(vmax_junction, me2); vmax_junction = min(vmax_junction, block->nominal_speed); float safe_speed = vmax_junction; if ((moves_queued > 1) && (previous_nominal_speed > 0.0001)) { float dx = current_speed[X_AXIS] - previous_speed[X_AXIS], dy = current_speed[Y_AXIS] - previous_speed[Y_AXIS], dz = fabs(csz - previous_speed[Z_AXIS]), de = fabs(cse - previous_speed[E_AXIS]), jerk = sqrt(dx * dx + dy * dy); // if ((fabs(previous_speed[X_AXIS]) > 0.0001) || (fabs(previous_speed[Y_AXIS]) > 0.0001)) { vmax_junction = block->nominal_speed; // } if (jerk > max_xy_jerk) vmax_junction_factor = max_xy_jerk / jerk; if (dz > max_z_jerk) vmax_junction_factor = min(vmax_junction_factor, max_z_jerk / dz); if (de > max_e_jerk) vmax_junction_factor = min(vmax_junction_factor, max_e_jerk / de); vmax_junction = min(previous_nominal_speed, vmax_junction * vmax_junction_factor); // Limit speed to max previous speed } block->max_entry_speed = vmax_junction; // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED. double v_allowable = max_allowable_speed(-block->acceleration, MINIMUM_PLANNER_SPEED, block->millimeters); block->entry_speed = min(vmax_junction, v_allowable); // Initialize planner efficiency flags // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds. // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then // the current block and next block junction speeds are guaranteed to always be at their maximum // junction speeds in deceleration and acceleration, respectively. This is due to how the current // block nominal speed limits both the current and next maximum junction speeds. Hence, in both // the reverse and forward planners, the corresponding block junction speed will always be at the // the maximum junction speed and may always be ignored for any speed reduction checks. block->nominal_length_flag = (block->nominal_speed <= v_allowable); block->recalculate_flag = true; // Always calculate trapezoid for new block // Update previous path unit_vector and nominal speed for (int i = 0; i < NUM_AXIS; i++) previous_speed[i] = current_speed[i]; previous_nominal_speed = block->nominal_speed; #if ENABLED(ADVANCE) // Calculate advance rate if (!bse || (!bsx && !bsy && !bsz)) { block->advance_rate = 0; block->advance = 0; } else { long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st); float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * (cse * cse * EXTRUSION_AREA * EXTRUSION_AREA) * 256; block->advance = advance; block->advance_rate = acc_dist ? advance / (float)acc_dist : 0; } /* SERIAL_ECHO_START; SERIAL_ECHOPGM("advance :"); SERIAL_ECHO(block->advance/256.0); SERIAL_ECHOPGM("advance rate :"); SERIAL_ECHOLN(block->advance_rate/256.0); */ #endif // ADVANCE calculate_trapezoid_for_block(block, block->entry_speed / block->nominal_speed, safe_speed / block->nominal_speed); // Move buffer head block_buffer_head = next_buffer_head; // Update position for (int i = 0; i < NUM_AXIS; i++) position[i] = target[i]; planner_recalculate(); st_wake_up(); } // plan_buffer_line()
static void lcd_menu_print_tune() { lcd_scroll_menu(PSTR("TUNE"), 7 + EXTRUDERS * 2, tune_item_callback, tune_item_details_callback); if (lcd_lib_button_pressed) { if (IS_SELECTED_SCROLL(0)) { if (card.sdprinting) lcd_change_to_menu(lcd_menu_print_printing); else lcd_change_to_menu(lcd_menu_print_heatup); }else if (IS_SELECTED_SCROLL(1)) { if (card.sdprinting) { if (card.pause) { if (movesplanned() < 1) { card.pause = false; lcd_lib_beep(); } } else { if (movesplanned() > 0 && commands_queued() < BUFSIZE) { lcd_lib_beep(); card.pause = true; if (current_position[Z_AXIS] < 170) enquecommand_P(PSTR("M601 X10 Y20 Z20 L30")); else if (current_position[Z_AXIS] < 200) enquecommand_P(PSTR("M601 X10 Y20 Z2 L30")); else enquecommand_P(PSTR("M601 X10 Y20 Z0 L30")); } } } }else if (IS_SELECTED_SCROLL(2)) LCD_EDIT_SETTING(feedmultiply, "Print speed", "%", 10, 1000); else if (IS_SELECTED_SCROLL(3)) lcd_change_to_menu(lcd_menu_print_tune_heatup_nozzle0, 0); #if EXTRUDERS > 1 else if (IS_SELECTED_SCROLL(4)) lcd_change_to_menu(lcd_menu_print_tune_heatup_nozzle1, 0); #endif else if (IS_SELECTED_SCROLL(3 + EXTRUDERS)) lcd_change_to_menu(lcd_menu_maintenance_advanced_bed_heatup, 0);//Use the maintainace heatup menu, which shows the current temperature. else if (IS_SELECTED_SCROLL(4 + EXTRUDERS)) LCD_EDIT_SETTING_BYTE_PERCENT(fanSpeed, "Fan speed", "%", 0, 100); else if (IS_SELECTED_SCROLL(5 + EXTRUDERS)) LCD_EDIT_SETTING(extrudemultiply[0], "Material flow", "%", 10, 1000); #if EXTRUDERS > 1 else if (IS_SELECTED_SCROLL(6 + EXTRUDERS)) LCD_EDIT_SETTING(extrudemultiply[1], "Material flow 2", "%", 10, 1000); #endif else if (IS_SELECTED_SCROLL(5 + EXTRUDERS * 2)) lcd_change_to_menu(lcd_menu_print_tune_retraction); else if (IS_SELECTED_SCROLL(6 + EXTRUDERS * 2)) LCD_EDIT_SETTING(led_brightness_level, "Brightness", "%", 0, 100); } }
static void lcd_main_menu() { SDscrool = 0; START_MENU(); // Majkl superawesome menu MENU_ITEM(back, MSG_WATCH, lcd_status_screen); if (movesplanned() || IS_SD_PRINTING) { MENU_ITEM(submenu, MSG_TUNE, lcd_tune_menu); }else{ MENU_ITEM(submenu, MSG_PREHEAT, lcd_preheat_menu); } #ifdef SDSUPPORT if (card.cardOK) { if (card.isFileOpen()) { if (card.sdprinting) MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause); else MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume); MENU_ITEM(function, MSG_STOP_PRINT, lcd_sdcard_stop); }else{ MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu); #if SDCARDDETECT < 1 MENU_ITEM(gcode, MSG_CNG_SDCARD, PSTR("M21")); // SD-card changed by user #endif } }else{ MENU_ITEM(submenu, MSG_NO_CARD, lcd_sdcard_menu); #if SDCARDDETECT < 1 MENU_ITEM(gcode, MSG_INIT_SDCARD, PSTR("M21")); // Manually initialize the SD-card via user interface #endif } #endif if (IS_SD_PRINTING) { }else{ MENU_ITEM(function, MSG_LOAD_FILAMENT, lcd_LoadFilament); MENU_ITEM(function, MSG_UNLOAD_FILAMENT, lcd_unLoadFilament); MENU_ITEM(submenu, MSG_SETTINGS, lcd_settings_menu); } MENU_ITEM(submenu, MSG_SUPPORT, lcd_support_menu); END_MENU(); }