Subversion Repositories Tronxy-X3A-Marlin

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 ron 1
/**
2
 * Marlin 3D Printer Firmware
3
 * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
 *
5
 * Based on Sprinter and grbl.
6
 * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
 
23
#include "MarlinConfig.h"
24
 
25
#if ENABLED(AUTO_BED_LEVELING_UBL)
26
 
27
  #include "Marlin.h"
28
  #include "ubl.h"
29
  #include "hex_print_routines.h"
30
  #include "temperature.h"
31
  #include "planner.h"
32
  #include "math.h"
33
 
34
  unified_bed_leveling ubl;
35
 
36
  uint8_t ubl_cnt = 0;
37
 
38
  void unified_bed_leveling::echo_name() { SERIAL_PROTOCOLPGM("Unified Bed Leveling"); }
39
 
40
  void unified_bed_leveling::report_current_mesh() {
41
    if (!leveling_is_valid()) return;
42
    SERIAL_ECHO_START();
43
    SERIAL_ECHOLNPGM("  G29 I999");
44
    for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
45
      for (uint8_t y = 0;  y < GRID_MAX_POINTS_Y; y++)
46
        if (!isnan(z_values[x][y])) {
47
          SERIAL_ECHO_START();
48
          SERIAL_ECHOPAIR("  M421 I", x);
49
          SERIAL_ECHOPAIR(" J", y);
50
          SERIAL_ECHOPGM(" Z");
51
          SERIAL_ECHO_F(z_values[x][y], 2);
52
          SERIAL_EOL();
53
        }
54
  }
55
 
56
  void unified_bed_leveling::report_state() {
57
    echo_name();
58
    SERIAL_PROTOCOLPGM(" System v" UBL_VERSION " ");
59
    if (!planner.leveling_active) SERIAL_PROTOCOLPGM("in");
60
    SERIAL_PROTOCOLLNPGM("active.");
61
    safe_delay(50);
62
  }
63
 
64
  #if ENABLED(UBL_DEVEL_DEBUGGING)
65
 
66
    static void debug_echo_axis(const AxisEnum axis) {
67
      if (current_position[axis] == destination[axis])
68
        SERIAL_ECHOPGM("-------------");
69
      else
70
        SERIAL_ECHO_F(destination[X_AXIS], 6);
71
    }
72
 
73
    void debug_current_and_destination(const char *title) {
74
 
75
      // if the title message starts with a '!' it is so important, we are going to
76
      // ignore the status of the g26_debug_flag
77
      if (*title != '!' && !g26_debug_flag) return;
78
 
79
      const float de = destination[E_CART] - current_position[E_CART];
80
 
81
      if (de == 0.0) return; // Printing moves only
82
 
83
      const float dx = destination[X_AXIS] - current_position[X_AXIS],
84
                  dy = destination[Y_AXIS] - current_position[Y_AXIS],
85
                  xy_dist = HYPOT(dx, dy);
86
 
87
      if (xy_dist == 0.0) return;
88
 
89
      SERIAL_ECHOPGM("   fpmm=");
90
      const float fpmm = de / xy_dist;
91
      SERIAL_ECHO_F(fpmm, 6);
92
 
93
      SERIAL_ECHOPGM("    current=( ");
94
      SERIAL_ECHO_F(current_position[X_AXIS], 6);
95
      SERIAL_ECHOPGM(", ");
96
      SERIAL_ECHO_F(current_position[Y_AXIS], 6);
97
      SERIAL_ECHOPGM(", ");
98
      SERIAL_ECHO_F(current_position[Z_AXIS], 6);
99
      SERIAL_ECHOPGM(", ");
100
      SERIAL_ECHO_F(current_position[E_CART], 6);
101
      SERIAL_ECHOPGM(" )   destination=( ");
102
      debug_echo_axis(X_AXIS);
103
      SERIAL_ECHOPGM(", ");
104
      debug_echo_axis(Y_AXIS);
105
      SERIAL_ECHOPGM(", ");
106
      debug_echo_axis(Z_AXIS);
107
      SERIAL_ECHOPGM(", ");
108
      debug_echo_axis(E_AXIS);
109
      SERIAL_ECHOPGM(" )   ");
110
      SERIAL_ECHO(title);
111
      SERIAL_EOL();
112
 
113
    }
114
 
115
  #endif // UBL_DEVEL_DEBUGGING
116
 
117
  int8_t unified_bed_leveling::storage_slot;
118
 
119
  float unified_bed_leveling::z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
120
 
121
  // 15 is the maximum nubmer of grid points supported + 1 safety margin for now,
122
  // until determinism prevails
123
  constexpr float unified_bed_leveling::_mesh_index_to_xpos[16],
124
                  unified_bed_leveling::_mesh_index_to_ypos[16];
125
 
126
  #if ENABLED(ULTIPANEL)
127
    bool unified_bed_leveling::lcd_map_control = false;
128
  #endif
129
 
130
  volatile int unified_bed_leveling::encoder_diff;
131
 
132
  unified_bed_leveling::unified_bed_leveling() {
133
    ubl_cnt++;  // Debug counter to ensure we only have one UBL object present in memory.  We can eliminate this (and all references to ubl_cnt) very soon.
134
    reset();
135
  }
136
 
137
  void unified_bed_leveling::reset() {
138
    const bool was_enabled = planner.leveling_active;
139
    set_bed_leveling_enabled(false);
140
    storage_slot = -1;
141
    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
142
      planner.set_z_fade_height(10.0);
143
    #endif
144
    ZERO(z_values);
145
    if (was_enabled) report_current_position();
146
  }
147
 
148
  void unified_bed_leveling::invalidate() {
149
    set_bed_leveling_enabled(false);
150
    set_all_mesh_points_to_value(NAN);
151
  }
152
 
153
  void unified_bed_leveling::set_all_mesh_points_to_value(const float value) {
154
    for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++) {
155
      for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++) {
156
        z_values[x][y] = value;
157
      }
158
    }
159
  }
160
 
161
  static void serial_echo_xy(const uint8_t sp, const int16_t x, const int16_t y) {
162
    SERIAL_ECHO_SP(sp);
163
    SERIAL_CHAR('(');
164
    if (x < 100) { SERIAL_CHAR(' '); if (x < 10) SERIAL_CHAR(' '); }
165
    SERIAL_ECHO(x);
166
    SERIAL_CHAR(',');
167
    if (y < 100) { SERIAL_CHAR(' '); if (y < 10) SERIAL_CHAR(' '); }
168
    SERIAL_ECHO(y);
169
    SERIAL_CHAR(')');
170
    safe_delay(5);
171
  }
172
 
173
  static void serial_echo_column_labels(const uint8_t sp) {
174
    SERIAL_ECHO_SP(7);
175
    for (int8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
176
      if (i < 10) SERIAL_CHAR(' ');
177
      SERIAL_ECHO(i);
178
      SERIAL_ECHO_SP(sp);
179
    }
180
    safe_delay(10);
181
  }
182
 
183
  /**
184
   * Produce one of these mesh maps:
185
   *   0: Human-readable
186
   *   1: CSV format for spreadsheet import
187
   *   2: TODO: Display on Graphical LCD
188
   *   4: Compact Human-Readable
189
   */
190
  void unified_bed_leveling::display_map(const int map_type) {
191
    #if HAS_AUTO_REPORTING || ENABLED(HOST_KEEPALIVE_FEATURE)
192
      suspend_auto_report = true;
193
    #endif
194
 
195
    constexpr uint8_t eachsp = 1 + 6 + 1,                           // [-3.567]
196
                      twixt = eachsp * (GRID_MAX_POINTS_X) - 9 * 2; // Leading 4sp, Coordinates 9sp each
197
 
198
    const bool human = !(map_type & 0x3), csv = map_type == 1, lcd = map_type == 2, comp = map_type & 0x4;
199
 
200
    SERIAL_ECHOPGM("\nBed Topography Report");
201
    if (human) {
202
      SERIAL_ECHOPGM(":\n\n");
203
      serial_echo_xy(4, MESH_MIN_X, MESH_MAX_Y);
204
      serial_echo_xy(twixt, MESH_MAX_X, MESH_MAX_Y);
205
      SERIAL_EOL();
206
      serial_echo_column_labels(eachsp - 2);
207
    }
208
    else {
209
      SERIAL_ECHOPGM(" for ");
210
      serialprintPGM(csv ? PSTR("CSV:\n") : PSTR("LCD:\n"));
211
    }
212
 
213
    // Add XY_PROBE_OFFSET_FROM_EXTRUDER because probe_pt() subtracts these when
214
    // moving to the xy position to be measured. This ensures better agreement between
215
    // the current Z position after G28 and the mesh values.
216
    const float current_xi = find_closest_x_index(current_position[X_AXIS] + X_PROBE_OFFSET_FROM_EXTRUDER),
217
                current_yi = find_closest_y_index(current_position[Y_AXIS] + Y_PROBE_OFFSET_FROM_EXTRUDER);
218
 
219
    if (!lcd) SERIAL_EOL();
220
    for (int8_t j = GRID_MAX_POINTS_Y - 1; j >= 0; j--) {
221
 
222
      // Row Label (J index)
223
      if (human) {
224
        if (j < 10) SERIAL_CHAR(' ');
225
        SERIAL_ECHO(j);
226
        SERIAL_ECHOPGM(" |");
227
      }
228
 
229
      // Row Values (I indexes)
230
      for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
231
 
232
        // Opening Brace or Space
233
        const bool is_current = i == current_xi && j == current_yi;
234
        if (human) SERIAL_CHAR(is_current ? '[' : ' ');
235
 
236
        // Z Value at current I, J
237
        const float f = z_values[i][j];
238
        if (lcd) {
239
          // TODO: Display on Graphical LCD
240
        }
241
        else if (isnan(f))
242
          serialprintPGM(human ? PSTR("  .   ") : PSTR("NAN"));
243
        else if (human || csv) {
244
          if (human && f >= 0.0) SERIAL_CHAR(f > 0 ? '+' : ' ');  // Space for positive ('-' for negative)
245
          SERIAL_ECHO_F(f, 3);                                    // Positive: 5 digits, Negative: 6 digits
246
        }
247
        idle();
248
        if (csv && i < GRID_MAX_POINTS_X - 1) SERIAL_CHAR('\t');
249
 
250
        // Closing Brace or Space
251
        if (human) SERIAL_CHAR(is_current ? ']' : ' ');
252
 
253
        #if TX_BUFFER_SIZE > 0
254
          SERIAL_FLUSHTX();
255
        #endif
256
        safe_delay(5);
257
      }
258
      if (!lcd) SERIAL_EOL();
259
 
260
      // A blank line between rows (unless compact)
261
      if (j && human && !comp) SERIAL_ECHOLNPGM("   |");
262
    }
263
 
264
    if (human) {
265
      serial_echo_column_labels(eachsp - 2);
266
      SERIAL_EOL();
267
      serial_echo_xy(4, MESH_MIN_X, MESH_MIN_Y);
268
      serial_echo_xy(twixt, MESH_MAX_X, MESH_MIN_Y);
269
      SERIAL_EOL();
270
      SERIAL_EOL();
271
    }
272
 
273
    #if HAS_AUTO_REPORTING || ENABLED(HOST_KEEPALIVE_FEATURE)
274
      suspend_auto_report = false;
275
    #endif
276
  }
277
 
278
  bool unified_bed_leveling::sanity_check() {
279
    uint8_t error_flag = 0;
280
 
281
    if (settings.calc_num_meshes() < 1) {
282
      SERIAL_PROTOCOLLNPGM("?Mesh too big for EEPROM.");
283
      error_flag++;
284
    }
285
 
286
    return !!error_flag;
287
  }
288
 
289
#endif // AUTO_BED_LEVELING_UBL