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
					
				| @ -496,6 +496,26 @@ | ||||
|   #define BABYSTEP_MULTIPLICATOR 1 //faster movements
 | ||||
| #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
 | ||||
| 
 | ||||
| // extruder advance constant (s2/mm3)
 | ||||
|  | ||||
| @ -937,12 +937,24 @@ void Planner::_buffer_line(const float &a, const float &b, const float &c, const | ||||
|       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.
 | ||||
|         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); | ||||
|         #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_rate = ceil(block->step_event_count * inverse_mm_s); // (step/sec) Always > 0
 | ||||
|  | ||||
| @ -123,6 +123,10 @@ typedef struct { | ||||
|   #if ENABLED(BARICUDA) | ||||
|     uint32_t valve_pressure, e_to_p_pressure; | ||||
|   #endif | ||||
|    | ||||
|   #if ENABLED(ENSURE_SMOOTH_MOVES) | ||||
|     uint32_t segment_time; | ||||
|   #endif | ||||
| 
 | ||||
| } block_t; | ||||
| 
 | ||||
| @ -366,6 +370,17 @@ class Planner { | ||||
|         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) | ||||
|       static float autotemp_max; | ||||
|       static float autotemp_min; | ||||
|  | ||||
| @ -2710,15 +2710,24 @@ void lcd_update() { | ||||
|     // We arrive here every ~100ms when idling often enough.
 | ||||
|     // 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
 | ||||
|     if ( | ||||
|       #if ENABLED(ULTIPANEL) | ||||
|         currentScreen == lcd_status_screen && | ||||
|       #endif | ||||
|         !lcd_status_update_delay--) { | ||||
|       lcd_status_update_delay = 9; | ||||
|       lcdDrawUpdate = LCDVIEW_REDRAW_NOW; | ||||
|     } | ||||
|     #if ENABLED(ENSURE_SMOOTH_MOVES) && ENABLED(ALWAYS_ALLOW_MENU) | ||||
|       if (planner.long_move()) { | ||||
|     #endif | ||||
|         if ( | ||||
|           #if ENABLED(ULTIPANEL) | ||||
|             currentScreen == lcd_status_screen && | ||||
|           #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) { | ||||
| 
 | ||||
|       switch (lcdDrawUpdate) { | ||||
| @ -2779,6 +2788,9 @@ void lcd_update() { | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     #if ENABLED(ENSURE_SMOOTH_MOVES) && DISABLED(ALWAYS_ALLOW_MENU) | ||||
|       } | ||||
|     #endif | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user