Support dual x-carriage printers
Dual x-carriage designs offer some substantial improvements for dual extruder printing.
This commit is contained in:
		| @@ -146,6 +146,36 @@ | |||||||
|   #define EXTRUDERS 1 |   #define EXTRUDERS 1 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | // Enable this for dual x-carriage printers.  | ||||||
|  | // A dual x-carriage design has the advantage that the inactive extruder can be parked which | ||||||
|  | // prevents hot-end ooze contaminating the print. It also reduces the weight of each x-carriage | ||||||
|  | // allowing faster printing speeds. | ||||||
|  | #define DUAL_X_CARRIAGE | ||||||
|  | #ifdef DUAL_X_CARRIAGE | ||||||
|  | // Configuration for second X-carriage | ||||||
|  | // Note: the first x-carriage is defined as the x-carriage which homes to the minimum endstop; | ||||||
|  | // the second x-carriage always homes to the maximum endstop. | ||||||
|  | #define X2_MIN_POS 88     // set minimum to ensure second x-carriage doesn't hit the parked first X-carriage | ||||||
|  | #define X2_MAX_POS 350.45 // set maximum to the distance between toolheads when both heads are homed  | ||||||
|  | #define X2_HOME_DIR 1     // the second X-carriage always homes to the maximum endstop position | ||||||
|  | #define X2_HOME_POS X2_MAX_POS // default home position is the maximum carriage position  | ||||||
|  |     // However: In this mode the EXTRUDER_OFFSET_X value for the second extruder provides a software  | ||||||
|  |     // override for X2_HOME_POS. This also allow recalibration of the distance between the two endstops | ||||||
|  |     // without modifying the firmware (through the "M218 T1 X???" command). | ||||||
|  |     // Remember: you should set the second extruder x-offset to 0 in your slicer. | ||||||
|  |  | ||||||
|  | // Pins for second x-carriage stepper driver (defined here to avoid further complicating pins.h) | ||||||
|  | #define X2_ENABLE_PIN 29 | ||||||
|  | #define X2_STEP_PIN 25 | ||||||
|  | #define X2_DIR_PIN 23 | ||||||
|  |  | ||||||
|  | // The following settings control the behaviour of the automatic parking and unparking of inactive extruder | ||||||
|  | #define TOOLCHANGE_PARK_ZLIFT 0.1        // the distance to raise Z axis when parking an extruder | ||||||
|  | #define TOOLCHANGE_UNPARK_ZLIFT 1        // the distance to raise Z axis when unparking an extruder | ||||||
|  | #define TOOLCHANGE_UNPARK_SKIP_TRAVEL_MOVES // disable if slicer natively suports dual x-carriage mode.  | ||||||
|  |     // When enabled this avoids unnecessary & inadvertant moves from the last position of old extruder.  | ||||||
|  | #endif // DUAL_X_CARRIAGE | ||||||
|  |      | ||||||
| //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again: | //homing hits the endstop, then retracts by this distance, before it tries to slowly bump again: | ||||||
| #define X_HOME_RETRACT_MM 5  | #define X_HOME_RETRACT_MM 5  | ||||||
| #define Y_HOME_RETRACT_MM 5  | #define Y_HOME_RETRACT_MM 5  | ||||||
|   | |||||||
| @@ -96,7 +96,11 @@ void process_commands(); | |||||||
|  |  | ||||||
| void manage_inactivity(); | void manage_inactivity(); | ||||||
|  |  | ||||||
| #if defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 | #if defined(DUAL_X_CARRIAGE) && defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 \ | ||||||
|  |     && defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1 | ||||||
|  |   #define  enable_x() do { WRITE(X_ENABLE_PIN, X_ENABLE_ON); WRITE(X2_ENABLE_PIN, X_ENABLE_ON); } while (0) | ||||||
|  |   #define disable_x() do { WRITE(X_ENABLE_PIN,!X_ENABLE_ON); WRITE(X2_ENABLE_PIN,!X_ENABLE_ON); } while (0) | ||||||
|  | #elif defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 | ||||||
|   #define  enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) |   #define  enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON) | ||||||
|   #define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) |   #define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON) | ||||||
| #else | #else | ||||||
|   | |||||||
| @@ -677,7 +677,46 @@ XYZ_CONSTS_FROM_CONFIG(float, max_length,      MAX_LENGTH); | |||||||
| XYZ_CONSTS_FROM_CONFIG(float, home_retract_mm, HOME_RETRACT_MM); | XYZ_CONSTS_FROM_CONFIG(float, home_retract_mm, HOME_RETRACT_MM); | ||||||
| XYZ_CONSTS_FROM_CONFIG(signed char, home_dir,  HOME_DIR); | XYZ_CONSTS_FROM_CONFIG(signed char, home_dir,  HOME_DIR); | ||||||
|  |  | ||||||
|  | #ifdef DUAL_X_CARRIAGE | ||||||
|  |   #if EXTRUDERS == 1 || defined(COREXY) \ | ||||||
|  |       || !defined(X2_ENABLE_PIN) || !defined(X2_STEP_PIN) || !defined(X2_DIR_PIN) \ | ||||||
|  |       || !defined(X2_HOME_POS) || !defined(X2_MIN_POS) || !defined(X2_MAX_POS) \ | ||||||
|  |       || !defined(X_MAX_PIN) || X_MAX_PIN < 0 | ||||||
|  |     #error "Missing or invalid definitions for DUAL_X_CARRIAGE mode." | ||||||
|  |   #endif | ||||||
|  |   #if X_HOME_DIR != -1 || X2_HOME_DIR != 1 | ||||||
|  |     #error "Please use canonical x-carriage assignment" // the x-carriages are defined by their homing directions | ||||||
|  |   #endif   | ||||||
|  |      | ||||||
|  | static float x_home_pos(int extruder) { | ||||||
|  |   if (extruder == 0) | ||||||
|  |     return base_home_pos(X_AXIS) + add_homeing[X_AXIS]; | ||||||
|  |   else | ||||||
|  |     // In dual carriage mode the extruder offset provides an override of the | ||||||
|  |     // second X-carriage offset when homed - otherwise X2_HOME_POS is used. | ||||||
|  |     // This allow soft recalibration of the second extruder offset position without firmware reflash  | ||||||
|  |     // (through the M218 command). | ||||||
|  |     return (extruder_offset[X_AXIS][1] != 0) ? extruder_offset[X_AXIS][1] : X2_HOME_POS; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int x_home_dir(int extruder) { | ||||||
|  |   return (extruder == 0) ? X_HOME_DIR : X2_HOME_DIR; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static bool active_extruder_parked = false; | ||||||
|  | static float raised_parked_position[NUM_AXIS]; | ||||||
|  | static unsigned long delayed_move_time = 0; | ||||||
|  | #endif      | ||||||
|  |  | ||||||
| static void axis_is_at_home(int axis) { | static void axis_is_at_home(int axis) { | ||||||
|  | #ifdef DUAL_X_CARRIAGE | ||||||
|  |   if (axis == X_AXIS && active_extruder != 0) { | ||||||
|  |     current_position[X_AXIS] = x_home_pos(active_extruder); | ||||||
|  |     min_pos[X_AXIS] =          X2_MIN_POS; | ||||||
|  |     max_pos[X_AXIS] =          X2_MAX_POS; | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | #endif   | ||||||
|   current_position[axis] = base_home_pos(axis) + add_homeing[axis]; |   current_position[axis] = base_home_pos(axis) + add_homeing[axis]; | ||||||
|   min_pos[axis] =          base_min_pos(axis) + add_homeing[axis]; |   min_pos[axis] =          base_min_pos(axis) + add_homeing[axis]; | ||||||
|   max_pos[axis] =          base_max_pos(axis) + add_homeing[axis]; |   max_pos[axis] =          base_max_pos(axis) + add_homeing[axis]; | ||||||
| @@ -686,10 +725,16 @@ static void axis_is_at_home(int axis) { | |||||||
| static void homeaxis(int axis) { | static void homeaxis(int axis) { | ||||||
| #define HOMEAXIS_DO(LETTER) \ | #define HOMEAXIS_DO(LETTER) \ | ||||||
|   ((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1)) |   ((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1)) | ||||||
|  |  | ||||||
|   if (axis==X_AXIS ? HOMEAXIS_DO(X) : |   if (axis==X_AXIS ? HOMEAXIS_DO(X) : | ||||||
|       axis==Y_AXIS ? HOMEAXIS_DO(Y) : |       axis==Y_AXIS ? HOMEAXIS_DO(Y) : | ||||||
|       axis==Z_AXIS ? HOMEAXIS_DO(Z) : |       axis==Z_AXIS ? HOMEAXIS_DO(Z) : | ||||||
|       0) { |       0) { | ||||||
|  |     int axis_home_dir = home_dir(axis); | ||||||
|  | #ifdef DUAL_X_CARRIAGE | ||||||
|  |     if (axis == X_AXIS) | ||||||
|  |       axis_home_dir = x_home_dir(active_extruder); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|     // Engage Servo endstop if enabled |     // Engage Servo endstop if enabled | ||||||
|     #ifdef SERVO_ENDSTOPS |     #ifdef SERVO_ENDSTOPS | ||||||
| @@ -864,8 +909,14 @@ void process_commands() | |||||||
|       { |       { | ||||||
|         current_position[X_AXIS] = 0;current_position[Y_AXIS] = 0; |         current_position[X_AXIS] = 0;current_position[Y_AXIS] = 0; | ||||||
|  |  | ||||||
|  |        #ifdef DUAL_X_CARRIAGE | ||||||
|  |         int x_axis_home_dir = home_dir(X_AXIS); | ||||||
|  |        #else | ||||||
|  |         int x_axis_home_dir = x_home_dir(active_extruder); | ||||||
|  |        #endif | ||||||
|  |          | ||||||
|         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); |         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); | ||||||
|         destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR;destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR; |         destination[X_AXIS] = 1.5 * max_length(X_AXIS) * x_axis_home_dir;destination[Y_AXIS] = 1.5 * max_length(Y_AXIS) * home_dir(Y_AXIS); | ||||||
|         feedrate = homing_feedrate[X_AXIS]; |         feedrate = homing_feedrate[X_AXIS]; | ||||||
|         if(homing_feedrate[Y_AXIS]<feedrate) |         if(homing_feedrate[Y_AXIS]<feedrate) | ||||||
|           feedrate =homing_feedrate[Y_AXIS]; |           feedrate =homing_feedrate[Y_AXIS]; | ||||||
| @@ -890,6 +941,14 @@ void process_commands() | |||||||
|  |  | ||||||
|       if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) |       if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) | ||||||
|       { |       { | ||||||
|  |       #ifdef DUAL_X_CARRIAGE | ||||||
|  |         int tmp_extruder = active_extruder; | ||||||
|  |         active_extruder = !active_extruder; | ||||||
|  |         HOMEAXIS(X); | ||||||
|  |         active_extruder = tmp_extruder; | ||||||
|  |         active_extruder_parked = false;  | ||||||
|  |         delayed_move_time = 0; | ||||||
|  |       #endif          | ||||||
|         HOMEAXIS(X); |         HOMEAXIS(X); | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -922,7 +981,7 @@ void process_commands() | |||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); |       plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); | ||||||
| #endif // DELTA | #endif // else DELTA | ||||||
|            |            | ||||||
|       #ifdef ENDSTOPS_ONLY_FOR_HOMING |       #ifdef ENDSTOPS_ONLY_FOR_HOMING | ||||||
|         enable_endstops(false); |         enable_endstops(false); | ||||||
| @@ -2001,6 +2060,36 @@ void process_commands() | |||||||
|       if(tmp_extruder != active_extruder) { |       if(tmp_extruder != active_extruder) { | ||||||
|         // Save current position to return to after applying extruder offset |         // Save current position to return to after applying extruder offset | ||||||
|         memcpy(destination, current_position, sizeof(destination)); |         memcpy(destination, current_position, sizeof(destination)); | ||||||
|  |       #ifdef DUAL_X_CARRIAGE | ||||||
|  |         if (Stopped == false && delayed_move_time == 0 && current_position[X_AXIS] != x_home_pos(active_extruder)) | ||||||
|  |         { | ||||||
|  |           // Park old head: 1) raise 2) move to park position 3) lower | ||||||
|  |           plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT,  | ||||||
|  |                 current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); | ||||||
|  |           plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT,  | ||||||
|  |                 current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder); | ||||||
|  |           plan_buffer_line(x_home_pos(active_extruder), current_position[Y_AXIS], current_position[Z_AXIS],  | ||||||
|  |                 current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); | ||||||
|  |           st_synchronize(); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // only apply Y extruder offset in dual x carriage mode (x offset is already used in determining home pos) | ||||||
|  |         current_position[Y_AXIS] = current_position[Y_AXIS] - | ||||||
|  |                      extruder_offset[Y_AXIS][active_extruder] + | ||||||
|  |                      extruder_offset[Y_AXIS][tmp_extruder]; | ||||||
|  |                       | ||||||
|  |         active_extruder = tmp_extruder; | ||||||
|  |  | ||||||
|  |         // Inactive head always starts at its parked position. | ||||||
|  |         axis_is_at_home(X_AXIS); | ||||||
|  |  | ||||||
|  |         // record raised toolhead position for use by unpark | ||||||
|  |         memcpy(raised_parked_position, current_position, sizeof(raised_parked_position)); | ||||||
|  |         raised_parked_position[Z_AXIS] += TOOLCHANGE_UNPARK_ZLIFT; | ||||||
|  |          | ||||||
|  |         active_extruder_parked = true; | ||||||
|  |         delayed_move_time = 0; | ||||||
|  |       #else     | ||||||
|         // Offset extruder (only by XY) |         // Offset extruder (only by XY) | ||||||
|         int i; |         int i; | ||||||
|         for(i = 0; i < 2; i++) { |         for(i = 0; i < 2; i++) { | ||||||
| @@ -2010,6 +2099,7 @@ void process_commands() | |||||||
|         } |         } | ||||||
|         // Set the new active extruder and position |         // Set the new active extruder and position | ||||||
|         active_extruder = tmp_extruder; |         active_extruder = tmp_extruder; | ||||||
|  |       #endif //else DUAL_X_CARRIAGE | ||||||
|         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); |         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); | ||||||
|         // Move to the old position if 'F' was in the parameters |         // Move to the old position if 'F' was in the parameters | ||||||
|         if(make_move && Stopped == false) { |         if(make_move && Stopped == false) { | ||||||
| @@ -2204,6 +2294,40 @@ void prepare_move() | |||||||
|                      active_extruder); |                      active_extruder); | ||||||
|   } |   } | ||||||
| #else | #else | ||||||
|  |  | ||||||
|  | #if defined(DUAL_X_CARRIAGE) | ||||||
|  |   if (active_extruder_parked) | ||||||
|  |   { | ||||||
|  |     if (current_position[E_AXIS] == destination[E_AXIS]) | ||||||
|  |     { | ||||||
|  |       // this is a travel move | ||||||
|  | #ifdef TOOLCHANGE_UNPARK_SKIP_TRAVEL_MOVES | ||||||
|  |       if (delayed_move_time != 0xFFFFFFFFUL) | ||||||
|  |       { | ||||||
|  |         // skip this move but still update current_position in main so that it can  | ||||||
|  |         // be used as starting position before extrusion (but not in planner) | ||||||
|  |         memcpy(current_position, destination, sizeof(current_position));  | ||||||
|  |         if (destination[Z_AXIS] > raised_parked_position[Z_AXIS]) | ||||||
|  |           raised_parked_position[Z_AXIS] = destination[Z_AXIS]; | ||||||
|  |         delayed_move_time = millis(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       delayed_move_time = 0; | ||||||
|  | #else | ||||||
|  |       // this will cause the unpark code below to execute the specified lift in moving to the initial (travel move) position. | ||||||
|  |       memcpy(current_position, destination, sizeof(current_position));  | ||||||
|  | #endif       | ||||||
|  |     } | ||||||
|  |     // unpark extruder: 1) raise, 2) move into starting XY position, 3) lower | ||||||
|  |     plan_buffer_line(raised_parked_position[X_AXIS], raised_parked_position[Y_AXIS], raised_parked_position[Z_AXIS],    current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); | ||||||
|  |     plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], raised_parked_position[Z_AXIS],  | ||||||
|  |         current_position[E_AXIS], min(max_feedrate[X_AXIS],max_feedrate[Y_AXIS]), active_extruder); | ||||||
|  |     plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS],  | ||||||
|  |         current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder); | ||||||
|  |     active_extruder_parked = false; | ||||||
|  |   } | ||||||
|  | #endif //DUAL_X_CARRIAGE | ||||||
|  |  | ||||||
|   // Do not use feedmultiply for E or Z only moves |   // Do not use feedmultiply for E or Z only moves | ||||||
|   if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) { |   if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) { | ||||||
|       plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); |       plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); | ||||||
| @@ -2254,6 +2378,9 @@ void controllerFan() | |||||||
|        || !READ(E2_ENABLE_PIN) |        || !READ(E2_ENABLE_PIN) | ||||||
|     #endif |     #endif | ||||||
|     #if EXTRUDER > 1 |     #if EXTRUDER > 1 | ||||||
|  |       #if defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1 | ||||||
|  |        || !READ(X2_ENABLE_PIN) | ||||||
|  |       #endif | ||||||
|        || !READ(E1_ENABLE_PIN) |        || !READ(E1_ENABLE_PIN) | ||||||
|     #endif |     #endif | ||||||
|        || !READ(E0_ENABLE_PIN)) //If any of the drivers are enabled... |        || !READ(E0_ENABLE_PIN)) //If any of the drivers are enabled... | ||||||
| @@ -2320,6 +2447,16 @@ void manage_inactivity() | |||||||
|      WRITE(E0_ENABLE_PIN,oldstatus); |      WRITE(E0_ENABLE_PIN,oldstatus); | ||||||
|     } |     } | ||||||
|   #endif |   #endif | ||||||
|  |   #if defined(DUAL_X_CARRIAGE) && defined(TOOLCHANGE_UNPARK_SKIP_TRAVEL_MOVES) | ||||||
|  |     // handle delayed move timeout | ||||||
|  |     if (delayed_move_time != 0 && (millis() - delayed_move_time) > 1000) | ||||||
|  |     { | ||||||
|  |       // travel moves have been received so enact them | ||||||
|  |       delayed_move_time = 0xFFFFFFFFUL; // force moves to be done | ||||||
|  |       memcpy(destination,current_position,sizeof(destination)); | ||||||
|  |       prepare_move();  | ||||||
|  |     } | ||||||
|  |   #endif   | ||||||
|   check_axes_activity(); |   check_axes_activity(); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -348,11 +348,21 @@ ISR(TIMER1_COMPA_vect) | |||||||
|  |  | ||||||
|     // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY) |     // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY) | ||||||
|     if((out_bits & (1<<X_AXIS))!=0){ |     if((out_bits & (1<<X_AXIS))!=0){ | ||||||
|       WRITE(X_DIR_PIN, INVERT_X_DIR); |       #ifdef DUAL_X_CARRIAGE | ||||||
|  |       if (active_extruder != 0) | ||||||
|  |         WRITE(X2_DIR_PIN,INVERT_X_DIR); | ||||||
|  |       else | ||||||
|  |       #endif         | ||||||
|  |         WRITE(X_DIR_PIN, INVERT_X_DIR); | ||||||
|       count_direction[X_AXIS]=-1; |       count_direction[X_AXIS]=-1; | ||||||
|     } |     } | ||||||
|     else{ |     else{ | ||||||
|       WRITE(X_DIR_PIN, !INVERT_X_DIR); |       #ifdef DUAL_X_CARRIAGE | ||||||
|  |       if (active_extruder != 0) | ||||||
|  |         WRITE(X2_DIR_PIN,!INVERT_X_DIR); | ||||||
|  |       else | ||||||
|  |       #endif         | ||||||
|  |         WRITE(X_DIR_PIN, !INVERT_X_DIR); | ||||||
|       count_direction[X_AXIS]=1; |       count_direction[X_AXIS]=1; | ||||||
|     } |     } | ||||||
|     if((out_bits & (1<<Y_AXIS))!=0){ |     if((out_bits & (1<<Y_AXIS))!=0){ | ||||||
| @@ -372,29 +382,41 @@ ISR(TIMER1_COMPA_vect) | |||||||
|     #endif |     #endif | ||||||
|       CHECK_ENDSTOPS |       CHECK_ENDSTOPS | ||||||
|       { |       { | ||||||
|         #if defined(X_MIN_PIN) && X_MIN_PIN > -1 |         #ifdef DUAL_X_CARRIAGE | ||||||
|           bool x_min_endstop=(READ(X_MIN_PIN) != X_ENDSTOPS_INVERTING); |         // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder | ||||||
|           if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) { |         if ((active_extruder == 0 && X_HOME_DIR == -1) || (active_extruder != 0 && X2_HOME_DIR == -1)) | ||||||
|             endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; |  | ||||||
|             endstop_x_hit=true; |  | ||||||
|             step_events_completed = current_block->step_event_count; |  | ||||||
|           } |  | ||||||
|           old_x_min_endstop = x_min_endstop; |  | ||||||
|         #endif           |         #endif           | ||||||
|  |         { | ||||||
|  |           #if defined(X_MIN_PIN) && X_MIN_PIN > -1 | ||||||
|  |             bool x_min_endstop=(READ(X_MIN_PIN) != X_ENDSTOPS_INVERTING); | ||||||
|  |             if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) { | ||||||
|  |               endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; | ||||||
|  |               endstop_x_hit=true; | ||||||
|  |               step_events_completed = current_block->step_event_count; | ||||||
|  |             } | ||||||
|  |             old_x_min_endstop = x_min_endstop; | ||||||
|  |           #endif | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     else { // +direction |     else { // +direction | ||||||
|       CHECK_ENDSTOPS  |       CHECK_ENDSTOPS  | ||||||
|       { |       { | ||||||
|         #if defined(X_MAX_PIN) && X_MAX_PIN > -1 |         #ifdef DUAL_X_CARRIAGE | ||||||
|           bool x_max_endstop=(READ(X_MAX_PIN) != X_ENDSTOPS_INVERTING); |         // with 2 x-carriages, endstops are only checked in the homing direction for the active extruder | ||||||
|           if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){ |         if ((active_extruder == 0 && X_HOME_DIR == 1) || (active_extruder != 0 && X2_HOME_DIR == 1)) | ||||||
|             endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; |  | ||||||
|             endstop_x_hit=true; |  | ||||||
|             step_events_completed = current_block->step_event_count; |  | ||||||
|           } |  | ||||||
|           old_x_max_endstop = x_max_endstop; |  | ||||||
|         #endif           |         #endif           | ||||||
|  |         { | ||||||
|  |           #if defined(X_MAX_PIN) && X_MAX_PIN > -1 | ||||||
|  |             bool x_max_endstop=(READ(X_MAX_PIN) != X_ENDSTOPS_INVERTING); | ||||||
|  |             if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){ | ||||||
|  |               endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; | ||||||
|  |               endstop_x_hit=true; | ||||||
|  |               step_events_completed = current_block->step_event_count; | ||||||
|  |             } | ||||||
|  |             old_x_max_endstop = x_max_endstop; | ||||||
|  |           #endif | ||||||
|  |         }   | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -507,10 +529,20 @@ ISR(TIMER1_COMPA_vect) | |||||||
|  |  | ||||||
|         counter_x += current_block->steps_x; |         counter_x += current_block->steps_x; | ||||||
|         if (counter_x > 0) { |         if (counter_x > 0) { | ||||||
|           WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); |           #ifdef DUAL_X_CARRIAGE | ||||||
|  |           if (active_extruder != 0) | ||||||
|  |             WRITE(X2_STEP_PIN,!INVERT_X_STEP_PIN); | ||||||
|  |           else | ||||||
|  |           #endif         | ||||||
|  |             WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); | ||||||
|           counter_x -= current_block->step_event_count; |           counter_x -= current_block->step_event_count; | ||||||
|           count_position[X_AXIS]+=count_direction[X_AXIS];    |           count_position[X_AXIS]+=count_direction[X_AXIS];    | ||||||
|           WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); |           #ifdef DUAL_X_CARRIAGE | ||||||
|  |           if (active_extruder != 0) | ||||||
|  |             WRITE(X2_STEP_PIN,INVERT_X_STEP_PIN); | ||||||
|  |           else | ||||||
|  |           #endif         | ||||||
|  |             WRITE(X_STEP_PIN, INVERT_X_STEP_PIN); | ||||||
|         } |         } | ||||||
|    |    | ||||||
|         counter_y += current_block->steps_y; |         counter_y += current_block->steps_y; | ||||||
| @@ -685,6 +717,9 @@ void st_init() | |||||||
|   #if defined(X_DIR_PIN) && X_DIR_PIN > -1 |   #if defined(X_DIR_PIN) && X_DIR_PIN > -1 | ||||||
|     SET_OUTPUT(X_DIR_PIN); |     SET_OUTPUT(X_DIR_PIN); | ||||||
|   #endif |   #endif | ||||||
|  |   #if defined(X2_DIR_PIN) && X2_DIR_PIN > -1 | ||||||
|  |     SET_OUTPUT(X2_DIR_PIN); | ||||||
|  |   #endif | ||||||
|   #if defined(Y_DIR_PIN) && Y_DIR_PIN > -1  |   #if defined(Y_DIR_PIN) && Y_DIR_PIN > -1  | ||||||
|     SET_OUTPUT(Y_DIR_PIN); |     SET_OUTPUT(Y_DIR_PIN); | ||||||
|   #endif |   #endif | ||||||
| @@ -711,6 +746,10 @@ void st_init() | |||||||
|     SET_OUTPUT(X_ENABLE_PIN); |     SET_OUTPUT(X_ENABLE_PIN); | ||||||
|     if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); |     if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); | ||||||
|   #endif |   #endif | ||||||
|  |   #if defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1 | ||||||
|  |     SET_OUTPUT(X2_ENABLE_PIN); | ||||||
|  |     if(!X_ENABLE_ON) WRITE(X2_ENABLE_PIN,HIGH); | ||||||
|  |   #endif | ||||||
|   #if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1 |   #if defined(Y_ENABLE_PIN) && Y_ENABLE_PIN > -1 | ||||||
|     SET_OUTPUT(Y_ENABLE_PIN); |     SET_OUTPUT(Y_ENABLE_PIN); | ||||||
|     if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); |     if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH); | ||||||
| @@ -788,6 +827,11 @@ void st_init() | |||||||
|     WRITE(X_STEP_PIN,INVERT_X_STEP_PIN); |     WRITE(X_STEP_PIN,INVERT_X_STEP_PIN); | ||||||
|     disable_x(); |     disable_x(); | ||||||
|   #endif   |   #endif   | ||||||
|  |   #if defined(X2_STEP_PIN) && (X2_STEP_PIN > -1)  | ||||||
|  |     SET_OUTPUT(X2_STEP_PIN); | ||||||
|  |     WRITE(X2_STEP_PIN,INVERT_X_STEP_PIN); | ||||||
|  |     disable_x(); | ||||||
|  |   #endif   | ||||||
|   #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1)  |   #if defined(Y_STEP_PIN) && (Y_STEP_PIN > -1)  | ||||||
|     SET_OUTPUT(Y_STEP_PIN); |     SET_OUTPUT(Y_STEP_PIN); | ||||||
|     WRITE(Y_STEP_PIN,INVERT_Y_STEP_PIN); |     WRITE(Y_STEP_PIN,INVERT_Y_STEP_PIN); | ||||||
|   | |||||||
| @@ -41,6 +41,8 @@ Features: | |||||||
| *   Heater power reporting. Useful for PID monitoring. | *   Heater power reporting. Useful for PID monitoring. | ||||||
| *   PID tuning | *   PID tuning | ||||||
| *   CoreXY kinematics (www.corexy.com/theory.html) | *   CoreXY kinematics (www.corexy.com/theory.html) | ||||||
|  | *   Delta kinematics | ||||||
|  | *   Dual X-carriage support for multiple extruder systems | ||||||
| *   Configurable serial port to support connection of wireless adaptors. | *   Configurable serial port to support connection of wireless adaptors. | ||||||
| *   Automatic operation of extruder/cold-end cooling fans based on nozzle temperature | *   Automatic operation of extruder/cold-end cooling fans based on nozzle temperature | ||||||
| *   RC Servo Support, specify angle or duration for continuous rotation servos. | *   RC Servo Support, specify angle or duration for continuous rotation servos. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user