|
@@ -1312,22 +1312,20 @@ bool get_target_extruder_from_command(int code) {
|
1312
|
1312
|
|
1313
|
1313
|
static DualXMode dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE;
|
1314
|
1314
|
|
1315
|
|
- static float x_home_pos(int extruder) {
|
|
1315
|
+ static float x_home_pos(const int extruder) {
|
1316
|
1316
|
if (extruder == 0)
|
1317
|
1317
|
return LOGICAL_X_POSITION(base_home_pos(X_AXIS));
|
1318
|
1318
|
else
|
1319
|
1319
|
/**
|
1320
|
1320
|
* In dual carriage mode the extruder offset provides an override of the
|
1321
|
|
- * second X-carriage offset when homed - otherwise X2_HOME_POS is used.
|
1322
|
|
- * This allow soft recalibration of the second extruder offset position
|
|
1321
|
+ * second X-carriage position when homed - otherwise X2_HOME_POS is used.
|
|
1322
|
+ * This allows soft recalibration of the second extruder home position
|
1323
|
1323
|
* without firmware reflash (through the M218 command).
|
1324
|
1324
|
*/
|
1325
|
|
- return (hotend_offset[X_AXIS][1] > 0) ? hotend_offset[X_AXIS][1] : X2_HOME_POS;
|
|
1325
|
+ return LOGICAL_X_POSITION(hotend_offset[X_AXIS][1] > 0 ? hotend_offset[X_AXIS][1] : X2_HOME_POS);
|
1326
|
1326
|
}
|
1327
|
1327
|
|
1328
|
|
- static int x_home_dir(int extruder) {
|
1329
|
|
- return (extruder == 0) ? X_HOME_DIR : X2_HOME_DIR;
|
1330
|
|
- }
|
|
1328
|
+ static int x_home_dir(const int extruder) { return extruder ? X2_HOME_DIR : X_HOME_DIR; }
|
1331
|
1329
|
|
1332
|
1330
|
static float inactive_extruder_x_pos = X2_MAX_POS; // used in mode 0 & 1
|
1333
|
1331
|
static bool active_extruder_parked = false; // used in mode 1 & 2
|
|
@@ -1351,25 +1349,33 @@ void update_software_endstops(AxisEnum axis) {
|
1351
|
1349
|
float offs = LOGICAL_POSITION(0, axis);
|
1352
|
1350
|
|
1353
|
1351
|
#if ENABLED(DUAL_X_CARRIAGE)
|
|
1352
|
+ bool did_update = false;
|
1354
|
1353
|
if (axis == X_AXIS) {
|
|
1354
|
+
|
|
1355
|
+ // In Dual X mode hotend_offset[X] is T1's home position
|
1355
|
1356
|
float dual_max_x = max(hotend_offset[X_AXIS][1], X2_MAX_POS);
|
|
1357
|
+
|
1356
|
1358
|
if (active_extruder != 0) {
|
|
1359
|
+ // T1 can move from X2_MIN_POS to X2_MAX_POS or X2 home position (whichever is larger)
|
1357
|
1360
|
soft_endstop_min[X_AXIS] = X2_MIN_POS + offs;
|
1358
|
1361
|
soft_endstop_max[X_AXIS] = dual_max_x + offs;
|
1359
|
|
- return;
|
1360
|
1362
|
}
|
1361
|
1363
|
else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) {
|
|
1364
|
+ // In Duplication Mode, T0 can move as far left as X_MIN_POS
|
|
1365
|
+ // but not so far to the right that T1 would move past the end
|
1362
|
1366
|
soft_endstop_min[X_AXIS] = base_min_pos(X_AXIS) + offs;
|
1363
|
1367
|
soft_endstop_max[X_AXIS] = min(base_max_pos(X_AXIS), dual_max_x - duplicate_extruder_x_offset) + offs;
|
1364
|
|
- return;
|
|
1368
|
+ }
|
|
1369
|
+ else {
|
|
1370
|
+ // In other modes, T0 can move from X_MIN_POS to X_MAX_POS
|
|
1371
|
+ soft_endstop_min[axis] = base_min_pos(axis) + offs;
|
|
1372
|
+ soft_endstop_max[axis] = base_max_pos(axis) + offs;
|
1365
|
1373
|
}
|
1366
|
1374
|
}
|
1367
|
|
- else
|
1368
|
|
- #endif
|
1369
|
|
- {
|
|
1375
|
+ #else
|
1370
|
1376
|
soft_endstop_min[axis] = base_min_pos(axis) + offs;
|
1371
|
1377
|
soft_endstop_max[axis] = base_max_pos(axis) + offs;
|
1372
|
|
- }
|
|
1378
|
+ #endif
|
1373
|
1379
|
|
1374
|
1380
|
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
1375
|
1381
|
if (DEBUGGING(LEVELING)) {
|
|
@@ -1418,6 +1424,7 @@ static void set_home_offset(AxisEnum axis, float v) {
|
1418
|
1424
|
* current_position to home, because neither X nor Y is at home until
|
1419
|
1425
|
* both are at home. Z can however be homed individually.
|
1420
|
1426
|
*
|
|
1427
|
+ * Callers must sync the planner position after calling this!
|
1421
|
1428
|
*/
|
1422
|
1429
|
static void set_axis_is_at_home(AxisEnum axis) {
|
1423
|
1430
|
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
|
@@ -1434,12 +1441,8 @@ static void set_axis_is_at_home(AxisEnum axis) {
|
1434
|
1441
|
update_software_endstops(axis);
|
1435
|
1442
|
|
1436
|
1443
|
#if ENABLED(DUAL_X_CARRIAGE)
|
1437
|
|
- if (axis == X_AXIS && (active_extruder != 0 || dual_x_carriage_mode == DXC_DUPLICATION_MODE)) {
|
1438
|
|
- if (active_extruder != 0)
|
1439
|
|
- current_position[X_AXIS] = x_home_pos(active_extruder);
|
1440
|
|
- else
|
1441
|
|
- current_position[X_AXIS] = LOGICAL_X_POSITION(base_home_pos(X_AXIS));
|
1442
|
|
- update_software_endstops(X_AXIS);
|
|
1444
|
+ if (axis == X_AXIS && (active_extruder == 1 || dual_x_carriage_mode == DXC_DUPLICATION_MODE)) {
|
|
1445
|
+ current_position[X_AXIS] = x_home_pos(active_extruder);
|
1443
|
1446
|
return;
|
1444
|
1447
|
}
|
1445
|
1448
|
#endif
|
|
@@ -3252,13 +3255,21 @@ inline void gcode_G4() {
|
3252
|
3255
|
#endif
|
3253
|
3256
|
)
|
3254
|
3257
|
) {
|
|
3258
|
+
|
3255
|
3259
|
#if HOMING_Z_WITH_PROBE
|
3256
|
3260
|
destination[X_AXIS] -= X_PROBE_OFFSET_FROM_EXTRUDER;
|
3257
|
3261
|
destination[Y_AXIS] -= Y_PROBE_OFFSET_FROM_EXTRUDER;
|
3258
|
3262
|
#endif
|
|
3263
|
+
|
3259
|
3264
|
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
3260
|
3265
|
if (DEBUGGING(LEVELING)) DEBUG_POS("Z_SAFE_HOMING", destination);
|
3261
|
3266
|
#endif
|
|
3267
|
+
|
|
3268
|
+ // This causes the carriage on Dual X to unpark
|
|
3269
|
+ #if ENABLED(DUAL_X_CARRIAGE)
|
|
3270
|
+ active_extruder_parked = false;
|
|
3271
|
+ #endif
|
|
3272
|
+
|
3262
|
3273
|
do_blocking_move_to_xy(destination[X_AXIS], destination[Y_AXIS]);
|
3263
|
3274
|
HOMEAXIS(Z);
|
3264
|
3275
|
}
|
|
@@ -3407,20 +3418,31 @@ inline void gcode_G28() {
|
3407
|
3418
|
|
3408
|
3419
|
// Home X
|
3409
|
3420
|
if (home_all_axis || homeX) {
|
|
3421
|
+
|
3410
|
3422
|
#if ENABLED(DUAL_X_CARRIAGE)
|
3411
|
|
- int tmp_extruder = active_extruder;
|
3412
|
|
- active_extruder = !active_extruder;
|
|
3423
|
+
|
|
3424
|
+ // Always home the 2nd (right) extruder first
|
|
3425
|
+ active_extruder = 1;
|
3413
|
3426
|
HOMEAXIS(X);
|
|
3427
|
+
|
|
3428
|
+ // Remember this extruder's position for later tool change
|
3414
|
3429
|
inactive_extruder_x_pos = RAW_X_POSITION(current_position[X_AXIS]);
|
3415
|
|
- active_extruder = tmp_extruder;
|
|
3430
|
+
|
|
3431
|
+ // Home the 1st (left) extruder
|
|
3432
|
+ active_extruder = 0;
|
3416
|
3433
|
HOMEAXIS(X);
|
3417
|
|
- // reset state used by the different modes
|
|
3434
|
+
|
|
3435
|
+ // Consider the active extruder to be parked
|
3418
|
3436
|
memcpy(raised_parked_position, current_position, sizeof(raised_parked_position));
|
3419
|
3437
|
delayed_move_time = 0;
|
3420
|
3438
|
active_extruder_parked = true;
|
|
3439
|
+
|
3421
|
3440
|
#else
|
|
3441
|
+
|
3422
|
3442
|
HOMEAXIS(X);
|
|
3443
|
+
|
3423
|
3444
|
#endif
|
|
3445
|
+
|
3424
|
3446
|
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
3425
|
3447
|
if (DEBUGGING(LEVELING)) DEBUG_POS("> homeX", current_position);
|
3426
|
3448
|
#endif
|
|
@@ -7446,10 +7468,8 @@ inline void invalid_extruder_error(const uint8_t &e) {
|
7446
|
7468
|
void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool no_move/*=false*/) {
|
7447
|
7469
|
#if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1
|
7448
|
7470
|
|
7449
|
|
- if (tmp_extruder >= MIXING_VIRTUAL_TOOLS) {
|
7450
|
|
- invalid_extruder_error(tmp_extruder);
|
7451
|
|
- return;
|
7452
|
|
- }
|
|
7471
|
+ if (tmp_extruder >= MIXING_VIRTUAL_TOOLS)
|
|
7472
|
+ return invalid_extruder_error(tmp_extruder);
|
7453
|
7473
|
|
7454
|
7474
|
// T0-Tnnn: Switch virtual tool by changing the mix
|
7455
|
7475
|
for (uint8_t j = 0; j < MIXING_STEPPERS; j++)
|
|
@@ -7459,10 +7479,8 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
|
7459
|
7479
|
|
7460
|
7480
|
#if HOTENDS > 1
|
7461
|
7481
|
|
7462
|
|
- if (tmp_extruder >= EXTRUDERS) {
|
7463
|
|
- invalid_extruder_error(tmp_extruder);
|
7464
|
|
- return;
|
7465
|
|
- }
|
|
7482
|
+ if (tmp_extruder >= EXTRUDERS)
|
|
7483
|
+ return invalid_extruder_error(tmp_extruder);
|
7466
|
7484
|
|
7467
|
7485
|
float old_feedrate_mm_s = feedrate_mm_s;
|
7468
|
7486
|
|
|
@@ -7490,22 +7508,28 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
|
7490
|
7508
|
}
|
7491
|
7509
|
#endif
|
7492
|
7510
|
|
7493
|
|
- if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE && IsRunning() &&
|
7494
|
|
- (delayed_move_time || current_position[X_AXIS] != x_home_pos(active_extruder))
|
|
7511
|
+ const float xhome = x_home_pos(active_extruder);
|
|
7512
|
+ if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE
|
|
7513
|
+ && IsRunning()
|
|
7514
|
+ && (delayed_move_time || current_position[X_AXIS] != xhome)
|
7495
|
7515
|
) {
|
|
7516
|
+ float raised_z = current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT;
|
|
7517
|
+ #if ENABLED(max_software_endstops)
|
|
7518
|
+ NOMORE(raised_z, soft_endstop_max[Z_AXIS]);
|
|
7519
|
+ #endif
|
7496
|
7520
|
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
7497
|
7521
|
if (DEBUGGING(LEVELING)) {
|
7498
|
|
- SERIAL_ECHOPAIR("Raise to ", current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT); SERIAL_EOL;
|
7499
|
|
- SERIAL_ECHOPAIR("MoveX to ", x_home_pos(active_extruder)); SERIAL_EOL;
|
7500
|
|
- SERIAL_ECHOPAIR("Lower to ", current_position[Z_AXIS]); SERIAL_EOL;
|
|
7522
|
+ SERIAL_ECHOLNPAIR("Raise to ", raised_z);
|
|
7523
|
+ SERIAL_ECHOLNPAIR("MoveX to ", xhome);
|
|
7524
|
+ SERIAL_ECHOLNPAIR("Lower to ", current_position[Z_AXIS]);
|
7501
|
7525
|
}
|
7502
|
7526
|
#endif
|
7503
|
7527
|
// Park old head: 1) raise 2) move to park position 3) lower
|
7504
|
7528
|
for (uint8_t i = 0; i < 3; i++)
|
7505
|
7529
|
planner.buffer_line(
|
7506
|
|
- i == 0 ? current_position[X_AXIS] : x_home_pos(active_extruder),
|
|
7530
|
+ i == 0 ? current_position[X_AXIS] : xhome,
|
7507
|
7531
|
current_position[Y_AXIS],
|
7508
|
|
- current_position[Z_AXIS] + (i == 2 ? 0 : TOOLCHANGE_PARK_ZLIFT),
|
|
7532
|
+ i == 2 ? current_position[Z_AXIS] : raised_z,
|
7509
|
7533
|
current_position[E_AXIS],
|
7510
|
7534
|
planner.max_feedrate_mm_s[i == 1 ? X_AXIS : Z_AXIS],
|
7511
|
7535
|
active_extruder
|
|
@@ -7513,9 +7537,11 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
|
7513
|
7537
|
stepper.synchronize();
|
7514
|
7538
|
}
|
7515
|
7539
|
|
7516
|
|
- // apply Y & Z extruder offset (x offset is already used in determining home pos)
|
|
7540
|
+ // Apply Y & Z extruder offset (X offset is used as home pos with Dual X)
|
7517
|
7541
|
current_position[Y_AXIS] -= hotend_offset[Y_AXIS][active_extruder] - hotend_offset[Y_AXIS][tmp_extruder];
|
7518
|
7542
|
current_position[Z_AXIS] -= hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder];
|
|
7543
|
+
|
|
7544
|
+ // Activate the new extruder
|
7519
|
7545
|
active_extruder = tmp_extruder;
|
7520
|
7546
|
|
7521
|
7547
|
// This function resets the max/min values - the current position may be overwritten below.
|
|
@@ -7525,9 +7551,14 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
|
7525
|
7551
|
if (DEBUGGING(LEVELING)) DEBUG_POS("New Extruder", current_position);
|
7526
|
7552
|
#endif
|
7527
|
7553
|
|
|
7554
|
+ // Only when auto-parking are carriages safe to move
|
|
7555
|
+ if (dual_x_carriage_mode != DXC_AUTO_PARK_MODE) no_move = true;
|
|
7556
|
+
|
7528
|
7557
|
switch (dual_x_carriage_mode) {
|
7529
|
7558
|
case DXC_FULL_CONTROL_MODE:
|
|
7559
|
+ // New current position is the position of the activated extruder
|
7530
|
7560
|
current_position[X_AXIS] = LOGICAL_X_POSITION(inactive_extruder_x_pos);
|
|
7561
|
+ // Save the inactive extruder's position (from the old current_position)
|
7531
|
7562
|
inactive_extruder_x_pos = RAW_X_POSITION(destination[X_AXIS]);
|
7532
|
7563
|
break;
|
7533
|
7564
|
case DXC_AUTO_PARK_MODE:
|
|
@@ -7541,7 +7572,10 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
|
7541
|
7572
|
delayed_move_time = 0;
|
7542
|
7573
|
break;
|
7543
|
7574
|
case DXC_DUPLICATION_MODE:
|
7544
|
|
- active_extruder_parked = (active_extruder == 0); // this triggers the second extruder to move into the duplication position
|
|
7575
|
+ // If the new extruder is the left one, set it "parked"
|
|
7576
|
+ // This triggers the second extruder to move into the duplication position
|
|
7577
|
+ active_extruder_parked = (active_extruder == 0);
|
|
7578
|
+
|
7545
|
7579
|
if (active_extruder_parked)
|
7546
|
7580
|
current_position[X_AXIS] = LOGICAL_X_POSITION(inactive_extruder_x_pos);
|
7547
|
7581
|
else
|
|
@@ -7566,9 +7600,7 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n
|
7566
|
7600
|
float z_diff = hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder],
|
7567
|
7601
|
z_raise = 0.3 + (z_diff > 0.0 ? z_diff : 0.0);
|
7568
|
7602
|
|
7569
|
|
- set_destination_to_current();
|
7570
|
|
-
|
7571
|
|
- // Always raise by some amount
|
|
7603
|
+ // Always raise by some amount (destination copied from current_position earlier)
|
7572
|
7604
|
destination[Z_AXIS] += z_raise;
|
7573
|
7605
|
planner.buffer_line_kinematic(destination, planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
|
7574
|
7606
|
stepper.synchronize();
|
|
@@ -9223,23 +9255,6 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
|
9223
|
9255
|
switch (dual_x_carriage_mode) {
|
9224
|
9256
|
case DXC_FULL_CONTROL_MODE:
|
9225
|
9257
|
break;
|
9226
|
|
- case DXC_DUPLICATION_MODE:
|
9227
|
|
- if (active_extruder == 0) {
|
9228
|
|
- // move duplicate extruder into correct duplication position.
|
9229
|
|
- planner.set_position_mm(
|
9230
|
|
- LOGICAL_X_POSITION(inactive_extruder_x_pos),
|
9231
|
|
- current_position[Y_AXIS],
|
9232
|
|
- current_position[Z_AXIS],
|
9233
|
|
- current_position[E_AXIS]
|
9234
|
|
- );
|
9235
|
|
- planner.buffer_line(current_position[X_AXIS] + duplicate_extruder_x_offset,
|
9236
|
|
- current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], planner.max_feedrate_mm_s[X_AXIS], 1);
|
9237
|
|
- SYNC_PLAN_POSITION_KINEMATIC();
|
9238
|
|
- stepper.synchronize();
|
9239
|
|
- extruder_duplication_enabled = true;
|
9240
|
|
- active_extruder_parked = false;
|
9241
|
|
- }
|
9242
|
|
- break;
|
9243
|
9258
|
case DXC_AUTO_PARK_MODE:
|
9244
|
9259
|
if (current_position[E_AXIS] == destination[E_AXIS]) {
|
9245
|
9260
|
// This is a travel move (with no extrusion)
|
|
@@ -9252,13 +9267,39 @@ void set_current_from_steppers_for_axis(const AxisEnum axis) {
|
9252
|
9267
|
return false;
|
9253
|
9268
|
}
|
9254
|
9269
|
}
|
9255
|
|
- delayed_move_time = 0;
|
9256
|
9270
|
// unpark extruder: 1) raise, 2) move into starting XY position, 3) lower
|
9257
|
|
- planner.buffer_line(raised_parked_position[X_AXIS], raised_parked_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
|
9258
|
|
- planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS], current_position[E_AXIS], PLANNER_XY_FEEDRATE(), active_extruder);
|
9259
|
|
- planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
|
|
9271
|
+ for (uint8_t i = 0; i < 3; i++)
|
|
9272
|
+ planner.buffer_line(
|
|
9273
|
+ i == 0 ? raised_parked_position[X_AXIS] : current_position[X_AXIS],
|
|
9274
|
+ i == 0 ? raised_parked_position[Y_AXIS] : current_position[Y_AXIS],
|
|
9275
|
+ i == 2 ? current_position[Z_AXIS] : raised_parked_position[Z_AXIS],
|
|
9276
|
+ current_position[E_AXIS],
|
|
9277
|
+ i == 1 ? PLANNER_XY_FEEDRATE() : planner.max_feedrate_mm_s[Z_AXIS],
|
|
9278
|
+ active_extruder
|
|
9279
|
+ );
|
|
9280
|
+ delayed_move_time = 0;
|
9260
|
9281
|
active_extruder_parked = false;
|
9261
|
9282
|
break;
|
|
9283
|
+ case DXC_DUPLICATION_MODE:
|
|
9284
|
+ if (active_extruder == 0) {
|
|
9285
|
+ // move duplicate extruder into correct duplication position.
|
|
9286
|
+ planner.set_position_mm(
|
|
9287
|
+ LOGICAL_X_POSITION(inactive_extruder_x_pos),
|
|
9288
|
+ current_position[Y_AXIS],
|
|
9289
|
+ current_position[Z_AXIS],
|
|
9290
|
+ current_position[E_AXIS]
|
|
9291
|
+ );
|
|
9292
|
+ planner.buffer_line(
|
|
9293
|
+ current_position[X_AXIS] + duplicate_extruder_x_offset,
|
|
9294
|
+ current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS],
|
|
9295
|
+ planner.max_feedrate_mm_s[X_AXIS], 1
|
|
9296
|
+ );
|
|
9297
|
+ SYNC_PLAN_POSITION_KINEMATIC();
|
|
9298
|
+ stepper.synchronize();
|
|
9299
|
+ extruder_duplication_enabled = true;
|
|
9300
|
+ active_extruder_parked = false;
|
|
9301
|
+ }
|
|
9302
|
+ break;
|
9262
|
9303
|
}
|
9263
|
9304
|
}
|
9264
|
9305
|
return true;
|
|
@@ -9950,7 +9991,7 @@ void kill(const char* lcd_msg) {
|
9950
|
9991
|
disable_all_steppers();
|
9951
|
9992
|
|
9952
|
9993
|
#if HAS_POWER_SWITCH
|
9953
|
|
- pinMode(PS_ON_PIN, INPUT);
|
|
9994
|
+ SET_INPUT(PS_ON_PIN);
|
9954
|
9995
|
#endif
|
9955
|
9996
|
|
9956
|
9997
|
suicide();
|