Ensure smooth print moves even with LCD enabled
lcd_update can take so much time that the block buffer gets drained if there are only short segments. This leads to jerky printer movements for example in circles and a bad print quality. This change implements a simple check: Only if the block currently executed is long enough, run lcd_update. This also means the printer will not show actual values on the LCD nor will it respond to buttons pressed. A option that keeps the menu accessible is also available. Aditionaly, slow down if a block would be so fast that adding a new block to the buffer would take more time. In this case, the buffer would drain until it's empty in worst case.
This commit is contained in:
parent
0be6167f14
commit
de89dc9f04
4 changed files with 68 additions and 9 deletions
|
@ -496,6 +496,26 @@
|
||||||
#define BABYSTEP_MULTIPLICATOR 1 //faster movements
|
#define BABYSTEP_MULTIPLICATOR 1 //faster movements
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Enabling ENSURE_SMOOTH_MOVES ensures your printer will never stutter (for example in circles with a short segments). That's done in two steps:
|
||||||
|
// --1--
|
||||||
|
// During short segments like in circles, the update of the LCD Display can take so long that the block buffer gets completely drained.
|
||||||
|
// If that happens, the movement of the printer gets very jerky until a longer segment like a longer straight line allows the buffer
|
||||||
|
// to be filled again. This small stops also effects print quality in a bad way.
|
||||||
|
// Enable ENSURE_SMOOTH_MOVES to update the LCD only when there is enough time during a move to do so.
|
||||||
|
// Note that this means the display will not show actual values during this time and your printer will also not react to buttons
|
||||||
|
// pressed immediately, except ALWAYS_ALLOW_MENU is also enabled.
|
||||||
|
// --2--
|
||||||
|
// No block is allowed to take less time than MIN_BLOCK_TIME. That's the time it takes in the main loop to add a new block to the buffer, checking temps,
|
||||||
|
// including all interruptions due to interrupts, but without LCD update. If we would allow shorter moves, the buffer would start continously draining.
|
||||||
|
//#define ENSURE_SMOOTH_MOVES
|
||||||
|
#if ENABLED(ENSURE_SMOOTH_MOVES)
|
||||||
|
//#define ALWAYS_ALLOW_MENU // If enabled, the menu will be always accessible.
|
||||||
|
// WARNING: If the menu is entered or navigated during short moves, the printer will stutter like without ENSURE_SMOOTH_MOVES!
|
||||||
|
#define LCD_UPDATE_THRESHOLD 170 // Minimum duration in ms of the current segment to allow a LCD update.
|
||||||
|
// Default value is valid for graphical LCDs like the REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER.
|
||||||
|
#define MIN_BLOCK_TIME 6 // Minimum duration in ms a single block has to take. You shouldn't need to modify this.
|
||||||
|
#endif
|
||||||
|
|
||||||
// @section extruder
|
// @section extruder
|
||||||
|
|
||||||
// extruder advance constant (s2/mm3)
|
// extruder advance constant (s2/mm3)
|
||||||
|
|
|
@ -937,13 +937,25 @@ void Planner::_buffer_line(const float &a, const float &b, const float &c, const
|
||||||
if (segment_time < min_segment_time) {
|
if (segment_time < min_segment_time) {
|
||||||
// buffer is draining, add extra time. The amount of time added increases if the buffer is still emptied more.
|
// buffer is draining, add extra time. The amount of time added increases if the buffer is still emptied more.
|
||||||
inverse_mm_s = 1000000.0 / (segment_time + lround(2 * (min_segment_time - segment_time) / moves_queued));
|
inverse_mm_s = 1000000.0 / (segment_time + lround(2 * (min_segment_time - segment_time) / moves_queued));
|
||||||
#ifdef XY_FREQUENCY_LIMIT
|
#if defined(XY_FREQUENCY_LIMIT) || ENABLED(ENSURE_SMOOTH_MOVES)
|
||||||
segment_time = lround(1000000.0 / inverse_mm_s);
|
segment_time = lround(1000000.0 / inverse_mm_s);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLED(ENSURE_SMOOTH_MOVES)
|
||||||
|
#if DISABLED(SLOWDOWN)
|
||||||
|
unsigned long segment_time = lround(1000000.0 / inverse_mm_s);
|
||||||
|
#endif
|
||||||
|
if (segment_time < (MIN_BLOCK_TIME) * 1000UL) {
|
||||||
|
// buffer will be draining, set to MIN_BLOCK_TIME.
|
||||||
|
inverse_mm_s = 1000000.0 / (1000.0 * (MIN_BLOCK_TIME));
|
||||||
|
segment_time = (MIN_BLOCK_TIME) * 1000UL;
|
||||||
|
}
|
||||||
|
block->segment_time = segment_time;
|
||||||
|
#endif
|
||||||
|
|
||||||
block->nominal_speed = block->millimeters * inverse_mm_s; // (mm/sec) Always > 0
|
block->nominal_speed = block->millimeters * inverse_mm_s; // (mm/sec) Always > 0
|
||||||
block->nominal_rate = ceil(block->step_event_count * inverse_mm_s); // (step/sec) Always > 0
|
block->nominal_rate = ceil(block->step_event_count * inverse_mm_s); // (step/sec) Always > 0
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,10 @@ typedef struct {
|
||||||
uint32_t valve_pressure, e_to_p_pressure;
|
uint32_t valve_pressure, e_to_p_pressure;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLED(ENSURE_SMOOTH_MOVES)
|
||||||
|
uint32_t segment_time;
|
||||||
|
#endif
|
||||||
|
|
||||||
} block_t;
|
} block_t;
|
||||||
|
|
||||||
#define BLOCK_MOD(n) ((n)&(BLOCK_BUFFER_SIZE-1))
|
#define BLOCK_MOD(n) ((n)&(BLOCK_BUFFER_SIZE-1))
|
||||||
|
@ -366,6 +370,17 @@ class Planner {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLED(ENSURE_SMOOTH_MOVES)
|
||||||
|
static bool long_move() {
|
||||||
|
if (blocks_queued()) {
|
||||||
|
block_t* block = &block_buffer[block_buffer_tail];
|
||||||
|
return (block->segment_time > (LCD_UPDATE_THRESHOLD * 1000UL));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ENABLED(AUTOTEMP)
|
#if ENABLED(AUTOTEMP)
|
||||||
static float autotemp_max;
|
static float autotemp_max;
|
||||||
static float autotemp_min;
|
static float autotemp_min;
|
||||||
|
|
|
@ -2710,15 +2710,24 @@ void lcd_update() {
|
||||||
// We arrive here every ~100ms when idling often enough.
|
// We arrive here every ~100ms when idling often enough.
|
||||||
// Instead of tracking the changes simply redraw the Info Screen ~1 time a second.
|
// Instead of tracking the changes simply redraw the Info Screen ~1 time a second.
|
||||||
static int8_t lcd_status_update_delay = 1; // first update one loop delayed
|
static int8_t lcd_status_update_delay = 1; // first update one loop delayed
|
||||||
if (
|
#if ENABLED(ENSURE_SMOOTH_MOVES) && ENABLED(ALWAYS_ALLOW_MENU)
|
||||||
#if ENABLED(ULTIPANEL)
|
if (planner.long_move()) {
|
||||||
currentScreen == lcd_status_screen &&
|
#endif
|
||||||
#endif
|
if (
|
||||||
!lcd_status_update_delay--) {
|
#if ENABLED(ULTIPANEL)
|
||||||
lcd_status_update_delay = 9;
|
currentScreen == lcd_status_screen &&
|
||||||
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
|
#endif
|
||||||
}
|
!lcd_status_update_delay--) {
|
||||||
|
lcd_status_update_delay = 9;
|
||||||
|
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
|
||||||
|
}
|
||||||
|
#if ENABLED(ENSURE_SMOOTH_MOVES) && ENABLED(ALWAYS_ALLOW_MENU)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLED(ENSURE_SMOOTH_MOVES) && DISABLED(ALWAYS_ALLOW_MENU)
|
||||||
|
if (planner.long_move()) {
|
||||||
|
#endif
|
||||||
if (lcdDrawUpdate) {
|
if (lcdDrawUpdate) {
|
||||||
|
|
||||||
switch (lcdDrawUpdate) {
|
switch (lcdDrawUpdate) {
|
||||||
|
@ -2779,6 +2788,9 @@ void lcd_update() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLED(ENSURE_SMOOTH_MOVES) && DISABLED(ALWAYS_ALLOW_MENU)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue