Explorar el Código

✨ Laser Safety Timeout (#24189)

John Robertson hace 3 años
padre
commit
85c0875db2
No account linked to committer's email address

+ 10
- 0
Marlin/Configuration_adv.h Ver fichero

3668
     #define LASER_TEST_PULSE_MIN           1   // Used with Laser Control Menu
3668
     #define LASER_TEST_PULSE_MIN           1   // Used with Laser Control Menu
3669
     #define LASER_TEST_PULSE_MAX         999   // Caution: Menu may not show more than 3 characters
3669
     #define LASER_TEST_PULSE_MAX         999   // Caution: Menu may not show more than 3 characters
3670
 
3670
 
3671
+   /**
3672
+    * Laser Safety Timeout
3673
+    *
3674
+    * The laser should be turned off when there is no movement for a period of time.
3675
+    * Consider material flammability, cut rate, and G-code order when setting this
3676
+    * value. Too low and it could turn off during a very slow move; too high and
3677
+    * the material could ignite.
3678
+    */
3679
+    #define LASER_SAFETY_TIMEOUT_MS     1000   // (ms)
3680
+
3671
     /**
3681
     /**
3672
      * Enable inline laser power to be handled in the planner / stepper routines.
3682
      * Enable inline laser power to be handled in the planner / stepper routines.
3673
      * Inline power is specified by the I (inline) flag in an M3 command (e.g., M3 S20 I)
3683
      * Inline power is specified by the I (inline) flag in an M3 command (e.g., M3 S20 I)

+ 29
- 28
Marlin/src/MarlinCore.cpp Ver fichero

423
     kill();
423
     kill();
424
   }
424
   }
425
 
425
 
426
-  // M18 / M84 : Handle steppers inactive time timeout
427
-  if (gcode.stepper_inactive_time) {
428
-
429
-    static bool already_shutdown_steppers; // = false
426
+  const bool has_blocks = planner.has_blocks_queued();  // Any moves in the planner?
427
+  if (has_blocks) gcode.reset_stepper_timeout(ms);      // Reset timeout for M18/M84, M85 max 'kill', and laser.
430
 
428
 
431
-    // Any moves in the planner? Resets both the M18/M84
432
-    // activity timeout and the M85 max 'kill' timeout
433
-    if (planner.has_blocks_queued())
434
-      gcode.reset_stepper_timeout(ms);
435
-    else if (!do_reset_timeout && gcode.stepper_inactive_timeout()) {
436
-      if (!already_shutdown_steppers) {
437
-        already_shutdown_steppers = true;  // L6470 SPI will consume 99% of free time without this
438
-
439
-        // Individual axes will be disabled if configured
440
-        TERN_(DISABLE_INACTIVE_X, stepper.disable_axis(X_AXIS));
441
-        TERN_(DISABLE_INACTIVE_Y, stepper.disable_axis(Y_AXIS));
442
-        TERN_(DISABLE_INACTIVE_Z, stepper.disable_axis(Z_AXIS));
443
-        TERN_(DISABLE_INACTIVE_I, stepper.disable_axis(I_AXIS));
444
-        TERN_(DISABLE_INACTIVE_J, stepper.disable_axis(J_AXIS));
445
-        TERN_(DISABLE_INACTIVE_K, stepper.disable_axis(K_AXIS));
446
-        TERN_(DISABLE_INACTIVE_U, stepper.disable_axis(U_AXIS));
447
-        TERN_(DISABLE_INACTIVE_V, stepper.disable_axis(V_AXIS));
448
-        TERN_(DISABLE_INACTIVE_W, stepper.disable_axis(W_AXIS));
449
-        TERN_(DISABLE_INACTIVE_E, stepper.disable_e_steppers());
450
-
451
-        TERN_(AUTO_BED_LEVELING_UBL, bedlevel.steppers_were_disabled());
429
+  // M18 / M84 : Handle steppers inactive time timeout
430
+  #if HAS_DISABLE_INACTIVE_AXIS
431
+    if (gcode.stepper_inactive_time) {
432
+
433
+      static bool already_shutdown_steppers; // = false
434
+
435
+      if (!has_blocks && !do_reset_timeout && gcode.stepper_inactive_timeout()) {
436
+        if (!already_shutdown_steppers) {
437
+          already_shutdown_steppers = true;  // L6470 SPI will consume 99% of free time without this
438
+
439
+          // Individual axes will be disabled if configured
440
+          TERN_(DISABLE_INACTIVE_X, stepper.disable_axis(X_AXIS));
441
+          TERN_(DISABLE_INACTIVE_Y, stepper.disable_axis(Y_AXIS));
442
+          TERN_(DISABLE_INACTIVE_Z, stepper.disable_axis(Z_AXIS));
443
+          TERN_(DISABLE_INACTIVE_I, stepper.disable_axis(I_AXIS));
444
+          TERN_(DISABLE_INACTIVE_J, stepper.disable_axis(J_AXIS));
445
+          TERN_(DISABLE_INACTIVE_K, stepper.disable_axis(K_AXIS));
446
+          TERN_(DISABLE_INACTIVE_U, stepper.disable_axis(U_AXIS));
447
+          TERN_(DISABLE_INACTIVE_V, stepper.disable_axis(V_AXIS));
448
+          TERN_(DISABLE_INACTIVE_W, stepper.disable_axis(W_AXIS));
449
+          TERN_(DISABLE_INACTIVE_E, stepper.disable_e_steppers());
450
+
451
+          TERN_(AUTO_BED_LEVELING_UBL, bedlevel.steppers_were_disabled());
452
+        }
452
       }
453
       }
454
+      else
455
+        already_shutdown_steppers = false;
453
     }
456
     }
454
-    else
455
-      already_shutdown_steppers = false;
456
-  }
457
+  #endif
457
 
458
 
458
   #if ENABLED(PHOTO_GCODE) && PIN_EXISTS(CHDK)
459
   #if ENABLED(PHOTO_GCODE) && PIN_EXISTS(CHDK)
459
     // Check if CHDK should be set to LOW (after M240 set it HIGH)
460
     // Check if CHDK should be set to LOW (after M240 set it HIGH)

+ 2
- 2
Marlin/src/feature/spindle_laser.cpp Ver fichero

39
 #endif
39
 #endif
40
 
40
 
41
 SpindleLaser cutter;
41
 SpindleLaser cutter;
42
-uint8_t SpindleLaser::power;
42
+uint8_t SpindleLaser::power,
43
+        SpindleLaser::last_power_applied; // = 0                      // Basic power state tracking
43
 #if ENABLED(LASER_FEATURE)
44
 #if ENABLED(LASER_FEATURE)
44
   cutter_test_pulse_t SpindleLaser::testPulse = 50;                   // Test fire Pulse time ms value.
45
   cutter_test_pulse_t SpindleLaser::testPulse = 50;                   // Test fire Pulse time ms value.
45
 #endif
46
 #endif
113
  * @param opwr Power value. Range 0 to MAX. When 0 disable spindle/laser.
114
  * @param opwr Power value. Range 0 to MAX. When 0 disable spindle/laser.
114
  */
115
  */
115
 void SpindleLaser::apply_power(const uint8_t opwr) {
116
 void SpindleLaser::apply_power(const uint8_t opwr) {
116
-  static uint8_t last_power_applied = 0;
117
   if (opwr == last_power_applied) return;
117
   if (opwr == last_power_applied) return;
118
   last_power_applied = opwr;
118
   last_power_applied = opwr;
119
   power = opwr;
119
   power = opwr;

+ 2
- 1
Marlin/src/feature/spindle_laser.h Ver fichero

89
   #endif
89
   #endif
90
 
90
 
91
   static bool isReady;                    // Ready to apply power setting from the UI to OCR
91
   static bool isReady;                    // Ready to apply power setting from the UI to OCR
92
-  static uint8_t power;
92
+  static uint8_t power,
93
+                 last_power_applied;      // Basic power state tracking
93
 
94
 
94
   #if ENABLED(MARLIN_DEV_MODE)
95
   #if ENABLED(MARLIN_DEV_MODE)
95
     static cutter_frequency_t frequency;  // Set PWM frequency; range: 2K-50K
96
     static cutter_frequency_t frequency;  // Set PWM frequency; range: 2K-50K

+ 10
- 1
Marlin/src/gcode/control/M17_M18_M84.cpp Ver fichero

211
 void GcodeSuite::M18_M84() {
211
 void GcodeSuite::M18_M84() {
212
   if (parser.seenval('S')) {
212
   if (parser.seenval('S')) {
213
     reset_stepper_timeout();
213
     reset_stepper_timeout();
214
-    stepper_inactive_time = parser.value_millis_from_seconds();
214
+    #if HAS_DISABLE_INACTIVE_AXIS
215
+      const millis_t ms = parser.value_millis_from_seconds();
216
+      #if LASER_SAFETY_TIMEOUT_MS > 0
217
+        if (ms && ms <= LASER_SAFETY_TIMEOUT_MS) {
218
+          SERIAL_ECHO_MSG("M18 timeout must be > ", MS_TO_SEC(LASER_SAFETY_TIMEOUT_MS + 999), " s for laser safety.");
219
+          return;
220
+        }
221
+      #endif
222
+      stepper_inactive_time = ms;
223
+    #endif
215
   }
224
   }
216
   else {
225
   else {
217
     if (parser.seen_axis()) {
226
     if (parser.seen_axis()) {

+ 4
- 0
Marlin/src/gcode/control/M3-M5.cpp Ver fichero

66
  *  PWM duty cycle goes from 0 (off) to 255 (always on).
66
  *  PWM duty cycle goes from 0 (off) to 255 (always on).
67
  */
67
  */
68
 void GcodeSuite::M3_M4(const bool is_M4) {
68
 void GcodeSuite::M3_M4(const bool is_M4) {
69
+  #if LASER_SAFETY_TIMEOUT_MS > 0
70
+    reset_stepper_timeout(); // Reset timeout to allow subsequent G-code to power the laser (imm.)
71
+  #endif
72
+
69
   #if EITHER(SPINDLE_LASER_USE_PWM, SPINDLE_SERVO)
73
   #if EITHER(SPINDLE_LASER_USE_PWM, SPINDLE_SERVO)
70
     auto get_s_power = [] {
74
     auto get_s_power = [] {
71
       if (parser.seenval('S')) {
75
       if (parser.seenval('S')) {

+ 8
- 1
Marlin/src/gcode/control/M85.cpp Ver fichero

29
 
29
 
30
   if (parser.seen('S')) {
30
   if (parser.seen('S')) {
31
     reset_stepper_timeout();
31
     reset_stepper_timeout();
32
-    max_inactive_time = parser.value_millis_from_seconds();
32
+    const millis_t ms = parser.value_millis_from_seconds();
33
+    #if LASER_SAFETY_TIMEOUT_MS > 0
34
+      if (ms && ms <= LASER_SAFETY_TIMEOUT_MS) {
35
+        SERIAL_ECHO_MSG("M85 timeout must be > ", MS_TO_SEC(LASER_SAFETY_TIMEOUT_MS + 999), " s for laser safety.");
36
+        return;
37
+      }
38
+    #endif
39
+    max_inactive_time = ms;
33
   }
40
   }
34
 
41
 
35
 }
42
 }

+ 5
- 2
Marlin/src/gcode/gcode.cpp Ver fichero

73
 
73
 
74
 // Inactivity shutdown
74
 // Inactivity shutdown
75
 millis_t GcodeSuite::previous_move_ms = 0,
75
 millis_t GcodeSuite::previous_move_ms = 0,
76
-         GcodeSuite::max_inactive_time = 0,
77
-         GcodeSuite::stepper_inactive_time = SEC_TO_MS(DEFAULT_STEPPER_DEACTIVE_TIME);
76
+         GcodeSuite::max_inactive_time = 0;
77
+
78
+#if HAS_DISABLE_INACTIVE_AXIS
79
+  millis_t GcodeSuite::stepper_inactive_time = SEC_TO_MS(DEFAULT_STEPPER_DEACTIVE_TIME);
80
+#endif
78
 
81
 
79
 // Relative motion mode for each logical axis
82
 // Relative motion mode for each logical axis
80
 static constexpr xyze_bool_t ar_init = AXIS_RELATIVE_MODES;
83
 static constexpr xyze_bool_t ar_init = AXIS_RELATIVE_MODES;

+ 11
- 5
Marlin/src/gcode/gcode.h Ver fichero

396
     static bool select_coordinate_system(const int8_t _new);
396
     static bool select_coordinate_system(const int8_t _new);
397
   #endif
397
   #endif
398
 
398
 
399
-  static millis_t previous_move_ms, max_inactive_time, stepper_inactive_time;
400
-  FORCE_INLINE static void reset_stepper_timeout(const millis_t ms=millis()) { previous_move_ms = ms; }
399
+  static millis_t previous_move_ms, max_inactive_time;
401
   FORCE_INLINE static bool stepper_max_timed_out(const millis_t ms=millis()) {
400
   FORCE_INLINE static bool stepper_max_timed_out(const millis_t ms=millis()) {
402
     return max_inactive_time && ELAPSED(ms, previous_move_ms + max_inactive_time);
401
     return max_inactive_time && ELAPSED(ms, previous_move_ms + max_inactive_time);
403
   }
402
   }
404
-  FORCE_INLINE static bool stepper_inactive_timeout(const millis_t ms=millis()) {
405
-    return ELAPSED(ms, previous_move_ms + stepper_inactive_time);
406
-  }
403
+  FORCE_INLINE static void reset_stepper_timeout(const millis_t ms=millis()) { previous_move_ms = ms; }
404
+
405
+  #if HAS_DISABLE_INACTIVE_AXIS
406
+    static millis_t stepper_inactive_time;
407
+    FORCE_INLINE static bool stepper_inactive_timeout(const millis_t ms=millis()) {
408
+      return ELAPSED(ms, previous_move_ms + stepper_inactive_time);
409
+    }
410
+  #else
411
+    static bool stepper_inactive_timeout(const millis_t) { return false; }
412
+  #endif
407
 
413
 
408
   static void report_echo_start(const bool forReplay);
414
   static void report_echo_start(const bool forReplay);
409
   static void report_heading(const bool forReplay, FSTR_P const fstr, const bool eol=true);
415
   static void report_heading(const bool forReplay, FSTR_P const fstr, const bool eol=true);

+ 4
- 0
Marlin/src/inc/Conditionals_adv.h Ver fichero

1044
   #undef CONFIGURATION_EMBEDDING
1044
   #undef CONFIGURATION_EMBEDDING
1045
   #define CANNOT_EMBED_CONFIGURATION defined(__AVR__)
1045
   #define CANNOT_EMBED_CONFIGURATION defined(__AVR__)
1046
 #endif
1046
 #endif
1047
+
1048
+#if ANY(DISABLE_INACTIVE_X, DISABLE_INACTIVE_Y, DISABLE_INACTIVE_Z, DISABLE_INACTIVE_I, DISABLE_INACTIVE_J, DISABLE_INACTIVE_K, DISABLE_INACTIVE_U, DISABLE_INACTIVE_V, DISABLE_INACTIVE_W, DISABLE_INACTIVE_E)
1049
+  #define HAS_DISABLE_INACTIVE_AXIS 1
1050
+#endif

+ 6
- 0
Marlin/src/inc/SanityCheck.h Ver fichero

3867
       #error "Enabled an inline laser feature without inline laser power being enabled."
3867
       #error "Enabled an inline laser feature without inline laser power being enabled."
3868
     #endif
3868
     #endif
3869
   #endif
3869
   #endif
3870
+
3870
   #define _PIN_CONFLICT(P) (PIN_EXISTS(P) && P##_PIN == SPINDLE_LASER_PWM_PIN)
3871
   #define _PIN_CONFLICT(P) (PIN_EXISTS(P) && P##_PIN == SPINDLE_LASER_PWM_PIN)
3871
   #if BOTH(SPINDLE_FEATURE, LASER_FEATURE)
3872
   #if BOTH(SPINDLE_FEATURE, LASER_FEATURE)
3872
     #error "Enable only one of SPINDLE_FEATURE or LASER_FEATURE."
3873
     #error "Enable only one of SPINDLE_FEATURE or LASER_FEATURE."
3934
     #endif
3935
     #endif
3935
   #endif
3936
   #endif
3936
   #undef _PIN_CONFLICT
3937
   #undef _PIN_CONFLICT
3938
+
3939
+  #ifdef LASER_SAFETY_TIMEOUT_MS
3940
+    static_assert(LASER_SAFETY_TIMEOUT_MS < (DEFAULT_STEPPER_DEACTIVE_TIME) * 1000UL, "LASER_SAFETY_TIMEOUT_MS must be less than DEFAULT_STEPPER_DEACTIVE_TIME (" STRINGIFY(DEFAULT_STEPPER_DEACTIVE_TIME) " seconds)");
3941
+  #endif
3942
+
3937
 #endif
3943
 #endif
3938
 
3944
 
3939
 #if ENABLED(COOLANT_MIST) && !PIN_EXISTS(COOLANT_MIST)
3945
 #if ENABLED(COOLANT_MIST) && !PIN_EXISTS(COOLANT_MIST)

+ 13
- 0
Marlin/src/module/temperature.cpp Ver fichero

71
   #include "../libs/nozzle.h"
71
   #include "../libs/nozzle.h"
72
 #endif
72
 #endif
73
 
73
 
74
+#if LASER_SAFETY_TIMEOUT_MS > 0
75
+  #include "../feature/spindle_laser.h"
76
+#endif
77
+
74
 // MAX TC related macros
78
 // MAX TC related macros
75
 #define TEMP_SENSOR_IS_MAX(n, M) (ENABLED(TEMP_SENSOR_##n##_IS_MAX##M) || (ENABLED(TEMP_SENSOR_REDUNDANT_IS_MAX##M) && REDUNDANT_TEMP_MATCH(SOURCE, E##n)))
79
 #define TEMP_SENSOR_IS_MAX(n, M) (ENABLED(TEMP_SENSOR_##n##_IS_MAX##M) || (ENABLED(TEMP_SENSOR_REDUNDANT_IS_MAX##M) && REDUNDANT_TEMP_MATCH(SOURCE, E##n)))
76
 #define TEMP_SENSOR_IS_ANY_MAX_TC(n) (ENABLED(TEMP_SENSOR_##n##_IS_MAX_TC) || (ENABLED(TEMP_SENSOR_REDUNDANT_IS_MAX_TC) && REDUNDANT_TEMP_MATCH(SOURCE, E##n)))
80
 #define TEMP_SENSOR_IS_ANY_MAX_TC(n) (ENABLED(TEMP_SENSOR_##n##_IS_MAX_TC) || (ENABLED(TEMP_SENSOR_REDUNDANT_IS_MAX_TC) && REDUNDANT_TEMP_MATCH(SOURCE, E##n)))
3328
 
3332
 
3329
 /**
3333
 /**
3330
  * Handle various ~1kHz tasks associated with temperature
3334
  * Handle various ~1kHz tasks associated with temperature
3335
+ *  - Check laser safety timeout
3331
  *  - Heater PWM (~1kHz with scaler)
3336
  *  - Heater PWM (~1kHz with scaler)
3332
  *  - LCD Button polling (~500Hz)
3337
  *  - LCD Button polling (~500Hz)
3333
  *  - Start / Read one ADC sensor
3338
  *  - Start / Read one ADC sensor
3337
  */
3342
  */
3338
 void Temperature::isr() {
3343
 void Temperature::isr() {
3339
 
3344
 
3345
+  // Shut down the laser if steppers are inactive for > LASER_SAFETY_TIMEOUT_MS ms
3346
+  #if LASER_SAFETY_TIMEOUT_MS > 0
3347
+    if (cutter.last_power_applied && ELAPSED(millis(), gcode.previous_move_ms + (LASER_SAFETY_TIMEOUT_MS))) {
3348
+      cutter.power = 0;       // Prevent planner idle from re-enabling power
3349
+      cutter.apply_power(0);
3350
+    }
3351
+  #endif
3352
+
3340
   static int8_t temp_count = -1;
3353
   static int8_t temp_count = -1;
3341
   static ADCSensorState adc_sensor_state = StartupDelay;
3354
   static ADCSensorState adc_sensor_state = StartupDelay;
3342
   static uint8_t pwm_count = _BV(SOFT_PWM_SCALE);
3355
   static uint8_t pwm_count = _BV(SOFT_PWM_SCALE);

+ 1
- 1
buildroot/tests/BIGTREE_SKR_PRO Ver fichero

26
         CUTTER_POWER_UNIT PERCENT \
26
         CUTTER_POWER_UNIT PERCENT \
27
         SPINDLE_LASER_PWM_PIN HEATER_1_PIN SPINDLE_LASER_ENA_PIN HEATER_2_PIN \
27
         SPINDLE_LASER_PWM_PIN HEATER_1_PIN SPINDLE_LASER_ENA_PIN HEATER_2_PIN \
28
         TEMP_SENSOR_COOLER 1000 TEMP_COOLER_PIN PD13
28
         TEMP_SENSOR_COOLER 1000 TEMP_COOLER_PIN PD13
29
-opt_enable LASER_FEATURE REPRAP_DISCOUNT_SMART_CONTROLLER
29
+opt_enable LASER_FEATURE LASER_SAFETY_TIMEOUT_MS REPRAP_DISCOUNT_SMART_CONTROLLER
30
 exec_test $1 $2 "BigTreeTech SKR Pro | Laser (Percent) | Cooling | LCD" "$3"
30
 exec_test $1 $2 "BigTreeTech SKR Pro | Laser (Percent) | Cooling | LCD" "$3"
31
 
31
 
32
 # clean up
32
 # clean up

+ 4
- 4
buildroot/tests/mega2560 Ver fichero

179
         DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \
179
         DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \
180
         MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \
180
         MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \
181
         AXIS_RELATIVE_MODES '{ false, false, false }'
181
         AXIS_RELATIVE_MODES '{ false, false, false }'
182
-opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT \
183
-           LASER_FEATURE AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN LASER_COOLANT_FLOW_METER MEATPACK_ON_SERIAL_PORT_1
182
+opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT MEATPACK_ON_SERIAL_PORT_1 \
183
+           LASER_FEATURE LASER_SAFETY_TIMEOUT_MS LASER_COOLANT_FLOW_METER AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN
184
 exec_test $1 $2 "MEGA2560 RAMPS | Laser Feature | Air Evacuation | Air Assist | Cooler | Flowmeter | 12864 LCD | meatpack | SERIAL_PORT_2 " "$3"
184
 exec_test $1 $2 "MEGA2560 RAMPS | Laser Feature | Air Evacuation | Air Assist | Cooler | Flowmeter | 12864 LCD | meatpack | SERIAL_PORT_2 " "$3"
185
 
185
 
186
 #
186
 #
193
         DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \
193
         DEFAULT_MAX_ACCELERATION '{ 3000, 3000, 100 }' \
194
         MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \
194
         MANUAL_FEEDRATE '{ 50*60, 50*60, 4*60 }' \
195
         AXIS_RELATIVE_MODES '{ false, false, false }'
195
         AXIS_RELATIVE_MODES '{ false, false, false }'
196
-opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT PRINTCOUNTER \
197
-           LASER_FEATURE AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN LASER_COOLANT_FLOW_METER I2C_AMMETER
196
+opt_enable REPRAP_DISCOUNT_SMART_CONTROLLER SDSUPPORT EEPROM_SETTINGS EEPROM_BOOT_SILENT EEPROM_AUTO_INIT PRINTCOUNTER I2C_AMMETER \
197
+           LASER_FEATURE LASER_SAFETY_TIMEOUT_MS LASER_COOLANT_FLOW_METER AIR_EVACUATION AIR_EVACUATION_PIN AIR_ASSIST AIR_ASSIST_PIN
198
 exec_test $1 $2 "MEGA2560 RAMPS | Laser Feature | Air Evacuation | Air Assist | Cooler | Flowmeter | 44780 LCD " "$3"
198
 exec_test $1 $2 "MEGA2560 RAMPS | Laser Feature | Air Evacuation | Air Assist | Cooler | Flowmeter | 44780 LCD " "$3"
199
 
199
 
200
 #
200
 #

Loading…
Cancelar
Guardar