void GCodeExport::switchExtruder(int new_extruder, const RetractionConfig& retraction_config_old_extruder) { if (current_extruder == new_extruder) return; bool force = true; bool extruder_switch = true; writeRetraction(&const_cast<RetractionConfig&>(retraction_config_old_extruder), force, extruder_switch); resetExtrusionValue(); // zero the E value on the old extruder, so that the current_e_value is registered on the old extruder int old_extruder = current_extruder; writeCode(extruder_attr[old_extruder].end_code.c_str()); startExtruder(new_extruder); }
void GCodePlanner::writeRetraction(unsigned int path_idx_travel_after) { if (makeRetractSwitchRetract(path_idx_travel_after)) { gcode.writeRetraction_extruderSwitch(); } else { RetractionConfig* extrusion_retraction_config = nullptr; for(int extrusion_path_idx = int(path_idx_travel_after) - 1; extrusion_path_idx >= 0; extrusion_path_idx--) { // backtrack to find the last extrusion path if (paths[extrusion_path_idx].config != &travelConfig) { extrusion_retraction_config = paths[extrusion_path_idx].config->retraction_config; break; } } writeRetraction(false, extrusion_retraction_config); } }
void GCodeExport::finalize(int maxObjectHeight, int moveSpeed, const char* endCode) { writeFanCommand(0); writeRetraction(); setZ(maxObjectHeight + 5000); writeMove(getPositionXY(), moveSpeed, 0); writeCode(endCode); log("Print time: %d\n", int(getTotalPrintTime())); log("Filament: %d\n", int(getTotalFilamentUsed(0))); log("Filament2: %d\n", int(getTotalFilamentUsed(1))); if (getFlavor() == GCODE_FLAVOR_ULTIGCODE) { char numberString[16]; sprintf(numberString, "%d", int(getTotalPrintTime())); replaceTagInStart("<__TIME__>", numberString); sprintf(numberString, "%d", int(getTotalFilamentUsed(0))); replaceTagInStart("<FILAMENT>", numberString); sprintf(numberString, "%d", int(getTotalFilamentUsed(1))); replaceTagInStart("<FILAMEN2>", numberString); } }
bool GCodePlanner::writePathWithCoasting(GCodePath& path, GCodePath& path_next, int64_t layerThickness, double coasting_volume, double coasting_speed, double coasting_min_volume, bool extruder_switch_retract) { int64_t coasting_min_dist_considered = 100; // hardcoded setting for when to not perform coasting double extrude_speed = path.config->getSpeed() * getExtrudeSpeedFactor(); // travel speed int64_t coasting_dist = MM2INT(MM2_2INT(coasting_volume) / layerThickness) / path.config->getLineWidth(); // closing brackets of MM2INT at weird places for precision issues int64_t coasting_min_dist = MM2INT(MM2_2INT(coasting_min_volume) / layerThickness) / path.config->getLineWidth(); // closing brackets of MM2INT at weird places for precision issues std::vector<int64_t> accumulated_dist_per_point; // the first accumulated dist is that of the last point! (that of the last point is always zero...) accumulated_dist_per_point.push_back(0); int64_t accumulated_dist = 0; bool length_is_less_than_min_dist = true; unsigned int acc_dist_idx_gt_coast_dist = NO_INDEX; // the index of the first point with accumulated_dist more than coasting_dist (= index into accumulated_dist_per_point) // == the point printed BEFORE the start point for coasting Point* last = &path.points[path.points.size() - 1]; for (unsigned int backward_point_idx = 1; backward_point_idx < path.points.size(); backward_point_idx++) { Point& point = path.points[path.points.size() - 1 - backward_point_idx]; int64_t dist = vSize(point - *last); accumulated_dist += dist; accumulated_dist_per_point.push_back(accumulated_dist); if (acc_dist_idx_gt_coast_dist == NO_INDEX && accumulated_dist >= coasting_dist) { acc_dist_idx_gt_coast_dist = backward_point_idx; // the newly added point } if (accumulated_dist >= coasting_min_dist) { length_is_less_than_min_dist = false; break; } last = &point; } if (accumulated_dist < coasting_min_dist_considered) { return false; } int64_t actual_coasting_dist = coasting_dist; if (length_is_less_than_min_dist) { // in this case accumulated_dist is the length of the whole path actual_coasting_dist = accumulated_dist * coasting_dist / coasting_min_dist; for (acc_dist_idx_gt_coast_dist = 0 ; acc_dist_idx_gt_coast_dist < accumulated_dist_per_point.size() ; acc_dist_idx_gt_coast_dist++) { // search for the correct coast_dist_idx if (accumulated_dist_per_point[acc_dist_idx_gt_coast_dist] > actual_coasting_dist) { break; } } } if (acc_dist_idx_gt_coast_dist == NO_INDEX) { // something has gone wrong; coasting_min_dist < coasting_dist ? return false; } unsigned int point_idx_before_start = path.points.size() - 1 - acc_dist_idx_gt_coast_dist; Point start; { // computation of begin point of coasting int64_t residual_dist = actual_coasting_dist - accumulated_dist_per_point[acc_dist_idx_gt_coast_dist - 1]; Point& a = path.points[point_idx_before_start]; Point& b = path.points[point_idx_before_start + 1]; start = b + normal(a-b, residual_dist); } { // write normal extrude path: for(unsigned int point_idx = 0; point_idx <= point_idx_before_start; point_idx++) { gcode.writeMove(path.points[point_idx], extrude_speed, path.getExtrusionMM3perMM()); } gcode.writeMove(start, extrude_speed, path.getExtrusionMM3perMM()); } if (path_next.retract) { writeRetraction(extruder_switch_retract, path.config->retraction_config); } for (unsigned int point_idx = point_idx_before_start + 1; point_idx < path.points.size(); point_idx++) { gcode.writeMove(path.points[point_idx], coasting_speed * path.config->getSpeed(), 0); } gcode.setLastCoastedAmountMM3(path.getExtrusionMM3perMM() * INT2MM(actual_coasting_dist)); return true; }
void GCodePlanner::writeGCode(bool liftHeadIfNeeded, int layerThickness) { GCodePathConfig* last_extrusion_config = nullptr; int extruder = gcode.getExtruderNr(); for(unsigned int path_idx = 0; path_idx < paths.size(); path_idx++) { GCodePath& path = paths[path_idx]; if (extruder != path.extruder) { extruder = path.extruder; gcode.switchExtruder(extruder); }else if (path.retract) { writeRetraction(path_idx); } if (path.config != &travelConfig && last_extrusion_config != path.config) { gcode.writeTypeComment(path.config->name); last_extrusion_config = path.config; } double speed = path.config->getSpeed(); if (path.getExtrusionMM3perMM() != 0)// Only apply the extrudeSpeed to extrusion moves speed *= getExtrudeSpeedFactor(); else speed *= getExtrudeSpeedFactor(); int64_t nozzle_size = 400; // TODO allow the machine settings to be passed on everywhere :: depends on which nozzle! if (MergeInfillLines(gcode, paths, travelConfig, nozzle_size).mergeInfillLines(speed, path_idx)) // !! has effect on path_idx !! { // !! has effect on path_idx !! // works when path_idx is the index of the travel move BEFORE the infill lines to be merged continue; } if (path.config == &travelConfig) { // early comp for travel paths, which are handled more simply for(unsigned int point_idx = 0; point_idx < path.points.size(); point_idx++) { gcode.writeMove(path.points[point_idx], speed, path.getExtrusionMM3perMM()); } continue; } bool spiralize = path.config->spiralize; if (spiralize) { //Check if we are the last spiralize path in the list, if not, do not spiralize. for(unsigned int m=path_idx+1; m<paths.size(); m++) { if (paths[m].config->spiralize) spiralize = false; } } if (!spiralize) // normal (extrusion) move (with coasting { CoastingConfig& coasting_config = storage.coasting_config[extruder]; bool coasting = coasting_config.coasting_enable; if (coasting) { coasting = writePathWithCoasting(path_idx, layerThickness , coasting_config.coasting_volume_move, coasting_config.coasting_speed_move, coasting_config.coasting_min_volume_move , coasting_config.coasting_volume_retract, coasting_config.coasting_speed_retract, coasting_config.coasting_min_volume_retract); } if (! coasting) // not same as 'else', cause we might have changed coasting in the line above... { // normal path to gcode algorithm if ( // change |||||| to /\/\/\/\/ ... false && path_idx + 2 < paths.size() // has a next move && paths[path_idx+1].points.size() == 1 // is single extruded line && paths[path_idx+1].config != &travelConfig // next move is extrusion && paths[path_idx+2].config == &travelConfig // next next move is travel && shorterThen(path.points.back() - gcode.getPositionXY(), 2 * nozzle_size) // preceding extrusion is close by && shorterThen(paths[path_idx+1].points.back() - path.points.back(), 2 * nozzle_size) // extrusion move is small && shorterThen(paths[path_idx+2].points.back() - paths[path_idx+1].points.back(), 2 * nozzle_size) // consecutive extrusion is close by ) { gcode.writeMove(paths[path_idx+2].points.back(), speed, paths[path_idx+1].getExtrusionMM3perMM()); path_idx += 2; } else { for(unsigned int point_idx = 0; point_idx < path.points.size(); point_idx++) { gcode.writeMove(path.points[point_idx], speed, path.getExtrusionMM3perMM()); } } } } else { // SPIRALIZE //If we need to spiralize then raise the head slowly by 1 layer as this path progresses. float totalLength = 0.0; int z = gcode.getPositionZ(); Point p0 = gcode.getPositionXY(); for(unsigned int i=0; i<path.points.size(); i++) { Point p1 = path.points[i]; totalLength += vSizeMM(p0 - p1); p0 = p1; } float length = 0.0; p0 = gcode.getPositionXY(); for(unsigned int point_idx = 0; point_idx < path.points.size(); point_idx++) { Point p1 = path.points[point_idx]; length += vSizeMM(p0 - p1); p0 = p1; gcode.setZ(z + layerThickness * length / totalLength); gcode.writeMove(path.points[point_idx], speed, path.getExtrusionMM3perMM()); } } } gcode.updateTotalPrintTime(); if (liftHeadIfNeeded && extraTime > 0.0) { gcode.writeComment("Small layer, adding delay"); if (last_extrusion_config) { bool extruder_switch_retract = false;// TODO: check whether we should do a retractoin_extruderSwitch; is the next path with a different extruder? writeRetraction(extruder_switch_retract, last_extrusion_config->retraction_config); } gcode.setZ(gcode.getPositionZ() + MM2INT(3.0)); gcode.writeMove(gcode.getPositionXY(), travelConfig.getSpeed(), 0); gcode.writeMove(gcode.getPositionXY() - Point(-MM2INT(20.0), 0), travelConfig.getSpeed(), 0); gcode.writeDelay(extraTime); } }