Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mixing Extruder Feature #3655

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ script:
- opt_enable EEPROM_SETTINGS EEPROM_CHITCHAT M100_FREE_MEMORY_WATCHER INCH_MODE_SUPPORT TEMPERATURE_UNITS_SUPPORT
- build_marlin
#
# Mixing Extruder
#
- restore_configs
- opt_enable MIXING_EXTRUDER
- opt_set MIXING_STEPPERS 2
- build_marlin
#
# Test DUAL_X_CARRIAGE
#
- restore_configs
Expand Down
22 changes: 18 additions & 4 deletions Marlin/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,20 +133,34 @@
// :[1,2,3,4]
#define EXTRUDERS 1

// For Cyclops or any "multi-extruder" that shares a single nozzle.
//#define SINGLENOZZLE

// Offset of the extruders (uncomment if using more than one and relying on firmware to position when changing).
// The offset has to be X=0, Y=0 for the extruder 0 hotend (default extruder).
// For the other hotends it is their distance from the extruder 0 hotend.
//#define HOTEND_OFFSET_X {0.0, 20.00} // (in mm) for each extruder, offset of the hotend on the X axis
//#define HOTEND_OFFSET_Y {0.0, 5.00} // (in mm) for each extruder, offset of the hotend on the Y axis

// For Cyclops or any "multi-extruder" that shares a single nozzle.
//#define SINGLENOZZLE

/**
* "Mixing Extruder"
* - Adds a new code, M165, to set the current mix factors.
* - Extends the stepping routines to move multiple steppers in proportion to the mix.
* - Optional support for Repetier Host M163, M164, and virtual extruder.
* - This implementation supports only a single extruder.
* - Enable DIRECT_MIXING_IN_G1 for Pia Taubert's reference implementation
*/
//#define MIXING_EXTRUDER
#ifdef MIXING_EXTRUDER
#define MIXING_STEPPERS 2 // Number of steppers in your mixing extruder
#define MIXING_VIRTUAL_TOOLS 16 // Use the Virtual Tool method with M163 and M164
//#define DIRECT_MIXING_IN_G1 // Allow ABCDHI mix factors in G1 movement commands
#endif

//// The following define selects which power supply you have. Please choose the one that matches your setup
// 1 = ATX
// 2 = X-Box 360 203Watts (the blue wire connected to PS_ON and the red wire to VCC)
// :{1:'ATX',2:'X-Box 360'}

#define POWER_SUPPLY 1

// Define this to have the electronics keep the power supply off on startup. If you don't know what this is leave it.
Expand Down
47 changes: 39 additions & 8 deletions Marlin/Marlin.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,38 +171,65 @@ void manage_inactivity(bool ignore_stepper_queue = false);
#define disable_z() ;
#endif


#if ENABLED(MIXING_EXTRUDER)

/**
* Mixing steppers synchronize their enable (and direction) together
*/
#if MIXING_STEPPERS > 3
#define enable_e0() { E0_ENABLE_WRITE( E_ENABLE_ON); E1_ENABLE_WRITE( E_ENABLE_ON); E2_ENABLE_WRITE( E_ENABLE_ON); E3_ENABLE_WRITE( E_ENABLE_ON); }
#define disable_e0() { E0_ENABLE_WRITE(!E_ENABLE_ON); E1_ENABLE_WRITE(!E_ENABLE_ON); E2_ENABLE_WRITE(!E_ENABLE_ON); E3_ENABLE_WRITE(!E_ENABLE_ON); }
#elif MIXING_STEPPERS > 2
#define enable_e0() { E0_ENABLE_WRITE( E_ENABLE_ON); E1_ENABLE_WRITE( E_ENABLE_ON); E2_ENABLE_WRITE( E_ENABLE_ON); }
#define disable_e0() { E0_ENABLE_WRITE(!E_ENABLE_ON); E1_ENABLE_WRITE(!E_ENABLE_ON); E2_ENABLE_WRITE(!E_ENABLE_ON); }
#else
#define enable_e0() { E0_ENABLE_WRITE( E_ENABLE_ON); E1_ENABLE_WRITE( E_ENABLE_ON); }
#define disable_e0() { E0_ENABLE_WRITE(!E_ENABLE_ON); E1_ENABLE_WRITE(!E_ENABLE_ON); }
#endif
#define enable_e1() NOOP
#define disable_e1() NOOP
#define enable_e2() NOOP
#define disable_e2() NOOP
#define enable_e3() NOOP
#define disable_e3() NOOP

#else // !MIXING_EXTRUDER

#if HAS_E0_ENABLE
#define enable_e0() E0_ENABLE_WRITE( E_ENABLE_ON)
#define disable_e0() E0_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define enable_e0() /* nothing */
#define disable_e0() /* nothing */
#define enable_e0() NOOP
#define disable_e0() NOOP
#endif

#if (EXTRUDERS > 1) && HAS_E1_ENABLE
#define enable_e1() E1_ENABLE_WRITE( E_ENABLE_ON)
#define disable_e1() E1_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define enable_e1() /* nothing */
#define disable_e1() /* nothing */
#define enable_e1() NOOP
#define disable_e1() NOOP
#endif

#if (EXTRUDERS > 2) && HAS_E2_ENABLE
#define enable_e2() E2_ENABLE_WRITE( E_ENABLE_ON)
#define disable_e2() E2_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define enable_e2() /* nothing */
#define disable_e2() /* nothing */
#define enable_e2() NOOP
#define disable_e2() NOOP
#endif

#if (EXTRUDERS > 3) && HAS_E3_ENABLE
#define enable_e3() E3_ENABLE_WRITE( E_ENABLE_ON)
#define disable_e3() E3_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define enable_e3() /* nothing */
#define disable_e3() /* nothing */
#define enable_e3() NOOP
#define disable_e3() NOOP
#endif

#endif // !MIXING_EXTRUDER

/**
* The axis order in all axis related arrays is X, Y, Z, E
*/
Expand Down Expand Up @@ -371,6 +398,10 @@ extern uint8_t active_extruder;
void print_heaterstates();
#endif

#if ENABLED(MIXING_EXTRUDER)
extern float mixing_factor[MIXING_STEPPERS];
#endif

void calculate_volumetric_multipliers();

// Buzzer
Expand Down
156 changes: 149 additions & 7 deletions Marlin/Marlin_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@
* M145 - Set the heatup state H<hotend> B<bed> F<fan speed> for S<material> (0=PLA, 1=ABS)
* M149 - Set temperature units
* M150 - Set BlinkM Color Output R: Red<0-255> U(!): Green<0-255> B: Blue<0-255> over i2c, G for green does not work.
* M163 - Set a single proportion for a mixing extruder. Requires MIXING_EXTRUDER.
* M164 - Save the mix as a virtual extruder. Requires MIXING_EXTRUDER and MIXING_VIRTUAL_TOOLS.
* M165 - Set the proportions for a mixing extruder. Use parameters ABCDHI to set the mixing factors. Requires MIXING_EXTRUDER.
* M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating
* Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling
* M200 - set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters).:D<millimeters>-
Expand Down Expand Up @@ -490,6 +493,13 @@ static uint8_t target_extruder;
static bool filament_ran_out = false;
#endif

#if ENABLED(MIXING_EXTRUDER)
float mixing_factor[MIXING_STEPPERS];
#if MIXING_VIRTUAL_TOOLS > 1
float mixing_virtual_tool_mix[MIXING_VIRTUAL_TOOLS][MIXING_STEPPERS];
#endif
#endif

static bool send_ok[BUFSIZE];

#if HAS_SERVOS
Expand Down Expand Up @@ -928,6 +938,15 @@ void setup() {
lcd_init();
#endif
#endif

#if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1
// Initialize mixing to 100% color 1
for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
mixing_factor[i] = (i == 0) ? 1 : 0;
for (uint8_t t = 0; t < MIXING_VIRTUAL_TOOLS; t++)
for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
mixing_virtual_tool_mix[t][i] = mixing_factor[i];
#endif
}

/**
Expand Down Expand Up @@ -2512,6 +2531,37 @@ static void homeaxis(AxisEnum axis) {

#endif // FWRETRACT

#if ENABLED(MIXING_EXTRUDER)

void normalize_mix() {
float mix_total = 0.0;
for (int i = 0; i < MIXING_STEPPERS; i++) {
float v = mixing_factor[i];
if (v < 0) v = mixing_factor[i] = 0;
mix_total += v;
}
// Scale all values if they don't add up to ~1.0
if (mix_total < 0.9999 || mix_total > 1.0001) {
SERIAL_PROTOCOLLNPGM("Warning: Mix factors must add up to 1.0. Scaling.");
float mix_scale = 1.0 / mix_total;
for (int i = 0; i < MIXING_STEPPERS; i++)
mixing_factor[i] *= mix_scale;
}
}

// Get mixing parameters from the GCode
// Factors that are left out are set to 0
// The total "must" be 1.0 (but it will be normalized)
void gcode_get_mix() {
const char* mixing_codes = "ABCDHI";
for (int i = 0; i < MIXING_STEPPERS; i++)
mixing_factor[i] = code_seen(mixing_codes[i]) ? code_value_float() : 0;

normalize_mix();
}

#endif

/**
* ***************************************************************************
* ***************************** G-CODE HANDLING *****************************
Expand All @@ -2536,6 +2586,10 @@ void gcode_get_destination() {
float next_feedrate = code_value_linear_units();
if (next_feedrate > 0.0) feedrate = next_feedrate;
}
// Get ABCDHI mixing factors
#if ENABLED(MIXING_EXTRUDER) && ENABLED(DIRECT_MIXING_IN_G1)
gcode_get_mix();
#endif
}

void unknown_command_error() {
Expand Down Expand Up @@ -4658,6 +4712,8 @@ inline void gcode_M109() {

KEEPALIVE_STATE(NOT_BUSY);

target_extruder = active_extruder; // for print_heaterstates

do {
// Target temperature might be changed during the loop
if (theTarget != thermalManager.degTargetBed()) {
Expand Down Expand Up @@ -6410,6 +6466,58 @@ inline void gcode_M907() {

#endif // HAS_MICROSTEPS

#if ENABLED(MIXING_EXTRUDER)

/**
* M163: Set a single mix factor for a mixing extruder
* This is called "weight" by some systems.
*
* S[index] The channel index to set
* P[float] The mix value
*
*/
inline void gcode_M163() {
int mix_index = code_seen('S') ? code_value_int() : 0;
float mix_value = code_seen('P') ? code_value_float() : 0.0;
if (mix_index < MIXING_STEPPERS) mixing_factor[mix_index] = mix_value;
}

#if MIXING_VIRTUAL_TOOLS > 1

/**
* M164: Store the current mix factors as a virtual tool.
*
* S[index] The virtual tool to store
*
*/
inline void gcode_M164() {
int tool_index = code_seen('S') ? code_value_int() : 0;
if (tool_index < MIXING_VIRTUAL_TOOLS) {
normalize_mix();
for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
mixing_virtual_tool_mix[tool_index][i] = mixing_factor[i];
}
}

#endif

/**
* M165: Set multiple mix factors for a mixing extruder.
* Factors that are left out will be set to 0.
* All factors together must add up to 1.0.
*
* A[factor] Mix factor for extruder stepper 1
* B[factor] Mix factor for extruder stepper 2
* C[factor] Mix factor for extruder stepper 3
* D[factor] Mix factor for extruder stepper 4
* H[factor] Mix factor for extruder stepper 5
* I[factor] Mix factor for extruder stepper 6
*
*/
inline void gcode_M165() { gcode_get_mix(); }

#endif // MIXING_EXTRUDER

/**
* M999: Restart after being stopped
*
Expand All @@ -6430,23 +6538,41 @@ inline void gcode_M999() {
FlushSerialRequestResend();
}

inline void invalid_extruder_error(const uint8_t &e) {
SERIAL_ECHO_START;
SERIAL_CHAR('T');
SERIAL_PROTOCOL_F(e, DEC);
SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
}

/**
* T0-T3: Switch tool, usually switching extruders
*
* F[mm/min] Set the movement feedrate
* S1 Don't move the tool in XY after change
*/
inline void gcode_T(uint8_t tmp_extruder) {
if (tmp_extruder >= EXTRUDERS) {
SERIAL_ECHO_START;
SERIAL_CHAR('T');
SERIAL_PROTOCOL_F(tmp_extruder, DEC);
SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);

#if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1

if (tmp_extruder >= MIXING_VIRTUAL_TOOLS) {
invalid_extruder_error(tmp_extruder);
return;
}

// T0-Tnnn: Switch virtual tool by changing the mix
for (uint8_t j = 0; j < MIXING_STEPPERS; j++)
mixing_factor[j] = mixing_virtual_tool_mix[tmp_extruder][j];

#else //!MIXING_EXTRUDER || MIXING_VIRTUAL_TOOLS <= 1

#if HOTENDS > 1

if (tmp_extruder >= EXTRUDERS) {
invalid_extruder_error(tmp_extruder);
return;
}

float stored_feedrate = feedrate;

if (code_seen('F')) {
Expand Down Expand Up @@ -6609,16 +6735,18 @@ inline void gcode_T(uint8_t tmp_extruder) {

feedrate = stored_feedrate;

#else // !HOTENDS > 1
#else // HOTENDS <= 1

// Set the new active extruder
active_extruder = tmp_extruder;

#endif
#endif // HOTENDS <= 1

SERIAL_ECHO_START;
SERIAL_ECHOPGM(MSG_ACTIVE_EXTRUDER);
SERIAL_PROTOCOLLN((int)active_extruder);

#endif //!MIXING_EXTRUDER || MIXING_VIRTUAL_TOOLS <= 1
}

/**
Expand Down Expand Up @@ -7012,6 +7140,20 @@ void process_next_command() {

#endif //EXPERIMENTAL_I2CBUS

#if ENABLED(MIXING_EXTRUDER)
case 163: // M163 S<int> P<float> set weight for a mixing extruder
gcode_M163();
break;
#if MIXING_VIRTUAL_TOOLS > 1
case 164: // M164 S<int> save current mix as a virtual extruder
gcode_M164();
break;
#endif
case 165: // M165 [ABCDHI]<float> set multiple mix weights
gcode_M165();
break;
#endif

case 200: // M200 D<millimeters> set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters).
gcode_M200();
break;
Expand Down
Loading