diff --git a/.gitattributes b/.gitattributes index bc2df2da3..d511b4ea9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,6 +8,7 @@ *.ino text eol=lf *.py text eol=lf *.sh text eol=lf +*.scad text eol=lf # Files with native line endings # *.sln text diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 63c857b72..817c4f934 100755 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -399,11 +399,11 @@ int feedrate_percentage = 100, saved_feedrate_percentage, bool axis_relative_modes[] = AXIS_RELATIVE_MODES, volumetric_enabled = - #if ENABLED(VOLUMETRIC_DEFAULT_ON) - true - #else - false - #endif + #if ENABLED(VOLUMETRIC_DEFAULT_ON) + true + #else + false + #endif ; float filament_size[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(DEFAULT_NOMINAL_FILAMENT_DIA), volumetric_multiplier[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(1.0); @@ -588,7 +588,6 @@ static uint8_t target_extruder; #endif #if ENABLED(AUTO_BED_LEVELING_BILINEAR) - #define UNPROBED 9999.0f int bilinear_grid_spacing[2], bilinear_start[2]; float bed_level_grid[ABL_GRID_MAX_POINTS_X][ABL_GRID_MAX_POINTS_Y]; #endif @@ -2344,7 +2343,7 @@ static void clean_up_after_endstop_or_probe_move() { bilinear_grid_spacing[X_AXIS] = bilinear_grid_spacing[Y_AXIS] = 0; for (uint8_t x = 0; x < ABL_GRID_MAX_POINTS_X; x++) for (uint8_t y = 0; y < ABL_GRID_MAX_POINTS_Y; y++) - bed_level_grid[x][y] = UNPROBED; + bed_level_grid[x][y] = NAN; #elif ENABLED(AUTO_BED_LEVELING_UBL) ubl.reset(); #endif @@ -2353,6 +2352,76 @@ static void clean_up_after_endstop_or_probe_move() { #endif // PLANNER_LEVELING +#if ENABLED(AUTO_BED_LEVELING_BILINEAR) || ENABLED(MESH_BED_LEVELING) + + // + // Enable if you prefer your output in JSON format + // suitable for SCAD or JavaScript mesh visualizers. + // + // Visualize meshes in OpenSCAD using the included script. + // + // buildroot/shared/scripts/MarlinMesh.scad + // + //#define SCAD_MESH_OUTPUT + + /** + * Print calibration results for plotting or manual frame adjustment. + */ + static void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, float (*fn)(const uint8_t, const uint8_t)) { + #ifndef SCAD_MESH_OUTPUT + for (uint8_t x = 0; x < sx; x++) { + for (uint8_t i = 0; i < precision + 2 + (x < 10 ? 1 : 0); i++) + SERIAL_PROTOCOLCHAR(' '); + SERIAL_PROTOCOL((int)x); + } + SERIAL_EOL; + #endif + #ifdef SCAD_MESH_OUTPUT + SERIAL_PROTOCOLLNPGM("measured_z = ["); // open 2D array + #endif + for (uint8_t y = 0; y < sy; y++) { + #ifdef SCAD_MESH_OUTPUT + SERIAL_PROTOCOLLNPGM(" ["); // open sub-array + #else + if (y < 10) SERIAL_PROTOCOLCHAR(' '); + SERIAL_PROTOCOL((int)y); + #endif + for (uint8_t x = 0; x < sx; x++) { + SERIAL_PROTOCOLCHAR(' '); + const float offset = fn(x, y); + if (offset != NAN) { + if (offset >= 0) SERIAL_PROTOCOLCHAR('+'); + SERIAL_PROTOCOL_F(offset, precision); + } + else { + #ifdef SCAD_MESH_OUTPUT + for (uint8_t i = 3; i < precision + 3; i++) + SERIAL_PROTOCOLCHAR(' '); + SERIAL_PROTOCOLPGM("NAN"); + #else + for (uint8_t i = 0; i < precision + 3; i++) + SERIAL_PROTOCOLCHAR(i ? '=' : ' '); + #endif + } + #ifdef SCAD_MESH_OUTPUT + if (x < sx - 1) SERIAL_PROTOCOLCHAR(','); + #endif + } + #ifdef SCAD_MESH_OUTPUT + SERIAL_PROTOCOLCHAR(' '); + SERIAL_PROTOCOLCHAR(']'); // close sub-array + if (y < sy - 1) SERIAL_PROTOCOLCHAR(','); + #endif + SERIAL_EOL; + } + #ifdef SCAD_MESH_OUTPUT + SERIAL_PROTOCOLPGM("\n];"); // close 2D array + #endif + SERIAL_EOL; + } + +#endif + #if ENABLED(AUTO_BED_LEVELING_BILINEAR) /** @@ -2372,7 +2441,7 @@ static void clean_up_after_endstop_or_probe_move() { SERIAL_CHAR(']'); } #endif - if (bed_level_grid[x][y] != UNPROBED) { + if (bed_level_grid[x][y] != NAN) { #if ENABLED(DEBUG_LEVELING_FEATURE) if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM(" (done)"); #endif @@ -2386,9 +2455,9 @@ static void clean_up_after_endstop_or_probe_move() { c1 = bed_level_grid[x + xdir][y + ydir], c2 = bed_level_grid[x + xdir * 2][y + ydir * 2]; // Treat far unprobed points as zero, near as equal to far - if (a2 == UNPROBED) a2 = 0.0; if (a1 == UNPROBED) a1 = a2; - if (b2 == UNPROBED) b2 = 0.0; if (b1 == UNPROBED) b1 = b2; - if (c2 == UNPROBED) c2 = 0.0; if (c1 == UNPROBED) c1 = c2; + if (a2 == NAN) a2 = 0.0; if (a1 == NAN) a1 = a2; + if (b2 == NAN) b2 = 0.0; if (b1 == NAN) b1 = b2; + if (c2 == NAN) c2 = 0.0; if (c1 == NAN) c1 = c2; const float a = 2 * a1 - a2, b = 2 * b1 - b2, c = 2 * c1 - c2; @@ -2453,39 +2522,10 @@ static void clean_up_after_endstop_or_probe_move() { } - /** - * Print calibration results for plotting or manual frame adjustment. - */ - static void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, float (*fn)(const uint8_t, const uint8_t)) { - for (uint8_t x = 0; x < sx; x++) { - for (uint8_t i = 0; i < precision + 2 + (x < 10 ? 1 : 0); i++) - SERIAL_PROTOCOLCHAR(' '); - SERIAL_PROTOCOL((int)x); - } - SERIAL_EOL; - for (uint8_t y = 0; y < sy; y++) { - if (y < 10) SERIAL_PROTOCOLCHAR(' '); - SERIAL_PROTOCOL((int)y); - for (uint8_t x = 0; x < sx; x++) { - SERIAL_PROTOCOLCHAR(' '); - float offset = fn(x, y); - if (offset != UNPROBED) { - if (offset >= 0) SERIAL_PROTOCOLCHAR('+'); - SERIAL_PROTOCOL_F(offset, precision); - } - else - for (uint8_t i = 0; i < precision + 3; i++) - SERIAL_PROTOCOLCHAR(i ? '=' : ' '); - } - SERIAL_EOL; - } - SERIAL_EOL; - } - static void print_bilinear_leveling_grid() { SERIAL_ECHOLNPGM("Bilinear Leveling Grid:"); - print_2d_array(ABL_GRID_MAX_POINTS_X, ABL_GRID_MAX_POINTS_Y, 2, - [](const uint8_t x, const uint8_t y) { return bed_level_grid[x][y]; } + print_2d_array(ABL_GRID_MAX_POINTS_X, ABL_GRID_MAX_POINTS_Y, 3, + [](const uint8_t ix, const uint8_t iy) { return bed_level_grid[ix][iy]; } ); } @@ -2501,7 +2541,7 @@ static void clean_up_after_endstop_or_probe_move() { static void bed_level_virt_print() { SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:"); print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5, - [](const uint8_t x, const uint8_t y) { return bed_level_grid_virt[x][y]; } + [](const uint8_t ix, const uint8_t iy) { return bed_level_grid_virt[ix][iy]; } ); } @@ -3715,13 +3755,9 @@ inline void gcode_G28() { SERIAL_PROTOCOLLNPGM("Num X,Y: " STRINGIFY(MESH_NUM_X_POINTS) "," STRINGIFY(MESH_NUM_Y_POINTS)); SERIAL_PROTOCOLPGM("Z offset: "); SERIAL_PROTOCOL_F(mbl.z_offset, 5); SERIAL_PROTOCOLLNPGM("\nMeasured points:"); - for (uint8_t py = 0; py < MESH_NUM_Y_POINTS; py++) { - for (uint8_t px = 0; px < MESH_NUM_X_POINTS; px++) { - SERIAL_PROTOCOLPGM(" "); - SERIAL_PROTOCOL_F(mbl.z_values[py][px], 5); - } - SERIAL_EOL; - } + print_2d_array(MESH_NUM_X_POINTS, MESH_NUM_Y_POINTS, 5, + [](const uint8_t ix, const uint8_t iy) { return mbl.z_values[ix][iy]; } + ); } /** diff --git a/buildroot/share/scripts/MarlinMesh.scad b/buildroot/share/scripts/MarlinMesh.scad new file mode 100644 index 000000000..68e0eee66 --- /dev/null +++ b/buildroot/share/scripts/MarlinMesh.scad @@ -0,0 +1,256 @@ + /**************************************\ + * * + * OpenSCAD Mesh Display * + * by Thinkyhead - April 2017 * + * * + * Copy the grid output from Marlin, * + * paste below as shown, and use * + * OpenSCAD to see a visualization * + * of your mesh. * + * * + \**************************************/ + +//$t = 0.15; // comment out during animation + +// +// Mesh info and points +// + +mesh_width = 200; // X Size in mm of the probed area +mesh_height = 200; // Y Size... +zprobe_offset = 0; // Added to the points +NAN = 0; // Z to use for un-measured points + +measured_z = [ + [ -1.20, -1.13, -1.09, -1.03, -1.19 ], + [ -1.16, -1.25, -1.27, -1.25, -1.08 ], + [ -1.13, -1.26, -1.39, -1.31, -1.18 ], + [ -1.09, -1.20, -1.26, -1.21, -1.18 ], + [ -1.13, -0.99, -1.03, -1.06, -1.32 ] +]; + +// +// Geometry +// + +max_z_scale = 100; // Scale at Time 0.5 +min_z_scale = 10; // Scale at Time 0.0 and 1.0 +thickness = 0.5; // thickness of the mesh triangles +tesselation = 1; // levels of tesselation from 0-2 +alternation = 2; // direction change modulus (try it) + +// +// Appearance +// + +show_plane = true; +show_labels = true; +arrow_length = 5; + +label_font_lg = "Arial"; +label_font_sm = "Arial"; +mesh_color = [1,1,1,0.5]; +plane_color = [0.4,0.6,0.9,0.6]; + +//================================================ Derive useful values + +big_z = max_2D(measured_z,0); +lil_z = min_2D(measured_z,0); + +mean_value = (big_z + lil_z) / 2.0; + +mesh_points_y = len(measured_z); +mesh_points_x = len(measured_z[0]); + +xspace = mesh_width / (mesh_points_x - 1); +yspace = mesh_height / (mesh_points_y - 1); + +// At $t=0 and $t=1 scale will be 100% +z_scale_factor = min_z_scale + (($t > 0.5) ? 1.0 - $t : $t) * (max_z_scale - min_z_scale) * 2; + +// +// Min and max recursive functions for 1D and 2D arrays +// Return the smallest or largest value in the array +// +function min_1D(b,i) = (i