void GCodeExport::startExtruder(int new_extruder) { if (new_extruder != current_extruder) // wouldn't be the case on the very first extruder start if it's extruder 0 { if (flavor == EGCodeFlavor::MAKERBOT) { *output_stream << "M135 T" << new_extruder << new_line; } else { *output_stream << "T" << new_extruder << new_line; } } current_extruder = new_extruder; assert(getCurrentExtrudedVolume() == 0.0 && "Just after an extruder switch we haven't extruded anything yet!"); resetExtrusionValue(); // zero the E value on the new extruder, just to be sure writeCode(extruder_attr[new_extruder].start_code.c_str()); CommandSocket::setExtruderForSend(new_extruder); CommandSocket::setSendCurrentPosition( getPositionXY() ); //Change the Z position so it gets re-writting again. We do not know if the switch code modified the Z position. currentPosition.z += 1; }
void GCodeExport::resetExtrusionValue() { if (flavor != EGCodeFlavor::MAKERBOT && flavor != EGCodeFlavor::BFB) { *output_stream << "G92 " << extruder_attr[current_extruder].extruderCharacter << "0" << new_line; double current_extruded_volume = getCurrentExtrudedVolume(); extruder_attr[current_extruder].totalFilament += current_extruded_volume; for (double& extruded_volume_at_retraction : extruder_attr[current_extruder].extruded_volume_at_previous_n_retractions) { // update the extruded_volume_at_previous_n_retractions only of the current extruder, since other extruders don't extrude the current volume extruded_volume_at_retraction -= current_extruded_volume; } current_e_value = 0.0; extruder_attr[current_extruder].retraction_e_amount_at_e_start = extruder_attr[current_extruder].retraction_e_amount_current; } }
void GCodeExport::writeRetraction_extruderSwitch() { if (flavor == EGCodeFlavor::BFB) { if (!extruder_attr[current_extruder].retraction_e_amount_current) *output_stream << "M103\r\n"; extruder_attr[current_extruder].retraction_e_amount_current = 1.0; // 1.0 is a stub; BFB doesn't use the actual retracted amount; retraction is performed by firmware return; } double retraction_e_amount = extruder_attr[current_extruder].extruder_switch_retraction_distance * ((is_volumatric)? extruder_attr[current_extruder].filament_area : 1.0); if (extruder_attr[current_extruder].retraction_e_amount_current == retraction_e_amount) { return; } double current_extruded_volume = getCurrentExtrudedVolume(); std::deque<double>& extruded_volume_at_previous_n_retractions = extruder_attr[current_extruder].extruded_volume_at_previous_n_retractions; extruded_volume_at_previous_n_retractions.push_front(current_extruded_volume); if (firmware_retract) { if (extruder_attr[current_extruder].retraction_e_amount_current) { return; } *output_stream << "G10 S1\n"; } else { current_e_value -= retraction_e_amount; *output_stream << "G1 F" << (extruder_attr[current_extruder].extruderSwitchRetractionSpeed * 60) << " " << extruder_attr[current_extruder].extruderCharacter << std::setprecision(5) << current_e_value << "\n"; // the E value of the extruder switch retraction 'overwrites' the E value of the normal retraction currentSpeed = extruder_attr[current_extruder].extruderSwitchRetractionSpeed; extruder_attr[current_extruder].last_retraction_prime_speed = extruder_attr[current_extruder].extruderSwitchPrimeSpeed; } extruder_attr[current_extruder].retraction_e_amount_current = retraction_e_amount; // suppose that for UM2 the retraction amount in the firmware is equal to the provided amount }
void GCodeExport::writeRetraction(RetractionConfig* config, bool force, bool extruder_switch) { ExtruderTrainAttributes& extr_attr = extruder_attr[current_extruder]; if (flavor == EGCodeFlavor::BFB)//BitsFromBytes does automatic retraction. { if (extruder_switch) { if (!extr_attr.retraction_e_amount_current) *output_stream << "M103" << new_line; extr_attr.retraction_e_amount_current = 1.0; // 1.0 is a stub; BFB doesn't use the actual retracted amount; retraction is performed by firmware } return; } double old_retraction_e_amount = extr_attr.retraction_e_amount_current; double new_retraction_e_amount = mmToE(config->distance); double retraction_diff_e_amount = old_retraction_e_amount - new_retraction_e_amount; if (std::abs(retraction_diff_e_amount) < 0.000001) { return; } { // handle retraction limitation double current_extruded_volume = getCurrentExtrudedVolume(); std::deque<double>& extruded_volume_at_previous_n_retractions = extr_attr.extruded_volume_at_previous_n_retractions; while (int(extruded_volume_at_previous_n_retractions.size()) > config->retraction_count_max && !extruded_volume_at_previous_n_retractions.empty()) { // extruder switch could have introduced data which falls outside the retraction window // also the retraction_count_max could have changed between the last retraction and this extruded_volume_at_previous_n_retractions.pop_back(); } if (!force && config->retraction_count_max <= 0) { return; } if (!force && int(extruded_volume_at_previous_n_retractions.size()) == config->retraction_count_max && current_extruded_volume < extruded_volume_at_previous_n_retractions.back() + config->retraction_extrusion_window * extr_attr.filament_area) { return; } extruded_volume_at_previous_n_retractions.push_front(current_extruded_volume); if (int(extruded_volume_at_previous_n_retractions.size()) == config->retraction_count_max + 1) { extruded_volume_at_previous_n_retractions.pop_back(); } } if (firmware_retract) { if (extruder_switch && extr_attr.retraction_e_amount_current) { return; } *output_stream << "G10"; if (extruder_switch) { *output_stream << " S1"; } *output_stream << new_line; //Assume default UM2 retraction settings. estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value + retraction_diff_e_amount)), 25); // TODO: hardcoded values! } else { double speed = ((retraction_diff_e_amount < 0.0)? config->speed : extr_attr.last_retraction_prime_speed) * 60; current_e_value += retraction_diff_e_amount; *output_stream << "G1 F" << speed << " " << extr_attr.extruderCharacter << std::setprecision(5) << current_e_value << new_line; currentSpeed = speed; estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), currentSpeed); extr_attr.last_retraction_prime_speed = config->primeSpeed; } extr_attr.retraction_e_amount_current = new_retraction_e_amount; // suppose that for UM2 the retraction amount in the firmware is equal to the provided amount extr_attr.prime_volume += config->prime_volume; }
void GCodeExport::writeMove(int x, int y, int z, double speed, double extrusion_mm3_per_mm) { if (currentPosition.x == x && currentPosition.y == y && currentPosition.z == z) return; #ifdef ASSERT_INSANE_OUTPUT assert(speed < 200 && speed > 1); // normal F values occurring in UM2 gcode (this code should not be compiled for release) assert(currentPosition != no_point3); assert((Point3(x,y,z) - currentPosition).vSize() < MM2INT(300)); // no crazy positions (this code should not be compiled for release) #endif //ASSERT_INSANE_OUTPUT if (extrusion_mm3_per_mm < 0) logWarning("Warning! Negative extrusion move!"); if (flavor == EGCodeFlavor::BFB) { writeMoveBFB(x, y, z, speed, extrusion_mm3_per_mm); return; } double extrusion_per_mm = mm3ToE(extrusion_mm3_per_mm); Point gcode_pos = getGcodePos(x,y, current_extruder); if (extrusion_mm3_per_mm > 0.000001) { Point3 diff = Point3(x,y,z) - getPosition(); if (isZHopped > 0) { *output_stream << std::setprecision(3) << "G1 Z" << INT2MM(currentPosition.z) << new_line; isZHopped = 0; } double prime_volume = extruder_attr[current_extruder].prime_volume; current_e_value += mm3ToE(prime_volume); if (extruder_attr[current_extruder].retraction_e_amount_current) { if (firmware_retract) { // note that BFB is handled differently *output_stream << "G11" << new_line; //Assume default UM2 retraction settings. if (prime_volume > 0) { *output_stream << "G1 F" << (extruder_attr[current_extruder].last_retraction_prime_speed * 60) << " " << extruder_attr[current_extruder].extruderCharacter << std::setprecision(5) << current_e_value << new_line; currentSpeed = extruder_attr[current_extruder].last_retraction_prime_speed; } estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), 25.0); } else { current_e_value += extruder_attr[current_extruder].retraction_e_amount_current; *output_stream << "G1 F" << (extruder_attr[current_extruder].last_retraction_prime_speed * 60) << " " << extruder_attr[current_extruder].extruderCharacter << std::setprecision(5) << current_e_value << new_line; currentSpeed = extruder_attr[current_extruder].last_retraction_prime_speed; estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), currentSpeed); } if (getCurrentExtrudedVolume() > 10000.0) //According to https://github.com/Ultimaker/CuraEngine/issues/14 having more then 21m of extrusion causes inaccuracies. So reset it every 10m, just to be sure. { resetExtrusionValue(); } extruder_attr[current_extruder].retraction_e_amount_current = 0.0; } else if (prime_volume > 0.0) { *output_stream << "G1 F" << (extruder_attr[current_extruder].last_retraction_prime_speed * 60) << " " << extruder_attr[current_extruder].extruderCharacter << std::setprecision(5) << current_e_value << new_line; currentSpeed = extruder_attr[current_extruder].last_retraction_prime_speed; estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), currentSpeed); } extruder_attr[current_extruder].prime_volume = 0.0; current_e_value += extrusion_per_mm * diff.vSizeMM(); *output_stream << "G1"; } else { *output_stream << "G0"; CommandSocket::sendLineTo(extruder_attr[current_extruder].retraction_e_amount_current ? PrintFeatureType::MoveRetraction : PrintFeatureType::MoveCombing, Point(x, y), extruder_attr[current_extruder].retraction_e_amount_current ? MM2INT(0.2) : MM2INT(0.1)); } if (currentSpeed != speed) { *output_stream << " F" << (speed * 60); currentSpeed = speed; } *output_stream << std::setprecision(3) << " X" << INT2MM(gcode_pos.X) << " Y" << INT2MM(gcode_pos.Y); if (z != currentPosition.z + isZHopped) *output_stream << " Z" << INT2MM(z + isZHopped); if (extrusion_mm3_per_mm > 0.000001) *output_stream << " " << extruder_attr[current_extruder].extruderCharacter << std::setprecision(5) << current_e_value; *output_stream << new_line; currentPosition = Point3(x, y, z); estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value)), speed); }
double GCodeExport::getTotalFilamentUsed(int extruder_nr) { if (extruder_nr == current_extruder) return extruder_attr[extruder_nr].totalFilament + getCurrentExtrudedVolume(); return extruder_attr[extruder_nr].totalFilament; }
void GCodeExport::writeRetraction(RetractionConfig* config, bool force) { if (flavor == EGCodeFlavor::BFB)//BitsFromBytes does automatic retraction. { return; } if (extruder_attr[current_extruder].retraction_e_amount_current == config->distance * ((is_volumatric)? extruder_attr[current_extruder].filament_area : 1.0)) { return; } if (config->distance <= 0) { return; } { // handle retraction limitation double current_extruded_volume = getCurrentExtrudedVolume(); std::deque<double>& extruded_volume_at_previous_n_retractions = extruder_attr[current_extruder].extruded_volume_at_previous_n_retractions; while (int(extruded_volume_at_previous_n_retractions.size()) >= config->retraction_count_max && !extruded_volume_at_previous_n_retractions.empty()) { // extruder switch could have introduced data which falls outside the retraction window // also the retraction_count_max could have changed between the last retraction and this extruded_volume_at_previous_n_retractions.pop_back(); } if (!force && config->retraction_count_max <= 0) { return; } if (!force && int(extruded_volume_at_previous_n_retractions.size()) == config->retraction_count_max - 1 && current_extruded_volume < extruded_volume_at_previous_n_retractions.back() + config->retraction_extrusion_window * extruder_attr[current_extruder].filament_area) { return; } extruded_volume_at_previous_n_retractions.push_front(current_extruded_volume); if (int(extruded_volume_at_previous_n_retractions.size()) == config->retraction_count_max) { extruded_volume_at_previous_n_retractions.pop_back(); } } extruder_attr[current_extruder].last_retraction_prime_speed = config->primeSpeed; double retraction_e_amount = config->distance * ((is_volumatric)? extruder_attr[current_extruder].filament_area : 1.0); if (firmware_retract) { *output_stream << "G10\n"; //Assume default UM2 retraction settings. estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), current_e_value - retraction_e_amount), 25); // TODO: hardcoded values! } else { current_e_value -= retraction_e_amount; *output_stream << "G1 F" << (config->speed * 60) << " " << extruder_attr[current_extruder].extruderCharacter << std::setprecision(5) << current_e_value << "\n"; currentSpeed = config->speed; estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), current_e_value), currentSpeed); } extruder_attr[current_extruder].retraction_e_amount_current = retraction_e_amount ; extruder_attr[current_extruder].prime_volume += config->prime_volume; if (config->zHop > 0) { isZHopped = config->zHop; *output_stream << std::setprecision(3) << "G1 Z" << INT2MM(currentPosition.z + isZHopped) << "\n"; } }