LCD Panel Interactive Mesh Editing (#7045)

Original Mesh Bed Leveling replacement put at top of UBL Menu Options to
help facilitate the removal of the Original Mesh Bed Leveling.

Radar display (and control) of the UBL Interactive Mesh Editing.
This commit is contained in:
Roxy-3D 2017-06-12 18:26:49 -05:00 committed by GitHub
parent 896dfa0577
commit 824f71d503
7 changed files with 294 additions and 32 deletions

View file

@ -324,6 +324,8 @@
#if ENABLED(AUTO_BED_LEVELING_UBL)
#include "ubl.h"
extern bool defer_return_to_status;
extern bool ubl_lcd_map_control;
unified_bed_leveling ubl;
#define UBL_MESH_VALID !( ( ubl.z_values[0][0] == ubl.z_values[0][1] && ubl.z_values[0][1] == ubl.z_values[0][2] \
&& ubl.z_values[1][0] == ubl.z_values[1][1] && ubl.z_values[1][1] == ubl.z_values[1][2] \
@ -755,7 +757,7 @@ void report_current_position_detail();
* Set the planner/stepper positions directly from current_position with
* no kinematic translation. Used for homing axes and cartesian/core syncing.
*/
inline void sync_plan_position() {
void sync_plan_position() {
#if ENABLED(DEBUG_LEVELING_FEATURE)
if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position", current_position);
#endif
@ -7656,6 +7658,12 @@ inline void gcode_M18_M84() {
if (parser.seen('E')) disable_e_steppers();
#endif
}
#if ENABLED(AUTO_BED_LEVELING_UBL)
ubl_lcd_map_control = false;
defer_return_to_status = false;
#endif
}
}
@ -12429,6 +12437,10 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) {
#if ENABLED(DISABLE_INACTIVE_E)
disable_e_steppers();
#endif
#if ENABLED(AUTO_BED_LEVELING_UBL)
ubl_lcd_map_control = false;
defer_return_to_status = false;
#endif
}
#ifdef CHDK // Check if pin should be set to LOW after M240 set it to HIGH

View file

@ -280,6 +280,9 @@
#ifndef MSG_UBL_OUTPUT_MAP_CSV
#define MSG_UBL_OUTPUT_MAP_CSV _UxGT("Output for CSV")
#endif
#ifndef MSG_UBL_OUTPUT_MAP_BACKUP
#define MSG_UBL_OUTPUT_MAP_BACKUP _UxGT("Off Printer Backup")
#endif
#ifndef MSG_UBL_INFO_UBL
#define MSG_UBL_INFO_UBL _UxGT("Output UBL Info")
#endif

View file

@ -107,11 +107,15 @@
}
}
// display_map() currently produces three different mesh map types
// 0 : suitable for PronterFace and Repetier's serial console
// 1 : .CSV file suitable for importation into various spread sheets
// 2 : disply of the map data on a RepRap Graphical LCD Panel
void unified_bed_leveling::display_map(const int map_type) {
const bool map0 = map_type == 0;
constexpr uint8_t spaces = 8 * (GRID_MAX_POINTS_X - 2);
if (map0) {
if (map_type == 0) {
SERIAL_PROTOCOLLNPGM("\nBed Topography Report:\n");
serial_echo_xy(0, GRID_MAX_POINTS_Y - 1);
SERIAL_ECHO_SP(spaces + 3);
@ -123,6 +127,9 @@
SERIAL_EOL();
}
if (map_type == 1) { SERIAL_PROTOCOLLNPGM("\nBed Topography Report for CSV:"); SERIAL_EOL(); }
if (map_type == 2) { SERIAL_PROTOCOLLNPGM("\nBed Topography Report for LCD:"); SERIAL_EOL(); }
const float current_xi = get_cell_index_x(current_position[X_AXIS] + (MESH_X_DIST) / 2.0),
current_yi = get_cell_index_y(current_position[Y_AXIS] + (MESH_Y_DIST) / 2.0);
@ -131,37 +138,37 @@
const bool is_current = i == current_xi && j == current_yi;
// is the nozzle here? then mark the number
if (map0) SERIAL_CHAR(is_current ? '[' : ' ');
if (map_type == 0) SERIAL_CHAR(is_current ? '[' : ' ');
const float f = z_values[i][j];
if (isnan(f)) {
serialprintPGM(map0 ? PSTR(" . ") : PSTR("NAN"));
serialprintPGM((map_type == 0) ? PSTR(" . ") : PSTR("NAN"));
}
else {
// if we don't do this, the columns won't line up nicely
if (map0 && f >= 0.0) SERIAL_CHAR(' ');
SERIAL_PROTOCOL_F(f, 3);
if ((map_type == 0) && f >= 0.0) SERIAL_CHAR(' ');
if (map_type <= 1) SERIAL_PROTOCOL_F(f, 3);
idle();
}
if (!map0 && i < GRID_MAX_POINTS_X - 1) SERIAL_CHAR(',');
if (map_type == 1 && i < GRID_MAX_POINTS_X - 1) SERIAL_CHAR(',');
#if TX_BUFFER_SIZE > 0
MYSERIAL.flushTX();
#endif
safe_delay(15);
if (map0) {
if (map_type == 0) {
SERIAL_CHAR(is_current ? ']' : ' ');
SERIAL_CHAR(' ');
}
}
SERIAL_EOL();
if (j && map0) { // we want the (0,0) up tight against the block of numbers
if (j && (map_type == 0)) { // we want the (0,0) up tight against the block of numbers
SERIAL_CHAR(' ');
SERIAL_EOL();
}
}
if (map0) {
if (map_type == 0) {
serial_echo_xy(UBL_MESH_MIN_X, UBL_MESH_MIN_Y);
SERIAL_ECHO_SP(spaces + 4);
serial_echo_xy(UBL_MESH_MAX_X, UBL_MESH_MIN_Y);

View file

@ -45,6 +45,9 @@
void lcd_mesh_edit_setup(float initial);
float lcd_mesh_edit();
void lcd_z_offset_edit_setup(float);
#ifdef DOGLCD
extern void _lcd_ubl_output_map_lcd();
#endif
float lcd_z_offset_edit();
#endif
@ -53,6 +56,9 @@
extern float probe_pt(const float &x, const float &y, bool, int);
extern bool set_probe_deployed(bool);
extern void set_bed_leveling_enabled(bool);
extern bool ubl_lcd_map_control;
typedef void (*screenFunc_t)();
extern void lcd_goto_screen(screenFunc_t screen, const uint32_t encoder = 0);
#define SIZE_OF_LITTLE_RAISE 1
#define BIG_RAISE_NOT_NEEDED 0
@ -1191,7 +1197,7 @@
#endif
g29_map_type = parser.seen('T') && parser.has_value() ? parser.value_int() : 0;
if (!WITHIN(g29_map_type, 0, 1)) {
if (!WITHIN(g29_map_type, 0, 2)) {
SERIAL_PROTOCOLLNPGM("Invalid map type.\n");
return UBL_ERR;
}
@ -1535,8 +1541,8 @@
while (ubl_lcd_clicked()) { // debounce and watch for abort
idle();
if (ELAPSED(millis(), nxt)) {
ubl_lcd_map_control = false;
lcd_return_to_status();
//SERIAL_PROTOCOLLNPGM("\nFine Tuning of Mesh Stopped.");
do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
LCD_MESSAGEPGM(MSG_EDITING_STOPPED);
@ -1567,6 +1573,13 @@
LCD_MESSAGEPGM(MSG_UBL_DONE_EDITING_MESH);
SERIAL_ECHOLNPGM("Done Editing Mesh");
if (ubl_lcd_map_control) {
#ifdef DOGLCD
lcd_goto_screen(_lcd_ubl_output_map_lcd);
#endif
}
else lcd_return_to_status();
}
#endif

View file

@ -26,6 +26,7 @@
#include "language.h"
#include "cardreader.h"
#include "temperature.h"
#include "planner.h"
#include "stepper.h"
#include "configuration_store.h"
#include "utility.h"
@ -43,6 +44,11 @@
#include "endstops.h"
#endif
#if ENABLED(AUTO_BED_LEVELING_UBL)
#include "ubl.h"
bool ubl_lcd_map_control = false;
#endif
int lcd_preheat_hotend_temp[2], lcd_preheat_bed_temp[2], lcd_preheat_fan_speed[2];
#if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT)
@ -102,9 +108,6 @@ uint16_t max_display_update_time = 0;
extern bool powersupply_on;
#endif
#if ENABLED(AUTO_BED_LEVELING_UBL)
#include "ubl.h"
#endif
////////////////////////////////////////////
///////////////// Menu Tree ////////////////
@ -1044,6 +1047,7 @@ void kill_screen(const char* lcd_msg) {
float lcd_mesh_edit() {
lcd_goto_screen(_lcd_mesh_edit_NOP);
lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
_lcd_mesh_fine_tune(PSTR("Mesh Editor"));
return mesh_edit_value;
}
@ -1795,8 +1799,10 @@ void kill_screen(const char* lcd_msg) {
custom_hotend_temp = 190,
side_points = 3,
ubl_fillin_amount = 5,
ubl_height_amount,
map_type;
ubl_height_amount = 1,
n_edit_pts = 1,
x_plot = 0,
y_plot = 0;
/**
* UBL Build Custom Mesh Command
@ -1856,8 +1862,7 @@ void kill_screen(const char* lcd_msg) {
void _lcd_ubl_edit_mesh() {
START_MENU();
MENU_BACK(MSG_UBL_TOOLS);
MENU_BACK(MSG_UBL_LEVEL_BED);
MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R T"));
MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R999 T"));
MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_CLOSEST, PSTR("G29 P4 T"));
MENU_ITEM(submenu, MSG_UBL_MESH_HEIGHT_ADJUST, _lcd_ubl_height_adjust_menu);
MENU_ITEM(function, MSG_WATCH, lcd_return_to_status);
@ -1944,7 +1949,7 @@ void kill_screen(const char* lcd_msg) {
*/
void _lcd_ubl_smart_fillin_cmd() {
char UBL_LCD_GCODE[12];
sprintf_P(UBL_LCD_GCODE, PSTR("G29 P3 T%i"), map_type);
sprintf_P(UBL_LCD_GCODE, PSTR("G29 P3 T0"));
enqueue_and_echo_command(UBL_LCD_GCODE);
}
@ -2045,12 +2050,219 @@ void kill_screen(const char* lcd_msg) {
}
/**
* UBL Output map Command
* UBL LCD "radar" map homing
*/
void _lcd_ubl_output_map_cmd() {
char UBL_LCD_GCODE[10];
sprintf_P(UBL_LCD_GCODE, PSTR("G29 T%i"), map_type);
enqueue_and_echo_command(UBL_LCD_GCODE);
void _lcd_ubl_output_map_lcd();
void _lcd_ubl_map_homing() {
if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_HOMING), NULL);
lcdDrawUpdate = LCDVIEW_CALL_NO_REDRAW;
if (axis_homed[X_AXIS] && axis_homed[Y_AXIS] && axis_homed[Z_AXIS])
lcd_goto_screen(_lcd_ubl_output_map_lcd);
}
/**
* UBL LCD "radar" map point editing
*/
void _lcd_ubl_map_lcd_edit_cmd() {
char ubl_lcd_gcode [50], str[10], str2[10];
ubl_lcd_map_control = true; // Used for returning to the map screen
dtostrf(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]), 0, 2, str);
dtostrf(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]), 0, 2, str2);
snprintf_P(ubl_lcd_gcode, sizeof(ubl_lcd_gcode), PSTR("G29 P4 X%s Y%s R%i"), str, str2, n_edit_pts);
enqueue_and_echo_command(ubl_lcd_gcode);
}
#ifdef DOGLCD
/**
* UBL LCD "radar" map data
*/
#define MAP_UPPER_LEFT_CORNER_X 35 // These probably should be moved to the .h file But for now,
#define MAP_UPPER_LEFT_CORNER_Y 8 // it is easier to play with things having them here
#define MAP_MAX_PIXELS_X 53
#define MAP_MAX_PIXELS_Y 49
void _lcd_ubl_plot_drawing_prep() {
uint8_t i, j, x_offset, y_offset, x_map_pixels, y_map_pixels;
uint8_t pixels_per_X_mesh_pnt, pixels_per_Y_mesh_pnt, inverted_y;
/*********************************************************/
/************ Scale the box pixels appropriately *********/
/*********************************************************/
x_map_pixels = ((MAP_MAX_PIXELS_X - 4) / GRID_MAX_POINTS_X) * GRID_MAX_POINTS_X;
y_map_pixels = ((MAP_MAX_PIXELS_Y - 4) / GRID_MAX_POINTS_Y) * GRID_MAX_POINTS_Y;
pixels_per_X_mesh_pnt = x_map_pixels / GRID_MAX_POINTS_X;
pixels_per_Y_mesh_pnt = y_map_pixels / GRID_MAX_POINTS_Y;
x_offset = MAP_UPPER_LEFT_CORNER_X + 1 + (MAP_MAX_PIXELS_X-x_map_pixels-2)/2;
y_offset = MAP_UPPER_LEFT_CORNER_Y + 1 + (MAP_MAX_PIXELS_Y-y_map_pixels-2)/2;
/*********************************************************/
/************ Clear the Mesh Map Box**********************/
/*********************************************************/
u8g.setColorIndex(1); // First draw the bigger box in White so we have a border around the mesh map box
u8g.drawBox(x_offset-2, y_offset-2, x_map_pixels+4, y_map_pixels+4);
u8g.setColorIndex(0); // Now actually clear the mesh map box
u8g.drawBox(x_offset, y_offset, x_map_pixels, y_map_pixels);
/*********************************************************/
/************ Display Mesh Point Locations ***************/
/*********************************************************/
u8g.setColorIndex(1);
for (i = 0; i < GRID_MAX_POINTS_X; i++) {
for (j = 0; j < GRID_MAX_POINTS_Y; j++) {
u8g.drawBox(x_offset+i*pixels_per_X_mesh_pnt+pixels_per_X_mesh_pnt/2,
y_offset+j*pixels_per_Y_mesh_pnt+pixels_per_Y_mesh_pnt/2, 1, 1);
}
}
/*********************************************************/
/************ Fill in the Specified Mesh Point ***********/
/*********************************************************/
inverted_y = GRID_MAX_POINTS_Y - y_plot - 1; // The origin is typically in the lower right corner. We need to
// invert the Y to get it to plot in the right location.
u8g.drawBox(x_offset+x_plot*pixels_per_X_mesh_pnt, y_offset+inverted_y*pixels_per_Y_mesh_pnt,
pixels_per_X_mesh_pnt, pixels_per_Y_mesh_pnt);
/*********************************************************/
/************** Put Relevent Text on Display *************/
/*********************************************************/
// Show X and Y positions at top of screen
u8g.setColorIndex(1);
u8g.setPrintPos(5, 7);
lcd_print("X:");
lcd_print(ftostr32(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]))));
u8g.setPrintPos(74, 7);
lcd_print("Y:");
lcd_print(ftostr32(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]))));
// Print plot position
u8g.setPrintPos(5, 64);
lcd_print("(");
u8g.print(x_plot);
lcd_print(",");
u8g.print(y_plot);
lcd_print(")");
// Show the location value
u8g.setPrintPos(74, 64);
lcd_print("Z:");
if (!isnan(ubl.z_values[x_plot][y_plot])) {
lcd_print(ftostr43sign(ubl.z_values[x_plot][y_plot]));
}
else {
lcd_print(" -----");
}
}
#endif // DOGLCD
/**
* UBL LCD Map Movement
*/
void ubl_map_move_to_xy() {
current_position[X_AXIS] = LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]));
current_position[Y_AXIS] = LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]));
planner.buffer_line_kinematic(current_position, MMM_TO_MMS(XY_PROBE_SPEED), active_extruder);
}
/**
* UBL LCD "radar" map
*/
void set_current_from_steppers_for_axis(const AxisEnum axis);
void sync_plan_position();
void _lcd_ubl_output_map_lcd() {
static int step_scaler=0;
int32_t signed_enc_pos;
defer_return_to_status = true;
if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS]) {
if (lcd_clicked) { return _lcd_ubl_map_lcd_edit_cmd(); }
ENCODER_DIRECTION_NORMAL();
if (encoderPosition != 0) {
signed_enc_pos = (int32_t)encoderPosition;
step_scaler += signed_enc_pos;
x_plot = (x_plot + step_scaler / ENCODER_STEPS_PER_MENU_ITEM);
if (abs(step_scaler) >= ENCODER_STEPS_PER_MENU_ITEM)
step_scaler = 0;
refresh_cmd_timeout();
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
}
encoderPosition = 0;
// Encoder to the right (++)
if (x_plot >= GRID_MAX_POINTS_X) { x_plot = 0; y_plot++; }
if (y_plot >= GRID_MAX_POINTS_Y) y_plot = 0;
// Encoder to the left (--)
if (x_plot <= GRID_MAX_POINTS_X - (GRID_MAX_POINTS_X + 1)) { x_plot = GRID_MAX_POINTS_X - 1; y_plot--; }
if (y_plot <= GRID_MAX_POINTS_Y - (GRID_MAX_POINTS_Y + 1)) y_plot = GRID_MAX_POINTS_Y - 1;
// Prevent underrun/overrun of plot numbers
x_plot = constrain(x_plot, GRID_MAX_POINTS_X - (GRID_MAX_POINTS_X + 1), GRID_MAX_POINTS_X + 1);
y_plot = constrain(y_plot, GRID_MAX_POINTS_Y - (GRID_MAX_POINTS_Y + 1), GRID_MAX_POINTS_Y + 1);
// Determine number of points to edit
#if IS_KINEMATIC
n_edit_pts = 9; //TODO: Delta accessible edit points
#else
if (x_plot < 1 || x_plot >= GRID_MAX_POINTS_X - 1)
if (y_plot < 1 || y_plot >= GRID_MAX_POINTS_Y - 1) n_edit_pts = 4; // Corners
else n_edit_pts = 6;
else if (y_plot < 1 || y_plot >= GRID_MAX_POINTS_Y - 1) n_edit_pts = 6; // Edges
else n_edit_pts = 9; // Field
#endif
if (lcdDrawUpdate) {
#if ENABLED(DOGLCD)
_lcd_ubl_plot_drawing_prep();
#else
_lcd_ubl_output_char_lcd();
#endif
ubl_map_move_to_xy(); // Move to current location
if (planner.movesplanned()>1) { // if the nozzle is moving, cancel the move. There is a new location
#define ENABLE_STEPPER_DRIVER_INTERRUPT() SBI(TIMSK1, OCIE1A)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() CBI(TIMSK1, OCIE1A)
DISABLE_STEPPER_DRIVER_INTERRUPT();
while (planner.blocks_queued()) planner.discard_current_block();
stepper.current_block = NULL;
planner.clear_block_buffer_runtime();
ENABLE_STEPPER_DRIVER_INTERRUPT();
set_current_from_steppers_for_axis(ALL_AXES);
sync_plan_position();
ubl_map_move_to_xy(); // Move to new location
}
}
safe_delay(10);
}
else lcd_goto_screen(_lcd_ubl_map_homing);
}
/**
* UBL Homing before LCD map
*/
void _lcd_ubl_output_map_lcd_cmd() {
if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS]))
enqueue_and_echo_commands_P(PSTR("G28"));
lcd_goto_screen(_lcd_ubl_map_homing);
}
/**
@ -2059,9 +2271,10 @@ void kill_screen(const char* lcd_msg) {
void _lcd_ubl_output_map() {
START_MENU();
MENU_BACK(MSG_UBL_LEVEL_BED);
MENU_ITEM_EDIT(int3, MSG_UBL_MAP_TYPE, &map_type, 0, 1);
if (map_type == 0) MENU_ITEM(function, MSG_UBL_OUTPUT_MAP_HOST, _lcd_ubl_output_map_cmd);
if (map_type == 1) MENU_ITEM(function, MSG_UBL_OUTPUT_MAP_CSV, _lcd_ubl_output_map_cmd);
MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_HOST, PSTR("G29 T0"));
MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_CSV, PSTR("G29 T1"));
MENU_ITEM(gcode, MSG_UBL_OUTPUT_MAP_BACKUP, PSTR("G29 S-1"));
MENU_ITEM(function, MSG_UBL_OUTPUT_MAP, _lcd_ubl_output_map_lcd_cmd);
END_MENU();
}
@ -2091,8 +2304,10 @@ void kill_screen(const char* lcd_msg) {
* Load Bed Mesh
* Save Bed Mesh
* - Output Map
* Map Type:
* Output Bed Mesh Host / Output Bed Mesh CSV
* Topography to Host
* CSV for Spreadsheet
* Mesh Output Backup
* Output to LCD Grid
* - UBL Tools
* - Build Mesh
* Build PLA Mesh
@ -4035,7 +4250,7 @@ void lcd_update() {
int32_t encoderMovementSteps = abs(encoderDiff) / ENCODER_PULSES_PER_STEP;
if (lastEncoderMovementMillis != 0) {
// Note that the rate is always calculated between to passes through the
// Note that the rate is always calculated between two passes through the
// loop and that the abs of the encoderDiff value is tracked.
float encoderStepRate = (float)(encoderMovementSteps) / ((float)(ms - lastEncoderMovementMillis)) * 1000.0;

View file

@ -50,6 +50,10 @@
#include <U8glib.h>
#if ENABLED(AUTO_BED_LEVELING_UBL)
#include "ubl.h"
#endif
#if ENABLED(SHOW_BOOTSCREEN) && ENABLED(SHOW_CUSTOM_BOOTSCREEN)
#include "_Bootscreen.h"
#endif

View file

@ -1076,4 +1076,12 @@ static void lcd_implementation_status_screen() {
#endif // LCD_HAS_STATUS_INDICATORS
#ifdef AUTO_BED_LEVELING_UBL
void lcd_return_to_status(); // These are just place holders for the 20x4 LCD work that
void _lcd_ubl_output_char_lcd() { // is coming up very soon. Soon this will morph into the
lcd_return_to_status(); // real code.
}
#endif // AUTO_BED_LEVELING_UBL
#endif // ULTRALCD_IMPL_HD44780_H