Added Prusa MultiMaterial Wipe Tower. Now it is time to integrate it

into the G-code generator.
This commit is contained in:
bubnikv 2017-05-10 15:54:59 +02:00
parent 2f57ee60d1
commit 146039f402
3 changed files with 980 additions and 0 deletions

View file

@ -430,6 +430,8 @@ src/libslic3r/TriangleMesh.cpp
src/libslic3r/TriangleMesh.hpp
src/libslic3r/utils.cpp
src/libslic3r/Utils.hpp
src/libslic3r/WipeTower.cpp
src/libslic3r/WipeTower.hpp
src/perlglue.cpp
src/poly2tri/common/shapes.cc
src/poly2tri/common/shapes.h

View file

@ -0,0 +1,809 @@
#include "WipeTower.hpp"
#include <assert.h>
#include <fstream>
#include <iostream>
#ifdef _MSC_VER
#define strcasecmp _stricmp
#endif
namespace PrusaSingleExtruderMM
{
static inline std::string line_XY(float x, float y)
{
char buf[128];
sprintf(buf, "G1 X%.3f Y%.3f\n", x, y);
return buf;
}
static inline std::string line_XYE(float x, float y, float e)
{
char buf[128];
sprintf(buf, "G1 X%.3f Y%.3f E%.4f\n", x, y, e);
return buf;
}
static inline std::string line_XYF(float x, float y, float f)
{
char buf[128];
sprintf(buf, "G1 X%.3f Y%.3f F%.0f\n", x, y, f);
return buf;
}
static inline std::string line_ZF(float z, float f)
{
char buf[128];
sprintf(buf, "G1 Z%.3f F%.0f\n", z, f);
return buf;
}
static inline std::string line_F(float f)
{
char buf[128];
sprintf(buf, "G1 F%.0f\n", f);
return buf;
}
static inline std::string line_XEF(float x, float e, float f)
{
char buf[128];
sprintf(buf, "G1 X%.3f E%.4f F%.0f\n", x, e, f);
return buf;
}
static inline std::string line_EF(float e, float f)
{
char buf[128];
sprintf(buf, "G1 E%.4f F%.0f\n", e, f);
return buf;
}
// Set extruder temperature, don't wait.
static inline std::string line_M104(int temperature)
{
char buf[128];
sprintf(buf, "M104 S%d\n", temperature);
return buf;
};
// Set extruder temperature and wait.
static inline std::string line_M109(int temperature)
{
char buf[128];
sprintf(buf, "M109 S%d\n", temperature);
buf;
};
// Set maximum feedrate
static inline std::string line_M203(int feedrate)
{
char buf[128];
sprintf(buf, "M203 E%d\n", feedrate);
return buf;
};
// Set speed factor override percentage
static inline std::string line_M220(int speed)
{
char buf[128];
sprintf(buf, "M220 S%d\n", speed);
return buf;
};
// Set digital trimpot motor
static inline std::string line_M907(int current)
{
char buf[128];
sprintf(buf, "M907 E%d\n", current);
return buf;
};
// Dwell for seconds. If delay == 0, this just flushes planner queue.
static inline std::string line_G4(int delay)
{
char buf[128];
sprintf(buf, "G4 S%d\n", delay);
return buf;
};
// Reset internal extruder counter.
static inline std::string line_ResetE()
{
return "G92 E0.0\n";
};
static inline std::string line_CommentValue(const char *comment, int value)
{
char strvalue[15];
sprintf(strvalue, "%d", value);
return std::string(";") + comment + strvalue + "\n";
};
static inline std::string line_CommentMaterial(WipeTower::material_type material)
{
std::string ret("; material : ");
switch (material)
{
case WipeTower::PVA:
ret += "#8 (PVA)";
break;
case WipeTower::SCAFF:
ret += "#5 (Scaffold)";
break;
case WipeTower::FLEX:
ret += "#4 (Flex)";
break;
default:
ret += "DEFAULT (PLA)";
break;
}
return ret + "\n";
};
static inline int randi(int lo, int hi)
{
int n = hi - lo + 1;
int i = rand() % n;
if (i < 0) i = -i;
return lo + i;
}
WipeTower::material_type WipeTower::parse_material(const char *name)
{
if (strcasecmp(name, "PLA") == 0)
return PLA;
if (strcasecmp(name, "ABS") == 0)
return ABS;
if (strcasecmp(name, "PET") == 0)
return PET;
if (strcasecmp(name, "HIPS") == 0)
return HIPS;
if (strcasecmp(name, "FLEX") == 0)
return FLEX;
if (strcasecmp(name, "SCAFF") == 0)
return SCAFF;
if (strcasecmp(name, "EDGE") == 0)
return EDGE;
if (strcasecmp(name, "NGEN") == 0)
return NGEN;
if (strcasecmp(name, "PVA") == 0)
return PVA;
return INVALID;
}
std::string WipeTower::FirstLayer(bool sideOnly, float offset)
{
float _ext = extrusion_flow + ((extrusion_flow / 100) * 10);
box_coordinates wipeTower_box(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_area * float(m_color_changes) - perimeterWidth / 2);
std::string gcode =
";-------------------------------------\n"
"; CP WIPE TOWER FIRST LAYER BRIM START\n";
gcode += line_ZF(m_z_pos + zHop, 7200);
gcode += line_F(6000);
gcode += line_XY( wipeTower_box.lu.x - (perimeterWidth * 10), wipeTower_box.lu.y );
gcode += line_ZF(m_z_pos, 7200);
gcode += line_F(2400);
gcode += line_XYE(wipeTower_box.ld.x - (perimeterWidth * 10), wipeTower_box.ld.y, retract);
float _offset = 0;
gcode += line_F(2100);
int _per = 0;
if (sideOnly)
{
do
{
_offset = _offset + perimeterWidth;
gcode += line_XY(wipeTower_box.ld.x - _offset, wipeTower_box.ld.y + offset);
gcode += line_XYE(wipeTower_box.lu.x - _offset, wipeTower_box.lu.y - offset, (wipeTower_box.lu.y - wipeTower_box.ld.y) * _ext);
_per++;
} while (_per < 4);
gcode += line_F(7000);
gcode += line_XY(wipeTower_box.rd.x + _offset, wipeTower_box.ld.y + offset);
gcode += line_F(2100);
_per = 0;
_offset = 0;
do
{
_offset = _offset + perimeterWidth;
gcode += line_XY(wipeTower_box.rd.x + _offset, wipeTower_box.ld.y + offset);
gcode += line_XYE(wipeTower_box.ru.x + _offset, wipeTower_box.lu.y - offset, (wipeTower_box.lu.y - wipeTower_box.ld.y) * _ext);
_per++;
} while (_per < 4);
}
else
{
do
{
_offset = _offset + perimeterWidth;
float _ext_X = ((wipeTower_box.rd.x + _offset) - (wipeTower_box.ld.x - _offset))* _ext;
float _ext_Y = ((wipeTower_box.lu.y + _offset) - (wipeTower_box.ld.y - _offset))* _ext;
float __x0 = wipeTower_box.ld.x - _offset + (perimeterWidth / 2);
float __y0 = wipeTower_box.ld.y - _offset + perimeterWidth;
gcode += line_XY(__x0, __y0);
float __x1 = wipeTower_box.lu.x - _offset + (perimeterWidth / 2);
float __y1 = wipeTower_box.lu.y + _offset;
gcode += line_XYE(__x1, __y1, _ext_Y);
float __x2 = wipeTower_box.ru.x + _offset - (perimeterWidth / 2);
float __y2 = wipeTower_box.ru.y + _offset;
gcode += line_XYE(__x2, __y2, _ext_X);
float __x3 = wipeTower_box.rd.x + _offset - (perimeterWidth / 2);
float __y3 = wipeTower_box.rd.y - _offset + perimeterWidth;
gcode += line_XYE(__x3, __y3, _ext_Y);
float __x4 = wipeTower_box.ld.x - _offset + (perimeterWidth / 2);
float __y4 = wipeTower_box.ld.y - _offset + perimeterWidth;
gcode += line_XYE(__x4, __y4, _ext_X);
_per++;
} while (_per < 4);
}
gcode += line_F(7000);
gcode += line_XY(wipeTower_box.ld.x, wipeTower_box.ld.y);
gcode += line_XY(wipeTower_box.rd.x, wipeTower_box.ld.y);
gcode += line_XY(wipeTower_box.ld.x, wipeTower_box.ld.y);
gcode += "; CP WIPE TOWER FIRST LAYER BRIM END\n";
gcode += ";-----------------------------------\n";
return gcode;
}
std::pair<std::string, WipeTower::xy> WipeTower::Toolchange(int tool, material_type current_material, material_type new_material, int temperature, wipe_shape shape, int count, float spaceAvailable, float wipeStartY, bool lastInFile, bool colorInit)
{
box_coordinates cleaning_box(
m_wipe_tower_pos.x,
m_wipe_tower_pos.y + wipeStartY, //(order * _wipe_area); //wipeStartY;
m_wipe_tower_width,
spaceAvailable - perimeterWidth / 2); //space_available //wipe_area
std::string gcode;
gcode += ";--------------------\n";
gcode += "; CP TOOLCHANGE START\n";
gcode += line_CommentValue(" toolchange #", count);
gcode += line_CommentMaterial(current_material);
gcode += ";--------------------\n";
gcode += line_M220(100);
gcode += line_ZF(m_z_pos + zHop, 7200);
gcode += line_EF((retract/2)*-1, 3600); // additional retract on move to tower
gcode += line_XYF(cleaning_box.ld.x + perimeterWidth, cleaning_box.ld.y + shape * perimeterWidth, 7200);
gcode += line_ZF(m_z_pos, 7200);
gcode += line_EF((retract / 2), 3600); // additional retract on move to tower
gcode += line_EF((retract), 1500);
m_y_position = (shape == NORMAL) ? cleaning_box.ld.y : cleaning_box.lu.y;
gcode += line_M907(750);
gcode += line_G4(0);
gcode += toolchange_Unload(cleaning_box, current_material, shape, temperature);
if (!lastInFile)
{
gcode += toolchange_Change(tool, current_material, new_material);
gcode += toolchange_Load(cleaning_box, current_material, shape, colorInit);
gcode += toolchange_Wipe(cleaning_box, current_material, shape);
gcode += toolchange_Done(cleaning_box, current_material, shape);
}
gcode += line_M907(550);
gcode += line_G4(0);
gcode += line_ResetE();
gcode += "; CP TOOLCHANGE END\n"
";------------------\n"
"\n\n";
return std::pair<std::string, xy>(gcode, (shape == NORMAL) ? cleaning_box.lu : cleaning_box.ld);
}
std::string WipeTower::toolchange_Unload(const box_coordinates &cleaning_box, material_type material, wipe_shape shape, int temperature)
{
float __xl = 0;
float __xr = 0;
__xl = cleaning_box.ld.x + (perimeterWidth / 2);
__xr = cleaning_box.rd.x - (perimeterWidth / 2);
std::string gcode = "; CP TOOLCHANGE UNLOAD";
switch (material)
{
case PVA:
gcode += line_F(4000);
m_y_position += shape * perimeterWidth * 1.2f;
gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, 0);
gcode += line_XYE(__xr - perimeterWidth, m_y_position, 3);
gcode += line_F(4500);
m_y_position += shape * perimeterWidth * 1.5f;
gcode += line_XYE(__xr - perimeterWidth, m_y_position, 0);
gcode += line_XYE(__xl + perimeterWidth, m_y_position, 3);
gcode += line_F(4800);
m_y_position += shape * perimeterWidth * 1.5f;
gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, 0);
gcode += line_XYE(__xr - (perimeterWidth * 2), m_y_position, 3);
gcode += line_F(5000);
m_y_position += shape * perimeterWidth * 1.5f;
gcode += line_XYE(__xr - perimeterWidth, m_y_position, 0);
gcode += line_XYE(__xl + perimeterWidth, m_y_position, 3);
gcode += line_EF(-15, 5000);
gcode += line_EF(-50, 5400);
gcode += line_EF(-15, 3000);
gcode += line_EF(-12, 2000);
if (temperature != 0)
{
gcode += line_M104(temperature);
}
// cooling moves
m_y_position += shape * perimeterWidth * 0.8f;
gcode += line_F(1600);
gcode += line_XYE(__xl, m_y_position, 3);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2000);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2200);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2400);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2400);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2400);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -3);
gcode += line_G4(0);
break; // end of SCAFF
case SCAFF:
gcode += line_F(4000);
m_y_position += shape * perimeterWidth * 3.f;
gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, 0);
gcode += line_XYE(__xr - perimeterWidth, m_y_position, 3);
gcode += line_F(4600);
m_y_position += shape * perimeterWidth * 3.f;
gcode += line_XYE(__xr - perimeterWidth, m_y_position, 0);
gcode += line_XYE(__xl + perimeterWidth, m_y_position, 4);
gcode += line_F(5200);
m_y_position += shape * perimeterWidth * 3.f;
gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, 0);
gcode += line_XYE(__xr - (perimeterWidth * 2), m_y_position, 4.5);
gcode += line_EF(-15, 5000);
gcode += line_EF(-50, 5400);
gcode += line_EF(-15, 3000);
gcode += line_EF(-12, 2000);
if (temperature != 0)
{
gcode += line_M104(temperature);
}
// cooling moves
m_y_position += shape * perimeterWidth * 0.8f;
gcode += line_F(1600);
gcode += line_XYE(__xl, m_y_position, 3);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2000);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2200);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2200);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2400);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -3);
gcode += line_G4(0);
break; // end of SCAFF
default:
gcode += line_F(4000);
m_y_position += shape * perimeterWidth * 1.2f;
gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, 0);
gcode += line_XYE(__xr - perimeterWidth, m_y_position, (__xr - __xl) * (extrusion_flow*(float)1.6));
gcode += line_F(4600);
m_y_position += shape * perimeterWidth * 1.2f;
gcode += line_XYE(__xr - perimeterWidth, m_y_position, perimeterWidth*extrusion_flow);
gcode += line_XYE(__xl + perimeterWidth, m_y_position, (__xr - __xl) * (extrusion_flow*(float)1.65));
gcode += line_F(5200);
m_y_position += shape * perimeterWidth * 1.2f; //1.4f
gcode += line_XYE(__xl + (perimeterWidth * 2), m_y_position, perimeterWidth*extrusion_flow);
gcode += line_XYE(__xr - (perimeterWidth * 2), m_y_position, (__xr - __xl) * (extrusion_flow*(float)1.74));
gcode += line_EF(-15, 5000);
gcode += line_EF(-50, 5400);
gcode += line_EF(-15, 3000);
gcode += line_EF(-12, 2000);
if (temperature != 0)
{
gcode += line_M104(temperature);
}
// cooling moves
m_y_position += shape * perimeterWidth * 0.8f;
gcode += line_F(1600);
gcode += line_XYE(__xl, m_y_position, 3);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2000);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2400);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -5);
gcode += line_F(2400);
gcode += line_XYE(__xl, m_y_position, 5);
gcode += line_XYE(__xr, m_y_position, -3);
gcode += line_G4(0);
break; // end of default material
}
return gcode;
}
std::string WipeTower::toolchange_Load(const box_coordinates &cleaning_box, material_type material, wipe_shape shape, bool colorInit)
{
float __xl = 0;
float __xr = 0;
std::string gcode = "; CP TOOLCHANGE LOAD\n";
switch (material)
{
default:
__xl = cleaning_box.ld.x + (perimeterWidth * 1);
__xr = cleaning_box.rd.x - (perimeterWidth * 1);
float _extrusion = (__xr - __xl) * extrusion_flow;
gcode += line_XEF(__xr, 20, 1400);
gcode += line_XEF(__xl, 40, 3000);
gcode += line_XEF(__xr, 20, 1600);
gcode += line_XEF(__xl, 10, 1000);
gcode += line_F(1600);
gcode += line_XYE(__xr, m_y_position, _extrusion);
gcode += line_F(2200);
int _pass = 2;
if (colorInit) _pass = 1;
for (int _i = 0; _i < _pass; _i++)
{
m_y_position += shape * perimeterWidth * 0.85f;
gcode += line_XY(__xr, m_y_position);
gcode += line_XYE(__xl, m_y_position, _extrusion);
m_y_position += shape * perimeterWidth * 0.85f;
gcode += line_XY(__xl, m_y_position);
gcode += line_XYE(__xr, m_y_position, _extrusion);
}
break;
}
gcode += line_M907(550);
return gcode;
}
std::string WipeTower::toolchange_Wipe(const box_coordinates &cleaning_box, material_type material, wipe_shape shape)
{
// wipe new filament until end of wipe area
float __xl = 0;
float __xr = 0;
int __p = 0;
float _wipespeed = 4200;
float _extr = extrusion_flow;
float _wipekoef = 1;
std::string gcode = "; CP TOOLCHANGE WIPE\n";
// increase flow on first layer, slow down print
if (int(m_z_pos * 100) < 21)
{
_extr = extrusion_flow + ((extrusion_flow / 100) * 18);
_wipekoef = (float)0.5;
}
else
{
_extr = extrusion_flow;
_wipekoef = (float)1;
}
switch (material)
{
default:
__xl = cleaning_box.ld.x + (perimeterWidth*2);
__xr = cleaning_box.rd.x - (perimeterWidth*2);
switch (shape)
{
case NORMAL:
do
{
__p++;
_wipespeed = _wipespeed + 50;
if (_wipespeed > 4800) { _wipespeed = 4800; }
gcode += line_F(_wipespeed * _wipekoef);
m_y_position += shape * perimeterWidth * 0.7f;
if (__p < 2)
{
gcode += line_XYE(__xl - (perimeterWidth/2), m_y_position, perimeterWidth * _extr);
gcode += line_XYE(__xr + (perimeterWidth), m_y_position, (__xr - __xl) * _extr);
}
else
{
gcode += line_XYE(__xl-(perimeterWidth), m_y_position, perimeterWidth * _extr);
gcode += line_XYE(__xr+(perimeterWidth*2), m_y_position, (__xr - __xl) * _extr);
__p = 0;
}
_wipespeed = _wipespeed + 50;
if (_wipespeed > 4800) { _wipespeed = 4800; }
gcode += line_F(_wipespeed * _wipekoef);
m_y_position += shape * perimeterWidth * 0.7f;
gcode += line_XYE(__xr + (perimeterWidth), m_y_position, perimeterWidth * _extr);
gcode += line_XYE(__xl - (perimeterWidth), m_y_position, (__xr - __xl) * _extr);
} while (m_y_position <= cleaning_box.lu.y - (perimeterWidth*1));
break;
case REVERSED:
do
{
__p++;
_wipespeed = _wipespeed + 50;
if (_wipespeed > 4900) { _wipespeed = 4900; }
gcode += line_F(_wipespeed * _wipekoef);
m_y_position += shape * perimeterWidth * 0.7f;
if (__p < 2)
{
gcode += line_XYE(__xl - (perimeterWidth/2), m_y_position, perimeterWidth * _extr);
gcode += line_XYE(__xr + (perimeterWidth), m_y_position, (__xr - __xl) * _extr);
}
else
{
gcode += line_XYE(__xl - (perimeterWidth), m_y_position, perimeterWidth * _extr);
gcode += line_XYE(__xr + (perimeterWidth *2), m_y_position, (__xr - __xl) * _extr);
__p = 0;
}
_wipespeed = _wipespeed + 50;
if (_wipespeed > 4900) { _wipespeed = 4900; }
gcode += line_F(_wipespeed * _wipekoef);
m_y_position += shape * perimeterWidth * 0.7f;
gcode += line_XYE(__xr + (perimeterWidth), m_y_position, perimeterWidth * _extr);
gcode += line_XYE(__xl - (perimeterWidth), m_y_position, (__xr - __xl) * _extr);
} while (m_y_position >= cleaning_box.ld.y + (perimeterWidth*1 ));
break;
}
break;
}
return gcode;
}
std::string WipeTower::toolchange_Done(const box_coordinates &cleaning_box, material_type /* material */, wipe_shape shape)
{
std::string gcode;
switch (shape)
{
case NORMAL:
gcode += line_F(7000);
gcode += line_XY(cleaning_box.lu.x, cleaning_box.lu.y);
gcode += line_F(3200);
gcode += line_XYE(cleaning_box.ld.x, cleaning_box.ld.y, (cleaning_box.lu.y - cleaning_box.ld.y)*(extrusion_flow ));
gcode += line_XYE(cleaning_box.rd.x, cleaning_box.rd.y, (cleaning_box.rd.x - cleaning_box.ld.x)*(extrusion_flow ));
gcode += line_XYE(cleaning_box.ru.x, cleaning_box.lu.y, (cleaning_box.lu.y - cleaning_box.ld.y)*(extrusion_flow ));
gcode += line_XYE(cleaning_box.lu.x, cleaning_box.lu.y, (cleaning_box.rd.x - cleaning_box.ld.x)*(extrusion_flow ));
gcode += line_F(7200);
gcode += line_XY(cleaning_box.ru.x, cleaning_box.lu.y);
gcode += line_XY(cleaning_box.lu.x, cleaning_box.lu.y);
gcode += line_F(6000);
break;
case REVERSED:
gcode += line_F(7000);
gcode += line_XY(cleaning_box.ld.x , cleaning_box.ld.y );
gcode += line_F(3200);
gcode += line_XYE(cleaning_box.rd.x , cleaning_box.rd.y, (cleaning_box.rd.x - cleaning_box.ld.x)*(extrusion_flow ));
gcode += line_XYE(cleaning_box.ru.x , cleaning_box.ru.y, (cleaning_box.ru.y - cleaning_box.rd.y)*(extrusion_flow ));
gcode += line_XYE(cleaning_box.lu.x , cleaning_box.lu.y, (cleaning_box.ru.x - cleaning_box.lu.x)*(extrusion_flow ));
gcode += line_XYE(cleaning_box.ld.x, cleaning_box.ld.y, (cleaning_box.lu.y - cleaning_box.ld.y)*(extrusion_flow ));
gcode += line_F(7200);
gcode += line_XY(cleaning_box.rd.x, cleaning_box.ld.y);
gcode += line_XY(cleaning_box.ld.x, cleaning_box.ld.y);
gcode += line_F(6000);
break;
}
return gcode;
}
std::string WipeTower::toolchange_Change(int tool, material_type /* current_material */, material_type new_material)
{
assert(tool >= 0 && tool < 4);
std::string gcode("T0\n");
gcode[1] += char(tool);
switch (new_material)
{
case PVA:
gcode += line_M220(80);
gcode += line_G4(0);
break;
case SCAFF:
gcode += line_M220(35);
gcode += line_G4(0);
break;
case FLEX:
gcode += line_M220(35);
gcode += line_G4(0);
break;
default:
gcode += line_M220(100);
gcode += line_G4(0);
break;
}
return gcode;
}
std::string WipeTower::Perimeter(int order, int total, int Layer, bool afterToolchange, int firstLayerOffset)
{
float _speed = 1.f;
std::string gcode =
";--------------------\n"
"; CP EMPTY GRID START\n";
gcode += line_CommentValue(" layer #", Layer);
if (Layer == 20)
_speed = 2.f;
box_coordinates _p = _boxForColor(order);
box_coordinates _to = _boxForColor(total);
_p.ld.y += firstLayerOffset;
_p.rd.y += firstLayerOffset;
_p.lu = _to.lu; _p.ru = _to.ru;
if (!afterToolchange)
{
gcode += line_EF(retract*(float)-1.5, 3600);
gcode += line_ZF(m_z_pos + zHop, 7200);
gcode += line_XYF(_p.ld.x + randi(5, 20), _p.ld.y, 7000);
gcode += line_ZF(m_z_pos, 7200);
gcode += line_XEF(_p.ld.x, retract*(float)1.5, 3600);
}
gcode += line_F(2400 / _speed);
gcode += line_XYE(_p.lu.x, _p.ru.y, (_p.ru.y - _p.ld.y) * extrusion_flow);
gcode += line_XYE(_p.ru.x, _p.ru.y, (_p.ru.x - _p.lu.x) * extrusion_flow);
gcode += line_XYE(_p.rd.x, _p.rd.y, (_p.ru.y - _p.ld.y) * extrusion_flow);
gcode += line_XYE(_p.ld.x + (perimeterWidth / 2), _p.ld.y, (_p.ru.x - _p.lu.x) * extrusion_flow);
gcode += line_F(3200 / _speed);
gcode += line_XYE(_p.lu.x + (perimeterWidth / 2), _p.lu.y - (perimeterWidth / 2), (_p.ru.y - _p.ld.y) * extrusion_flow);
gcode += line_XYE(_p.ru.x - (perimeterWidth / 2), _p.ru.y - (perimeterWidth / 2), (_p.ru.x - _p.lu.x) * extrusion_flow);
gcode += line_XYE(_p.rd.x - (perimeterWidth / 2), _p.rd.y + (perimeterWidth / 2), (_p.ru.y - _p.ld.y) * extrusion_flow);
gcode += line_XYE(_p.ld.x + perimeterWidth, _p.ld.y + (perimeterWidth / 2), (_p.ru.x - _p.lu.x) * extrusion_flow);
gcode += line_XYE(_p.ld.x + perimeterWidth, _p.ld.y + perimeterWidth, perimeterWidth * extrusion_flow);
gcode += line_F(2900 / _speed);
gcode += line_XYE(_p.ld.x + (perimeterWidth * 3), _p.ld.y + perimeterWidth, (perimeterWidth * 3) * extrusion_flow);
gcode += line_XYE(_p.lu.x + (perimeterWidth * 3), _p.lu.y - perimeterWidth, (_p.ru.y - _p.ld.y) * extrusion_flow);
gcode += line_XYE(_p.lu.x + (perimeterWidth * 6), _p.lu.y - perimeterWidth, (perimeterWidth * 3) * extrusion_flow);
gcode += line_XYE(_p.ld.x + (perimeterWidth * 6), _p.ld.y + perimeterWidth, (_p.ru.y - _p.ld.y) * extrusion_flow);
if (_p.lu.y - _p.ld.y > 4)
{
gcode += line_F(3200 / _speed);
float _step = (m_wipe_tower_width - (perimeterWidth * 12)) / 3;
float _sx = 0;
for (int _s = 0; _s < 3; _s++)
{
float _ext = ((_p.ru.y - _p.ld.y) / 3)*(extrusion_flow*(float)1.5);
_sx = _sx + (_step / 2);
gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + (_step / 4) + (_step * _s), _p.ld.y + (perimeterWidth * 8), _ext);
gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + (_step / 4) + (_step * _s), _p.lu.y - (perimeterWidth * 8), _ext);
gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + ((_step / 4) * 2) + (_step * _s), _p.lu.y - perimeterWidth, _ext);
gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + ((_step / 4) * 3) + (_step * _s), _p.lu.y - (perimeterWidth * 8), _ext);
gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + ((_step / 4) * 3) + (_step * _s), _p.ld.y + (perimeterWidth * 8), _ext);
gcode += line_XYE(_p.ld.x + (perimeterWidth * 6) + (_step)+(_step * _s), _p.ld.y + perimeterWidth, _ext);
}
}
gcode += line_F(2900 / _speed);
gcode += line_XYE(_p.ru.x - (perimeterWidth * 6), _p.ru.y - perimeterWidth, (_p.ru.y - _p.ld.y) * extrusion_flow);
gcode += line_XYE(_p.ru.x - (perimeterWidth * 3), _p.ru.y - perimeterWidth, (perimeterWidth * 3) * extrusion_flow);
gcode += line_XYE(_p.rd.x - (perimeterWidth * 3), _p.rd.y + perimeterWidth, (_p.ru.y - _p.ld.y) * extrusion_flow);
gcode += line_XYE(_p.rd.x - perimeterWidth, _p.rd.y + perimeterWidth, perimeterWidth * extrusion_flow);
gcode += line_F(7200);
gcode += line_XY(_p.ld.x + perimeterWidth, _p.rd.y + (perimeterWidth / 2));
gcode += line_XY(_p.rd.x - perimeterWidth, _p.ld.y + (perimeterWidth / 2));
gcode += "; CP EMPTY GRID END\n"
";------------------\n\n\n\n\n\n\n";
return gcode;
}
WipeTower::box_coordinates WipeTower::_boxForColor(int order) const
{
return box_coordinates(m_wipe_tower_pos.x, m_wipe_tower_pos.y + m_wipe_area * order - perimeterWidth / 2, m_wipe_tower_width, perimeterWidth);
}
}; // namespace PrusaSingleExtruderMM

View file

@ -0,0 +1,169 @@
#ifndef PrusaSingleExtruderMM_WipeTower_hpp_
#define PrusaSingleExtruderMM_WipeTower_hpp_
#include <algorithm>
#include <string>
#include <utility>
namespace PrusaSingleExtruderMM
{
class WipeTower
{
public:
enum material_type
{
INVALID = -1,
PLA = 0, // E:210C B:55C
ABS = 1, // E:255C B:100C
PET = 2, // E:240C B:90C
HIPS = 3, // E:220C B:100C
FLEX = 4, // E:245C B:80C
SCAFF = 5, // E:215C B:55C
EDGE = 6, // E:240C B:80C
NGEN = 7, // E:230C B:80C
PVA = 8 // E:210C B:80C
};
enum wipe_shape
{
NORMAL = 1,
REVERSED = -1
};
struct xy
{
xy(float x = 0.f, float y = 0.f) : x(x), y(y) {}
float x;
float y;
};
// Parse material name into material_type.
static material_type parse_material(const char *name);
// x -- x coordinates of wipe tower in mm ( left bottom corner )
// y -- y coordinates of wipe tower in mm ( left bottom corner )
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
// wipe_area -- space available for one toolchange in mm
// colors -- maximum colors for object
WipeTower(float x, float y, float width, float wipe_area, int color_changes) :
m_wipe_tower_pos(x, y),
m_wipe_tower_width(width),
m_wipe_area(wipe_area),
m_color_changes(color_changes),
m_z_pos(0.f) {}
// colors -- maximum color changes for layer
void setColors(int colors) { m_color_changes = colors; }
// Z height -- mm
void setZ(float z) { m_z_pos = z; }
// _retract - retract value in mm
void setRetract(float _retract) { retract = _retract; }
// _zHop - z hop value in mm
void setZHop(float _zhop) { zHop = _zhop; }
void setExtrusion(int layerHeight)
{
// set extrusion coefficient for layer height
// layerHeight -- mm * 100
switch (layerHeight)
{
case 15:
extrusion_flow = (float)0.024;
break;
case 20:
extrusion_flow = (float)0.029;
break;
default:
break;
}
}
/*
Returns gcode for wipe tower brim
sideOnly -- set to false -- experimental, draw brim on sides of wipe tower
offset -- set to 0 -- experimental, offset to replace brim in front / rear of wipe tower
*/
std::string FirstLayer(bool sideOnly, float offset);
/*
Returns gcode for toolchange
tool -- extruder # 0 - 3
current_material -- filament type currently used to print and loaded in nozzle -- see enum material_type
new_material -- filament type that will be loaded in to the nozzle -- see enum material_type
temperature -- temperature in Celsius for new filament that will be loaded into the nozzle
shape -- orientation of purge / wipe shape -- 0 = normal, 1 = reversed -- enum wipe_shape
count -- total toolchanges done counter ( comment in header of toolchange only )
spaceAvailable -- space available for toolchange ( purge / load / wipe ) - in mm
wipeStartY -- experimental, don't use, set to 0
lastInFile -- for last toolchange in object set to true to unload filament into cooling tube, for all other set to false
colorInit -- experimental, set to 0
*/
std::pair<std::string, WipeTower::xy> Toolchange(
int tool, material_type current_material, material_type new_material, int temperature, wipe_shape shape,
int count, float spaceAvailable, float wipeStartY, bool lastInFile, bool colorInit);
/*
Returns gcode to draw empty pattern in place of a toolchange -> in case there are less toolchanges atm then what is required later
order -- total toolchanges done for current layer
total -- total colors in current z layer including empty ones
layer -- Z height in mm * 100 ( slows down print for first layer )
afterToolchange -- true - ignore some not neccesary moves | false - do whole move from object to wipe tower
firstLayerOffset -- experimental , set to 0
*/
std::string Perimeter(int order, int total, int layer, bool afterToolchange, int firstLayerOffset);
private:
WipeTower();
// Left front corner of the wipe tower in mm.
xy m_wipe_tower_pos;
// Width of the wipe tower.
float m_wipe_tower_width;
// Per color Y span.
float m_wipe_area;
// Current Z position.
float m_z_pos;
// Maximum number of color changes per layer.
int m_color_changes;
// Current y position at the wipe tower.
float m_y_position;
float zHop = 0.5f;
float retract = 4.f;
float perimeterWidth = 0.5f;
float extrusion_flow = 0.029f;
struct box_coordinates
{
box_coordinates(float left, float bottom, float width, float height) :
ld(left , bottom ),
lu(left , bottom + height),
rd(left + width, bottom ),
ru(left + width, bottom + height) {}
box_coordinates(const xy &pos, float width, float height) : box_coordinates(pos.x, pos.y, width, height) {}
xy ld; // left down
xy lu; // left upper
xy ru; // right upper
xy rd; // right lower
};
std::string toolchange_Unload(const box_coordinates &cleaning_box, material_type material, wipe_shape shape, int temperature);
std::string toolchange_Change(int tool, material_type current_material, material_type new_material);
std::string toolchange_Load(const box_coordinates &cleaning_box, material_type material, wipe_shape shape, bool colorInit);
std::string toolchange_Wipe(const box_coordinates &cleaning_box, material_type material, wipe_shape shape);
std::string toolchange_Done(const box_coordinates &cleaning_box, material_type material, wipe_shape shape);
box_coordinates _boxForColor(int order) const;
};
}; // namespace PrusaSingleExtruderMM
#endif /* PrusaSingleExtruderMM_WipeTower_hpp_ */