Browse Source

Merge pull request #3744 from thinkyhead/rc_bezier_curves

Add BEZIER_CURVE_SUPPORT — G5 command
Scott Lahteine 8 years ago
parent
commit
3016dfe484

+ 6
- 0
.travis.yml View File

@@ -194,6 +194,12 @@ script:
194 194
   - opt_enable ULTIMAKERCONTROLLER FILAMENT_LCD_DISPLAY
195 195
   - build_marlin
196 196
   #
197
+  # Enable BEZIER_CURVE_SUPPORT
198
+  #
199
+  - restore_configs
200
+  - opt_enable_adv BEZIER_CURVE_SUPPORT
201
+  - build_marlin
202
+  #
197 203
   # Enable COREXY
198 204
   #
199 205
   - restore_configs

+ 3
- 2
Marlin/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -459,6 +457,9 @@
459 457
 #define MM_PER_ARC_SEGMENT 1
460 458
 #define N_ARC_CORRECTION 25
461 459
 
460
+// Support for G5 with XYZE destination and IJPQ offsets
461
+//#define BEZIER_CURVE_SUPPORT
462
+
462 463
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
463 464
 
464 465
 // @section temperature

+ 0
- 1
Marlin/Marlin.h View File

@@ -250,7 +250,6 @@ bool enqueue_and_echo_command(const char* cmd, bool say_ok=false); //put a singl
250 250
 void enqueue_and_echo_command_now(const char* cmd); // enqueue now, only return when the command has been enqueued
251 251
 void enqueue_and_echo_commands_P(const char* cmd); //put one or many ASCII commands at the end of the current buffer, read from flash
252 252
 
253
-void prepare_arc_move(char isclockwise);
254 253
 void clamp_to_software_endstops(float target[3]);
255 254
 
256 255
 extern millis_t previous_cmd_ms;

+ 71
- 1
Marlin/Marlin_main.cpp View File

@@ -45,6 +45,10 @@
45 45
   #include "mesh_bed_leveling.h"
46 46
 #endif
47 47
 
48
+#if ENABLED(BEZIER_CURVE_SUPPORT)
49
+  #include "planner_bezier.h"
50
+#endif
51
+
48 52
 #include "ultralcd.h"
49 53
 #include "planner.h"
50 54
 #include "stepper.h"
@@ -102,6 +106,7 @@
102 106
  * G2  - CW ARC
103 107
  * G3  - CCW ARC
104 108
  * G4  - Dwell S<seconds> or P<milliseconds>
109
+ * G5  - Cubic B-spline with
105 110
  * G10 - retract filament according to settings of M207
106 111
  * G11 - retract recover filament according to settings of M208
107 112
  * G28 - Home one or more axes
@@ -510,6 +515,10 @@ void process_next_command();
510 515
   void plan_arc(float target[NUM_AXIS], float* offset, uint8_t clockwise);
511 516
 #endif
512 517
 
518
+#if ENABLED(BEZIER_CURVE_SUPPORT)
519
+  void plan_cubic_move(const float offset[4]);
520
+#endif
521
+
513 522
 void serial_echopair_P(const char* s_P, int v)           { serialprintPGM(s_P); SERIAL_ECHO(v); }
514 523
 void serial_echopair_P(const char* s_P, long v)          { serialprintPGM(s_P); SERIAL_ECHO(v); }
515 524
 void serial_echopair_P(const char* s_P, float v)         { serialprintPGM(s_P); SERIAL_ECHO(v); }
@@ -2510,6 +2519,43 @@ inline void gcode_G4() {
2510 2519
   while (PENDING(millis(), codenum)) idle();
2511 2520
 }
2512 2521
 
2522
+#if ENABLED(BEZIER_CURVE_SUPPORT)
2523
+
2524
+  /**
2525
+   * Parameters interpreted according to:
2526
+   * http://linuxcnc.org/docs/2.6/html/gcode/gcode.html#sec:G5-Cubic-Spline
2527
+   * However I, J omission is not supported at this point; all
2528
+   * parameters can be omitted and default to zero.
2529
+   */
2530
+
2531
+  /**
2532
+   * G5: Cubic B-spline
2533
+   */
2534
+  inline void gcode_G5() {
2535
+    if (IsRunning()) {
2536
+
2537
+      #ifdef SF_ARC_FIX
2538
+        bool relative_mode_backup = relative_mode;
2539
+        relative_mode = true;
2540
+      #endif
2541
+      gcode_get_destination();
2542
+      #ifdef SF_ARC_FIX
2543
+        relative_mode = relative_mode_backup;
2544
+      #endif
2545
+
2546
+      float offset[] = {
2547
+        code_seen('I') ? code_value() : 0.0,
2548
+        code_seen('J') ? code_value() : 0.0,
2549
+        code_seen('P') ? code_value() : 0.0,
2550
+        code_seen('Q') ? code_value() : 0.0
2551
+      };
2552
+
2553
+      plan_cubic_move(offset);
2554
+    }
2555
+  }
2556
+
2557
+#endif // BEZIER_CURVE_SUPPORT
2558
+
2513 2559
 #if ENABLED(FWRETRACT)
2514 2560
 
2515 2561
   /**
@@ -6498,10 +6544,12 @@ void process_next_command() {
6498 6544
 
6499 6545
       // G2, G3
6500 6546
       #if ENABLED(ARC_SUPPORT) && DISABLED(SCARA)
6547
+
6501 6548
         case 2: // G2  - CW ARC
6502 6549
         case 3: // G3  - CCW ARC
6503 6550
           gcode_G2_G3(codenum == 2);
6504 6551
           break;
6552
+
6505 6553
       #endif
6506 6554
 
6507 6555
       // G4 Dwell
@@ -6509,6 +6557,15 @@ void process_next_command() {
6509 6557
         gcode_G4();
6510 6558
         break;
6511 6559
 
6560
+      #if ENABLED(BEZIER_CURVE_SUPPORT)
6561
+
6562
+        // G5
6563
+        case 5: // G5  - Cubic B_spline
6564
+          gcode_G5();
6565
+          break;
6566
+
6567
+      #endif // BEZIER_CURVE_SUPPORT
6568
+
6512 6569
       #if ENABLED(FWRETRACT)
6513 6570
 
6514 6571
         case 10: // G10: retract
@@ -6516,7 +6573,7 @@ void process_next_command() {
6516 6573
           gcode_G10_G11(codenum == 10);
6517 6574
           break;
6518 6575
 
6519
-      #endif //FWRETRACT
6576
+      #endif // FWRETRACT
6520 6577
 
6521 6578
       case 28: // G28: Home all axes, one at a time
6522 6579
         gcode_G28();
@@ -7588,6 +7645,19 @@ void prepare_move() {
7588 7645
   }
7589 7646
 #endif
7590 7647
 
7648
+#if ENABLED(BEZIER_CURVE_SUPPORT)
7649
+
7650
+  void plan_cubic_move(const float offset[4]) {
7651
+    cubic_b_spline(current_position, destination, offset, feedrate * feedrate_multiplier / 60 / 100.0, active_extruder);
7652
+
7653
+    // As far as the parser is concerned, the position is now == target. In reality the
7654
+    // motion control system might still be processing the action and the real tool position
7655
+    // in any intermediate location.
7656
+    set_current_to_destination();
7657
+  }
7658
+
7659
+#endif // BEZIER_CURVE_SUPPORT
7660
+
7591 7661
 #if HAS_CONTROLLERFAN
7592 7662
 
7593 7663
   void controllerFan() {

+ 3
- 2
Marlin/example_configurations/Felix/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -459,6 +457,9 @@
459 457
 #define MM_PER_ARC_SEGMENT 1
460 458
 #define N_ARC_CORRECTION 25
461 459
 
460
+// Support for G5 with XYZE destination and IJPQ offsets
461
+//#define BEZIER_CURVE_SUPPORT
462
+
462 463
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
463 464
 
464 465
 // @section temperature

+ 3
- 2
Marlin/example_configurations/Hephestos/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -459,6 +457,9 @@
459 457
 #define MM_PER_ARC_SEGMENT 1
460 458
 #define N_ARC_CORRECTION 25
461 459
 
460
+// Support for G5 with XYZE destination and IJPQ offsets
461
+//#define BEZIER_CURVE_SUPPORT
462
+
462 463
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
463 464
 
464 465
 // @section temperature

+ 3
- 2
Marlin/example_configurations/Hephestos_2/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -459,6 +457,9 @@
459 457
 #define MM_PER_ARC_SEGMENT 1
460 458
 #define N_ARC_CORRECTION 25
461 459
 
460
+// Support for G5 with XYZE destination and IJPQ offsets
461
+//#define BEZIER_CURVE_SUPPORT
462
+
462 463
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
463 464
 
464 465
 // @section temperature

+ 3
- 2
Marlin/example_configurations/K8200/Configuration_adv.h View File

@@ -290,8 +290,6 @@
290 290
 
291 291
 #define AXIS_RELATIVE_MODES {false, false, false, false}
292 292
 
293
-// @section machine
294
-
295 293
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
296 294
 #define INVERT_X_STEP_PIN false
297 295
 #define INVERT_Y_STEP_PIN false
@@ -465,6 +463,9 @@
465 463
 #define MM_PER_ARC_SEGMENT 1
466 464
 #define N_ARC_CORRECTION 25
467 465
 
466
+// Support for G5 with XYZE destination and IJPQ offsets
467
+//#define BEZIER_CURVE_SUPPORT
468
+
468 469
 const unsigned int dropsegments = 2; //everything with less than this number of steps will be ignored as move and joined with the next movement
469 470
 
470 471
 // @section temperature

+ 3
- 2
Marlin/example_configurations/RigidBot/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -459,6 +457,9 @@
459 457
 #define MM_PER_ARC_SEGMENT 1
460 458
 #define N_ARC_CORRECTION 25
461 459
 
460
+// Support for G5 with XYZE destination and IJPQ offsets
461
+//#define BEZIER_CURVE_SUPPORT
462
+
462 463
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
463 464
 
464 465
 // @section temperature

+ 3
- 2
Marlin/example_configurations/SCARA/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -459,6 +457,9 @@
459 457
 #define MM_PER_ARC_SEGMENT 1
460 458
 #define N_ARC_CORRECTION 25
461 459
 
460
+// Support for G5 with XYZE destination and IJPQ offsets
461
+//#define BEZIER_CURVE_SUPPORT
462
+
462 463
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
463 464
 
464 465
 // @section temperature

+ 3
- 2
Marlin/example_configurations/TAZ4/Configuration_adv.h View File

@@ -292,8 +292,6 @@
292 292
 
293 293
 #define AXIS_RELATIVE_MODES {false, false, false, false}
294 294
 
295
-// @section machine
296
-
297 295
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
298 296
 #define INVERT_X_STEP_PIN false
299 297
 #define INVERT_Y_STEP_PIN false
@@ -467,6 +465,9 @@
467 465
 #define MM_PER_ARC_SEGMENT 1
468 466
 #define N_ARC_CORRECTION 25
469 467
 
468
+// Support for G5 with XYZE destination and IJPQ offsets
469
+//#define BEZIER_CURVE_SUPPORT
470
+
470 471
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
471 472
 
472 473
 // @section temperature

+ 3
- 2
Marlin/example_configurations/WITBOX/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -459,6 +457,9 @@
459 457
 #define MM_PER_ARC_SEGMENT 1
460 458
 #define N_ARC_CORRECTION 25
461 459
 
460
+// Support for G5 with XYZE destination and IJPQ offsets
461
+//#define BEZIER_CURVE_SUPPORT
462
+
462 463
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
463 464
 
464 465
 // @section temperature

+ 3
- 2
Marlin/example_configurations/delta/biv2.5/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -461,6 +459,9 @@
461 459
 #define MM_PER_ARC_SEGMENT 1
462 460
 #define N_ARC_CORRECTION 25
463 461
 
462
+// Support for G5 with XYZE destination and IJPQ offsets
463
+//#define BEZIER_CURVE_SUPPORT
464
+
464 465
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
465 466
 
466 467
 // @section temperature

+ 3
- 2
Marlin/example_configurations/delta/generic/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -461,6 +459,9 @@
461 459
 #define MM_PER_ARC_SEGMENT 1
462 460
 #define N_ARC_CORRECTION 25
463 461
 
462
+// Support for G5 with XYZE destination and IJPQ offsets
463
+//#define BEZIER_CURVE_SUPPORT
464
+
464 465
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
465 466
 
466 467
 // @section temperature

+ 3
- 2
Marlin/example_configurations/delta/kossel_mini/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -460,6 +458,9 @@
460 458
 #define MM_PER_ARC_SEGMENT 1
461 459
 #define N_ARC_CORRECTION 25
462 460
 
461
+// Support for G5 with XYZE destination and IJPQ offsets
462
+//#define BEZIER_CURVE_SUPPORT
463
+
463 464
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
464 465
 
465 466
 // @section temperature

+ 3
- 2
Marlin/example_configurations/delta/kossel_pro/Configuration_adv.h View File

@@ -289,8 +289,6 @@
289 289
 
290 290
 #define AXIS_RELATIVE_MODES {false, false, false, false}
291 291
 
292
-// @section machine
293
-
294 292
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
295 293
 #define INVERT_X_STEP_PIN false
296 294
 #define INVERT_Y_STEP_PIN false
@@ -465,6 +463,9 @@
465 463
 #define MM_PER_ARC_SEGMENT 1
466 464
 #define N_ARC_CORRECTION 25
467 465
 
466
+// Support for G5 with XYZE destination and IJPQ offsets
467
+//#define BEZIER_CURVE_SUPPORT
468
+
468 469
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
469 470
 
470 471
 // @section temperature

+ 3
- 2
Marlin/example_configurations/delta/kossel_xl/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -461,6 +459,9 @@
461 459
 #define MM_PER_ARC_SEGMENT 1
462 460
 #define N_ARC_CORRECTION 25
463 461
 
462
+// Support for G5 with XYZE destination and IJPQ offsets
463
+//#define BEZIER_CURVE_SUPPORT
464
+
464 465
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
465 466
 
466 467
 // @section temperature

+ 3
- 2
Marlin/example_configurations/makibox/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -459,6 +457,9 @@
459 457
 #define MM_PER_ARC_SEGMENT 1
460 458
 #define N_ARC_CORRECTION 25
461 459
 
460
+// Support for G5 with XYZE destination and IJPQ offsets
461
+//#define BEZIER_CURVE_SUPPORT
462
+
462 463
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
463 464
 
464 465
 // @section temperature

+ 3
- 2
Marlin/example_configurations/tvrrug/Round2/Configuration_adv.h View File

@@ -284,8 +284,6 @@
284 284
 
285 285
 #define AXIS_RELATIVE_MODES {false, false, false, false}
286 286
 
287
-// @section machine
288
-
289 287
 //By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
290 288
 #define INVERT_X_STEP_PIN false
291 289
 #define INVERT_Y_STEP_PIN false
@@ -459,6 +457,9 @@
459 457
 #define MM_PER_ARC_SEGMENT 1
460 458
 #define N_ARC_CORRECTION 25
461 459
 
460
+// Support for G5 with XYZE destination and IJPQ offsets
461
+//#define BEZIER_CURVE_SUPPORT
462
+
462 463
 const unsigned int dropsegments = 5; //everything with less than this number of steps will be ignored as move and joined with the next movement
463 464
 
464 465
 // @section temperature

+ 194
- 0
Marlin/planner_bezier.cpp View File

@@ -0,0 +1,194 @@
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
+/**
24
+ * planner_bezier.cpp
25
+ *
26
+ * Compute and buffer movement commands for bezier curves
27
+ *
28
+ */
29
+
30
+#include "Marlin.h"
31
+
32
+#if ENABLED(BEZIER_CURVE_SUPPORT)
33
+
34
+#include "planner.h"
35
+#include "language.h"
36
+#include "temperature.h"
37
+
38
+// See the meaning in the documentation of cubic_b_spline().
39
+#define MIN_STEP 0.002
40
+#define MAX_STEP 0.1
41
+#define SIGMA 0.1
42
+
43
+/* Compute the linear interpolation between to real numbers.
44
+*/
45
+inline static float interp(float a, float b, float t) { return (1.0 - t) * a + t * b; }
46
+
47
+/**
48
+ * Compute a Bézier curve using the De Casteljau's algorithm (see
49
+ * https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm), which is
50
+ * easy to code and has good numerical stability (very important,
51
+ * since Arudino works with limited precision real numbers).
52
+ */
53
+inline static float eval_bezier(float a, float b, float c, float d, float t) {
54
+  float iab = interp(a, b, t);
55
+  float ibc = interp(b, c, t);
56
+  float icd = interp(c, d, t);
57
+  float iabc = interp(iab, ibc, t);
58
+  float ibcd = interp(ibc, icd, t);
59
+  float iabcd = interp(iabc, ibcd, t);
60
+  return iabcd;
61
+}
62
+
63
+/**
64
+ * We approximate Euclidean distance with the sum of the coordinates
65
+ * offset (so-called "norm 1"), which is quicker to compute.
66
+ */
67
+inline static float dist1(float x1, float y1, float x2, float y2) { return fabs(x1 - x2) + fabs(y1 - y2); }
68
+
69
+/**
70
+ * The algorithm for computing the step is loosely based on the one in Kig
71
+ * (See https://sources.debian.net/src/kig/4:15.08.3-1/misc/kigpainter.cpp/#L759)
72
+ * However, we do not use the stack.
73
+ *
74
+ * The algorithm goes as it follows: the parameters t runs from 0.0 to
75
+ * 1.0 describing the curve, which is evaluated by eval_bezier(). At
76
+ * each iteration we have to choose a step, i.e., the increment of the
77
+ * t variable. By default the step of the previous iteration is taken,
78
+ * and then it is enlarged or reduced depending on how straight the
79
+ * curve locally is. The step is always clamped between MIN_STEP/2 and
80
+ * 2*MAX_STEP. MAX_STEP is taken at the first iteration.
81
+ *
82
+ * For some t, the step value is considered acceptable if the curve in
83
+ * the interval [t, t+step] is sufficiently straight, i.e.,
84
+ * sufficiently close to linear interpolation. In practice the
85
+ * following test is performed: the distance between eval_bezier(...,
86
+ * t+step/2) is evaluated and compared with 0.5*(eval_bezier(...,
87
+ * t)+eval_bezier(..., t+step)). If it is smaller than SIGMA, then the
88
+ * step value is considered acceptable, otherwise it is not. The code
89
+ * seeks to find the larger step value which is considered acceptable.
90
+ *
91
+ * At every iteration the recorded step value is considered and then
92
+ * iteratively halved until it becomes acceptable. If it was already
93
+ * acceptable in the beginning (i.e., no halving were done), then
94
+ * maybe it was necessary to enlarge it; then it is iteratively
95
+ * doubled while it remains acceptable. The last acceptable value
96
+ * found is taken, provided that it is between MIN_STEP and MAX_STEP
97
+ * and does not bring t over 1.0.
98
+ *
99
+ * Caveat: this algorithm is not perfect, since it can happen that a
100
+ * step is considered acceptable even when the curve is not linear at
101
+ * all in the interval [t, t+step] (but its mid point coincides "by
102
+ * chance" with the midpoint according to the parametrization). This
103
+ * kind of glitches can be eliminated with proper first derivative
104
+ * estimates; however, given the improbability of such configurations,
105
+ * the mitigation offered by MIN_STEP and the small computational
106
+ * power available on Arduino, I think it is not wise to implement it.
107
+ */
108
+void cubic_b_spline(const float position[NUM_AXIS], const float target[NUM_AXIS], const float offset[4], float feed_rate, uint8_t extruder) {
109
+  // Absolute first and second control points are recovered.
110
+  float first0 = position[X_AXIS] + offset[0];
111
+  float first1 = position[Y_AXIS] + offset[1];
112
+  float second0 = target[X_AXIS] + offset[2];
113
+  float second1 = target[Y_AXIS] + offset[3];
114
+  float t = 0.0;
115
+
116
+  float tmp[4];
117
+  tmp[X_AXIS] = position[X_AXIS];
118
+  tmp[Y_AXIS] = position[Y_AXIS];
119
+  float step = MAX_STEP;
120
+
121
+  uint8_t idle_counter = 0;
122
+  millis_t next_ping_ms = millis() + 200UL;
123
+
124
+  while (t < 1.0) {
125
+
126
+    millis_t now = millis();
127
+    if (ELAPSED(now, next_ping_ms)) {
128
+      next_ping_ms = now + 200UL;
129
+      (idle_counter++ & 0x03) ? thermalManager.manage_heater() : idle();
130
+    }
131
+
132
+    // First try to reduce the step in order to make it sufficiently
133
+    // close to a linear interpolation.
134
+    bool did_reduce = false;
135
+    float new_t = t + step;
136
+    NOMORE(new_t, 1.0);
137
+    float new_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], new_t);
138
+    float new_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], new_t);
139
+    for (;;) {
140
+      if (new_t - t < (MIN_STEP)) break;
141
+      float candidate_t = 0.5 * (t + new_t);
142
+      float candidate_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], candidate_t);
143
+      float candidate_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], candidate_t);
144
+      float interp_pos0 = 0.5 * (tmp[X_AXIS] + new_pos0);
145
+      float interp_pos1 = 0.5 * (tmp[Y_AXIS] + new_pos1);
146
+      if (dist1(candidate_pos0, candidate_pos1, interp_pos0, interp_pos1) <= (SIGMA)) break;
147
+      new_t = candidate_t;
148
+      new_pos0 = candidate_pos0;
149
+      new_pos1 = candidate_pos1;
150
+      did_reduce = true;
151
+    }
152
+
153
+    // If we did not reduce the step, maybe we should enlarge it.
154
+    if (!did_reduce) for (;;) {
155
+      if (new_t - t > MAX_STEP) break;
156
+      float candidate_t = t + 2.0 * (new_t - t);
157
+      if (candidate_t >= 1.0) break;
158
+      float candidate_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], candidate_t);
159
+      float candidate_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], candidate_t);
160
+      float interp_pos0 = 0.5 * (tmp[X_AXIS] + candidate_pos0);
161
+      float interp_pos1 = 0.5 * (tmp[Y_AXIS] + candidate_pos1);
162
+      if (dist1(new_pos0, new_pos1, interp_pos0, interp_pos1) > (SIGMA)) break;
163
+      new_t = candidate_t;
164
+      new_pos0 = candidate_pos0;
165
+      new_pos1 = candidate_pos1;
166
+    }
167
+
168
+    // Check some postcondition; they are disabled in the actual
169
+    // Marlin build, but if you test the same code on a computer you
170
+    // may want to check they are respect.
171
+    /*
172
+      assert(new_t <= 1.0);
173
+      if (new_t < 1.0) {
174
+        assert(new_t - t >= (MIN_STEP) / 2.0);
175
+        assert(new_t - t <= (MAX_STEP) * 2.0);
176
+      }
177
+    */
178
+
179
+    step = new_t - t;
180
+    t = new_t;
181
+
182
+    // Compute and send new position
183
+    tmp[X_AXIS] = new_pos0;
184
+    tmp[Y_AXIS] = new_pos1;
185
+    // FIXME. The following two are wrong, since the parameter t is
186
+    // not linear in the distance.
187
+    tmp[Z_AXIS] = interp(position[Z_AXIS], target[Z_AXIS], t);
188
+    tmp[E_AXIS] = interp(position[E_AXIS], target[E_AXIS], t);
189
+    clamp_to_software_endstops(tmp);
190
+    planner.buffer_line(tmp[X_AXIS], tmp[Y_AXIS], tmp[Z_AXIS], tmp[E_AXIS], feed_rate, extruder);
191
+  }
192
+}
193
+
194
+#endif // BEZIER_CURVE_SUPPORT

+ 43
- 0
Marlin/planner_bezier.h View File

@@ -0,0 +1,43 @@
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
+/**
24
+ * planner_bezier.h
25
+ *
26
+ * Compute and buffer movement commands for bezier curves
27
+ *
28
+ */
29
+
30
+#ifndef PLANNER_BEZIER_H
31
+#define PLANNER_BEZIER_H
32
+
33
+#include "Marlin.h"
34
+
35
+void cubic_b_spline(
36
+              const float position[NUM_AXIS], // current position
37
+              const float target[NUM_AXIS],   // target position
38
+              const float offset[4],          // a pair of offsets
39
+              float feed_rate,
40
+              uint8_t extruder
41
+            );
42
+
43
+#endif // PLANNER_BEZIER_H

Loading…
Cancel
Save