Mister-Green/Repetier-Firmware 1.0.3/Repetier/Printer.cpp
2019-08-07 01:22:58 +02:00

2674 lines
108 KiB
C++

/*
This file is part of Repetier-Firmware.
Repetier-Firmware is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Repetier-Firmware is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Repetier-Firmware. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Repetier.h"
#if USE_ADVANCE
ufast8_t Printer::maxExtruderSpeed; ///< Timer delay for end extruder speed
volatile int Printer::extruderStepsNeeded; ///< This many extruder steps are still needed, <0 = reverse steps needed.
//uint8_t Printer::extruderAccelerateDelay; ///< delay between 2 speec increases
#endif
uint8_t Printer::unitIsInches = 0; ///< 0 = Units are mm, 1 = units are inches.
//Stepper Movement Variables
float Printer::axisStepsPerMM[E_AXIS_ARRAY] = {XAXIS_STEPS_PER_MM, YAXIS_STEPS_PER_MM, ZAXIS_STEPS_PER_MM, 1}; ///< Number of steps per mm needed.
float Printer::invAxisStepsPerMM[E_AXIS_ARRAY]; ///< Inverse of axisStepsPerMM for faster conversion
float Printer::maxFeedrate[E_AXIS_ARRAY] = {MAX_FEEDRATE_X, MAX_FEEDRATE_Y, MAX_FEEDRATE_Z}; ///< Maximum allowed feedrate.
float Printer::homingFeedrate[Z_AXIS_ARRAY] = {HOMING_FEEDRATE_X, HOMING_FEEDRATE_Y, HOMING_FEEDRATE_Z};
#if DUAL_X_RESOLUTION
float Printer::axisX1StepsPerMM = XAXIS_STEPS_PER_MM;
float Printer::axisX2StepsPerMM = X2AXIS_STEPS_PER_MM;
#endif
#if RAMP_ACCELERATION
// float max_start_speed_units_per_second[E_AXIS_ARRAY] = MAX_START_SPEED_UNITS_PER_SECOND; ///< Speed we can use, without acceleration.
float Printer::maxAccelerationMMPerSquareSecond[E_AXIS_ARRAY] = {MAX_ACCELERATION_UNITS_PER_SQ_SECOND_X, MAX_ACCELERATION_UNITS_PER_SQ_SECOND_Y, MAX_ACCELERATION_UNITS_PER_SQ_SECOND_Z}; ///< X, Y, Z and E max acceleration in mm/s^2 for printing moves or retracts
float Printer::maxTravelAccelerationMMPerSquareSecond[E_AXIS_ARRAY] = {MAX_TRAVEL_ACCELERATION_UNITS_PER_SQ_SECOND_X, MAX_TRAVEL_ACCELERATION_UNITS_PER_SQ_SECOND_Y, MAX_TRAVEL_ACCELERATION_UNITS_PER_SQ_SECOND_Z}; ///< X, Y, Z max acceleration in mm/s^2 for travel moves
/** Acceleration in steps/s^3 in printing mode.*/
unsigned long Printer::maxPrintAccelerationStepsPerSquareSecond[E_AXIS_ARRAY];
/** Acceleration in steps/s^2 in movement mode.*/
unsigned long Printer::maxTravelAccelerationStepsPerSquareSecond[E_AXIS_ARRAY];
// uint32_t Printer::maxInterval;
#endif
#if NONLINEAR_SYSTEM
long Printer::currentNonlinearPositionSteps[E_TOWER_ARRAY];
uint8_t lastMoveID = 0; // Last move ID
#endif
#if DRIVE_SYSTEM != DELTA
int32_t Printer::zCorrectionStepsIncluded = 0;
#endif
#if FEATURE_BABYSTEPPING
int16_t Printer::zBabystepsMissing = 0;
int16_t Printer::zBabysteps = 0;
#endif
uint8_t Printer::relativeCoordinateMode = false; ///< Determines absolute (false) or relative Coordinates (true).
uint8_t Printer::relativeExtruderCoordinateMode = false; ///< Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode.
long Printer::currentPositionSteps[E_AXIS_ARRAY];
float Printer::currentPosition[Z_AXIS_ARRAY];
float Printer::lastCmdPos[Z_AXIS_ARRAY];
long Printer::destinationSteps[E_AXIS_ARRAY];
float Printer::coordinateOffset[Z_AXIS_ARRAY] = {0, 0, 0};
uint8_t Printer::flag0 = 0;
uint8_t Printer::flag1 = 0;
uint8_t Printer::flag2 = 0;
uint8_t Printer::flag3 = 0;
uint8_t Printer::debugLevel = 6; ///< Bitfield defining debug output. 1 = echo, 2 = info, 4 = error, 8 = dry run., 16 = Only communication, 32 = No moves
fast8_t Printer::stepsPerTimerCall = 1;
uint16_t Printer::menuMode = 0;
uint8_t Printer::mode = DEFAULT_PRINTER_MODE;
uint8_t Printer::fanSpeed = 0; // Last fan speed set with M106/M107
float Printer::extrudeMultiplyError = 0;
float Printer::extrusionFactor = 1.0;
uint8_t Printer::interruptEvent = 0;
int Printer::currentLayer = 0;
int Printer::maxLayer = -1; // -1 = unknown
char Printer::printName[21] = ""; // max. 20 chars + 0
float Printer::progress = 0;
millis_t Printer::lastTempReport = 0;
#if EEPROM_MODE != 0
float Printer::zBedOffset = HAL::eprGetFloat(EPR_Z_PROBE_Z_OFFSET);
#else
float Printer::zBedOffset = Z_PROBE_Z_OFFSET;
#endif
#if FEATURE_AUTOLEVEL
float Printer::autolevelTransformation[9]; ///< Transformation matrix
#endif
uint32_t Printer::interval = 30000; ///< Last step duration in ticks.
uint32_t Printer::timer; ///< used for acceleration/deceleration timing
uint32_t Printer::stepNumber; ///< Step number in current move.
#if USE_ADVANCE
#if ENABLE_QUADRATIC_ADVANCE
int32_t Printer::advanceExecuted; ///< Executed advance steps
#endif
int Printer::advanceStepsSet;
#endif
#if NONLINEAR_SYSTEM
int32_t Printer::maxDeltaPositionSteps;
floatLong Printer::deltaDiagonalStepsSquaredA;
floatLong Printer::deltaDiagonalStepsSquaredB;
floatLong Printer::deltaDiagonalStepsSquaredC;
float Printer::deltaMaxRadiusSquared;
float Printer::radius0;
int32_t Printer::deltaFloorSafetyMarginSteps = 0;
int32_t Printer::deltaAPosXSteps;
int32_t Printer::deltaAPosYSteps;
int32_t Printer::deltaBPosXSteps;
int32_t Printer::deltaBPosYSteps;
int32_t Printer::deltaCPosXSteps;
int32_t Printer::deltaCPosYSteps;
int32_t Printer::realDeltaPositionSteps[TOWER_ARRAY];
int16_t Printer::travelMovesPerSecond;
int16_t Printer::printMovesPerSecond;
#endif
#if !NONLINEAR_SYSTEM || defined(FAST_COREXYZ)
int32_t Printer::xMinStepsAdj, Printer::yMinStepsAdj, Printer::zMinStepsAdj; // adjusted to cover extruder/probe offsets
int32_t Printer::xMaxStepsAdj, Printer::yMaxStepsAdj, Printer::zMaxStepsAdj;
#endif
#if FEATURE_Z_PROBE || MAX_HARDWARE_ENDSTOP_Z || NONLINEAR_SYSTEM
int32_t Printer::stepsRemainingAtZHit;
#endif
#if DRIVE_SYSTEM == DELTA
int32_t Printer::stepsRemainingAtXHit;
int32_t Printer::stepsRemainingAtYHit;
#endif
#if SOFTWARE_LEVELING
int32_t Printer::levelingP1[3];
int32_t Printer::levelingP2[3];
int32_t Printer::levelingP3[3];
#endif
//float Printer::minimumSpeed; ///< lowest allowed speed to keep integration error small
//float Printer::minimumZSpeed;
int32_t Printer::xMaxSteps; ///< For software endstops, limit of move in positive direction.
int32_t Printer::yMaxSteps; ///< For software endstops, limit of move in positive direction.
int32_t Printer::zMaxSteps; ///< For software endstops, limit of move in positive direction.
int32_t Printer::xMinSteps; ///< For software endstops, limit of move in negative direction.
int32_t Printer::yMinSteps; ///< For software endstops, limit of move in negative direction.
int32_t Printer::zMinSteps; ///< For software endstops, limit of move in negative direction.
float Printer::xLength;
float Printer::xMin;
float Printer::yLength;
float Printer::yMin;
float Printer::zLength;
float Printer::zMin;
float Printer::feedrate; ///< Last requested feedrate.
int Printer::feedrateMultiply; ///< Multiplier for feedrate in percent (factor 1 = 100)
unsigned int Printer::extrudeMultiply; ///< Flow multiplier in percent (factor 1 = 100)
float Printer::maxJerk; ///< Maximum allowed jerk in mm/s
#if DRIVE_SYSTEM != DELTA
float Printer::maxZJerk; ///< Maximum allowed jerk in z direction in mm/s
#endif
float Printer::offsetX; ///< X-offset for different extruder positions.
float Printer::offsetY; ///< Y-offset for different extruder positions.
float Printer::offsetZ; ///< Z-offset for different extruder positions.
float Printer::offsetZ2 = 0; ///< Z-offset without rotation correction.
speed_t Printer::vMaxReached; ///< Maximum reached speed
uint32_t Printer::msecondsPrinting; ///< Milliseconds of printing time (means time with heated extruder)
float Printer::filamentPrinted; ///< mm of filament printed since counting started
#if ENABLE_BACKLASH_COMPENSATION
float Printer::backlashX;
float Printer::backlashY;
float Printer::backlashZ;
uint8_t Printer::backlashDir;
#endif
float Printer::memoryX = IGNORE_COORDINATE;
float Printer::memoryY = IGNORE_COORDINATE;
float Printer::memoryZ = IGNORE_COORDINATE;
float Printer::memoryE = IGNORE_COORDINATE;
float Printer::memoryF = -1;
#if GANTRY && !defined(FAST_COREXYZ)
int8_t Printer::motorX;
int8_t Printer::motorYorZ;
#endif
#if FAN_THERMO_PIN > -1
float Printer::thermoMinTemp = FAN_THERMO_MIN_TEMP;
float Printer::thermoMaxTemp = FAN_THERMO_MAX_TEMP;
#endif
#ifdef DEBUG_SEGMENT_LENGTH
float Printer::maxRealSegmentLength = 0;
#endif
#ifdef DEBUG_REAL_JERK
float Printer::maxRealJerk = 0;
#endif
#if MULTI_XENDSTOP_HOMING
fast8_t Printer::multiXHomeFlags; // 1 = move X0, 2 = move X1
#endif
#if MULTI_YENDSTOP_HOMING
fast8_t Printer::multiYHomeFlags; // 1 = move Y0, 2 = move Y1
#endif
#if MULTI_ZENDSTOP_HOMING
fast8_t Printer::multiZHomeFlags; // 1 = move Z0, 2 = move Z1
#endif
#ifdef DEBUG_PRINT
int debugWaitLoop = 0;
#endif
#if LAZY_DUAL_X_AXIS
bool Printer::sledParked = false;
#endif
fast8_t Printer::wizardStackPos;
wizardVar Printer::wizardStack[WIZARD_STACK_SIZE];
#if defined(DRV_TMC2130)
#if TMC2130_ON_X
TMC2130Stepper* Printer::tmc_driver_x = NULL;
#endif
#if TMC2130_ON_Y
TMC2130Stepper* Printer::tmc_driver_y = NULL;
#endif
#if TMC2130_ON_Z
TMC2130Stepper* Printer::tmc_driver_z = NULL;
#endif
#if TMC2130_ON_EXT0
TMC2130Stepper* Printer::tmc_driver_e0 = NULL;
#endif
#if TMC2130_ON_EXT1
TMC2130Stepper* Printer::tmc_driver_e1 = NULL;
#endif
#if TMC2130_ON_EXT2
TMC2130Stepper* Printer::tmc_driver_e2 = NULL;
#endif
#endif
#if !NONLINEAR_SYSTEM
void Printer::constrainDestinationCoords() {
if(isNoDestinationCheck() || isHoming()) return;
#if min_software_endstop_x
if (destinationSteps[X_AXIS] < xMinStepsAdj) destinationSteps[X_AXIS] = xMinStepsAdj;
#endif
#if min_software_endstop_y
if (destinationSteps[Y_AXIS] < yMinStepsAdj) destinationSteps[Y_AXIS] = yMinStepsAdj;
#endif
#if min_software_endstop_z
if (isAutolevelActive() == false && destinationSteps[Z_AXIS] < zMinStepsAdj && !isZProbingActive()) destinationSteps[Z_AXIS] = zMinStepsAdj;
#endif
#if max_software_endstop_x
if (destinationSteps[X_AXIS] > xMaxStepsAdj) destinationSteps[X_AXIS] = xMaxStepsAdj;
#endif
#if max_software_endstop_y
if (destinationSteps[Y_AXIS] > yMaxStepsAdj) destinationSteps[Y_AXIS] = yMaxStepsAdj;
#endif
#if max_software_endstop_z
if (isAutolevelActive() == false && destinationSteps[Z_AXIS] > zMaxStepsAdj && !isZProbingActive()) destinationSteps[Z_AXIS] = zMaxStepsAdj;
#endif
EVENT_CONTRAIN_DESTINATION_COORDINATES
}
#endif
void Printer::setDebugLevel(uint8_t newLevel) {
if(newLevel != debugLevel) {
debugLevel = newLevel;
if(debugDryrun()) {
// Disable all heaters in case they were on
Extruder::disableAllHeater();
}
}
Com::printFLN(PSTR("DebugLevel:"), (int)newLevel);
}
void Printer::toggleEcho() {
setDebugLevel(debugLevel ^ 1);
}
void Printer::toggleInfo() {
setDebugLevel(debugLevel ^ 2);
}
void Printer::toggleErrors() {
setDebugLevel(debugLevel ^ 4);
}
void Printer::toggleDryRun() {
setDebugLevel(debugLevel ^ 8);
}
void Printer::toggleCommunication() {
setDebugLevel(debugLevel ^ 16);
}
void Printer::toggleNoMoves() {
setDebugLevel(debugLevel ^ 32);
}
void Printer::toggleEndStop() {
setDebugLevel(debugLevel ^ 64);
}
bool Printer::isPositionAllowed(float x, float y, float z) {
if(isNoDestinationCheck()) return true;
bool allowed = true;
#if DRIVE_SYSTEM == DELTA
if(!isHoming()) {
allowed = allowed && (z >= 0) && (z <= zLength + 0.05 + ENDSTOP_Z_BACK_ON_HOME);
allowed = allowed && (x * x + y * y <= deltaMaxRadiusSquared);
}
#else // DRIVE_SYSTEM
if(!isHoming()) {
allowed = allowed && x >= xMin - 0.01;
allowed = allowed && x <= xMin + xLength + 0.01;
allowed = allowed && y >= yMin - 0.01;
allowed = allowed && y <= yMin + yLength + 0.01;
allowed = allowed && z >= zMin - 0.01;
allowed = allowed && z <= zMin + zLength + ENDSTOP_Z_BACK_ON_HOME + 0.01;
}
#endif
/*#if DUAL_X_AXIS
// Prevent carriage hit by disallowing moves inside other parking direction.
if(Extruder::current->id == 0) {
if(x > xMin + xLength + 0.01)
allowed = false;
} else {
if(x < xMin - 0.01)
allowed = false;
}
#endif*/
if(!allowed) {
Printer::updateCurrentPosition(true);
Commands::printCurrentPosition();
}
return allowed;
}
void Printer::setFanSpeedDirectly(uint8_t speed) {
uint8_t trimmedSpeed = TRIM_FAN_PWM(speed);
#if FAN_PIN > -1 && FEATURE_FAN_CONTROL
if(pwm_pos[PWM_FAN1] == trimmedSpeed)
return;
#if FAN_KICKSTART_TIME
if(fanKickstart == 0 && speed > pwm_pos[PWM_FAN1] && speed < 85) {
if(pwm_pos[PWM_FAN1]) fanKickstart = FAN_KICKSTART_TIME / 100;
else fanKickstart = FAN_KICKSTART_TIME / 25;
}
#endif
pwm_pos[PWM_FAN1] = trimmedSpeed;
#endif
}
void Printer::setFan2SpeedDirectly(uint8_t speed) {
uint8_t trimmedSpeed = TRIM_FAN_PWM(speed);
#if FAN2_PIN > -1 && FEATURE_FAN2_CONTROL
if(pwm_pos[PWM_FAN2] == trimmedSpeed)
return;
#if FAN_KICKSTART_TIME
if(fan2Kickstart == 0 && speed > pwm_pos[PWM_FAN2] && speed < 85) {
if(pwm_pos[PWM_FAN2]) fan2Kickstart = FAN_KICKSTART_TIME / 100;
else fan2Kickstart = FAN_KICKSTART_TIME / 25;
}
#endif
pwm_pos[PWM_FAN2] = trimmedSpeed;
#endif
}
bool Printer::updateDoorOpen() {
#if defined(DOOR_PIN) && DOOR_PIN > -1 // && SUPPORT_LASER should always be respected
bool isOpen = isDoorOpen();
uint8_t b = READ(DOOR_PIN) != DOOR_INVERTING;
if(!b && isOpen) {
UI_STATUS_F(Com::tSpace);
} else if(b && !isOpen) {
Com::printWarningFLN(Com::tDoorOpen);
UI_STATUS_F(Com::tDoorOpen);
}
flag3 = (b ? flag3 | PRINTER_FLAG3_DOOR_OPEN : flag3 & ~PRINTER_FLAG3_DOOR_OPEN);
return b;
#else
return 0;
#endif
}
void Printer::reportPrinterMode() {
Printer::setMenuMode(MENU_MODE_CNC + MENU_MODE_LASER + MENU_MODE_FDM, false);
switch(Printer::mode) {
case PRINTER_MODE_FFF:
Printer::setMenuMode(MENU_MODE_FDM, true);
Com::printFLN(Com::tPrinterModeFFF);
break;
case PRINTER_MODE_LASER:
Printer::setMenuMode(MENU_MODE_LASER, true);
Com::printFLN(Com::tPrinterModeLaser);
break;
case PRINTER_MODE_CNC:
Printer::setMenuMode(MENU_MODE_CNC, true);
Com::printFLN(Com::tPrinterModeCNC);
break;
}
}
void Printer::updateDerivedParameter() {
#if NONLINEAR_SYSTEM
travelMovesPerSecond = EEPROM::deltaSegmentsPerSecondMove();
printMovesPerSecond = EEPROM::deltaSegmentsPerSecondPrint();
if(travelMovesPerSecond < 15) travelMovesPerSecond = 15; // lower values make no sense and can cause serious problems
if(printMovesPerSecond < 15) printMovesPerSecond = 15;
#endif
#if DRIVE_SYSTEM == DELTA
axisStepsPerMM[X_AXIS] = axisStepsPerMM[Y_AXIS] = axisStepsPerMM[Z_AXIS];
maxAccelerationMMPerSquareSecond[X_AXIS] = maxAccelerationMMPerSquareSecond[Y_AXIS] = maxAccelerationMMPerSquareSecond[Z_AXIS];
homingFeedrate[X_AXIS] = homingFeedrate[Y_AXIS] = homingFeedrate[Z_AXIS];
maxFeedrate[X_AXIS] = maxFeedrate[Y_AXIS] = maxFeedrate[Z_AXIS];
maxTravelAccelerationMMPerSquareSecond[X_AXIS] = maxTravelAccelerationMMPerSquareSecond[Y_AXIS] = maxTravelAccelerationMMPerSquareSecond[Z_AXIS];
zMaxSteps = axisStepsPerMM[Z_AXIS] * (zLength);
towerAMinSteps = axisStepsPerMM[A_TOWER] * xMin;
towerBMinSteps = axisStepsPerMM[B_TOWER] * yMin;
towerCMinSteps = axisStepsPerMM[C_TOWER] * zMin;
//radius0 = EEPROM::deltaHorizontalRadius();
float radiusA = radius0 + EEPROM::deltaRadiusCorrectionA();
float radiusB = radius0 + EEPROM::deltaRadiusCorrectionB();
float radiusC = radius0 + EEPROM::deltaRadiusCorrectionC();
deltaAPosXSteps = floor(radiusA * cos(EEPROM::deltaAlphaA() * M_PI / 180.0f) * axisStepsPerMM[Z_AXIS] + 0.5f);
deltaAPosYSteps = floor(radiusA * sin(EEPROM::deltaAlphaA() * M_PI / 180.0f) * axisStepsPerMM[Z_AXIS] + 0.5f);
deltaBPosXSteps = floor(radiusB * cos(EEPROM::deltaAlphaB() * M_PI / 180.0f) * axisStepsPerMM[Z_AXIS] + 0.5f);
deltaBPosYSteps = floor(radiusB * sin(EEPROM::deltaAlphaB() * M_PI / 180.0f) * axisStepsPerMM[Z_AXIS] + 0.5f);
deltaCPosXSteps = floor(radiusC * cos(EEPROM::deltaAlphaC() * M_PI / 180.0f) * axisStepsPerMM[Z_AXIS] + 0.5f);
deltaCPosYSteps = floor(radiusC * sin(EEPROM::deltaAlphaC() * M_PI / 180.0f) * axisStepsPerMM[Z_AXIS] + 0.5f);
deltaDiagonalStepsSquaredA.l = static_cast<uint32_t>((EEPROM::deltaDiagonalCorrectionA() + EEPROM::deltaDiagonalRodLength()) * axisStepsPerMM[Z_AXIS]);
deltaDiagonalStepsSquaredB.l = static_cast<uint32_t>((EEPROM::deltaDiagonalCorrectionB() + EEPROM::deltaDiagonalRodLength()) * axisStepsPerMM[Z_AXIS]);
deltaDiagonalStepsSquaredC.l = static_cast<uint32_t>((EEPROM::deltaDiagonalCorrectionC() + EEPROM::deltaDiagonalRodLength()) * axisStepsPerMM[Z_AXIS]);
if(deltaDiagonalStepsSquaredA.l > 65534 || 2 * radius0 * axisStepsPerMM[Z_AXIS] > 65534) {
setLargeMachine(true);
#ifdef SUPPORT_64_BIT_MATH
deltaDiagonalStepsSquaredA.L = RMath::sqr(static_cast<uint64_t>(deltaDiagonalStepsSquaredA.l));
deltaDiagonalStepsSquaredB.L = RMath::sqr(static_cast<uint64_t>(deltaDiagonalStepsSquaredB.l));
deltaDiagonalStepsSquaredC.L = RMath::sqr(static_cast<uint64_t>(deltaDiagonalStepsSquaredC.l));
#else
deltaDiagonalStepsSquaredA.f = RMath::sqr(static_cast<float>(deltaDiagonalStepsSquaredA.l));
deltaDiagonalStepsSquaredB.f = RMath::sqr(static_cast<float>(deltaDiagonalStepsSquaredB.l));
deltaDiagonalStepsSquaredC.f = RMath::sqr(static_cast<float>(deltaDiagonalStepsSquaredC.l));
#endif
} else {
setLargeMachine(false);
deltaDiagonalStepsSquaredA.l = RMath::sqr(deltaDiagonalStepsSquaredA.l);
deltaDiagonalStepsSquaredB.l = RMath::sqr(deltaDiagonalStepsSquaredB.l);
deltaDiagonalStepsSquaredC.l = RMath::sqr(deltaDiagonalStepsSquaredC.l);
}
deltaMaxRadiusSquared = RMath::sqr(EEPROM::deltaMaxRadius());
long cart[Z_AXIS_ARRAY], delta[TOWER_ARRAY];
cart[X_AXIS] = cart[Y_AXIS] = 0;
cart[Z_AXIS] = zMaxSteps;
transformCartesianStepsToDeltaSteps(cart, delta);
maxDeltaPositionSteps = delta[0];
xMaxSteps = yMaxSteps = zMaxSteps;
xMinSteps = yMinSteps = zMinSteps = 0;
deltaFloorSafetyMarginSteps = DELTA_FLOOR_SAFETY_MARGIN_MM * axisStepsPerMM[Z_AXIS];
#elif DRIVE_SYSTEM == TUGA
deltaDiagonalStepsSquared.l = uint32_t(EEPROM::deltaDiagonalRodLength() * axisStepsPerMM[X_AXIS]);
if(deltaDiagonalStepsSquared.l > 65534) {
setLargeMachine(true);
deltaDiagonalStepsSquared.f = float(deltaDiagonalStepsSquared.l) * float(deltaDiagonalStepsSquared.l);
} else
deltaDiagonalStepsSquared.l = deltaDiagonalStepsSquared.l * deltaDiagonalStepsSquared.l;
deltaBPosXSteps = static_cast<int32_t>(EEPROM::deltaDiagonalRodLength() * axisStepsPerMM[X_AXIS]);
xMaxSteps = static_cast<int32_t>(axisStepsPerMM[X_AXIS] * (xMin + xLength));
yMaxSteps = static_cast<int32_t>(axisStepsPerMM[Y_AXIS] * yLength);
zMaxSteps = static_cast<int32_t>(axisStepsPerMM[Z_AXIS] * (zMin + zLength));
xMinSteps = static_cast<int32_t>(axisStepsPerMM[X_AXIS] * xMin);
yMinSteps = 0;
zMinSteps = static_cast<int32_t>(axisStepsPerMM[Z_AXIS] * zMin);
#else
#if DUAL_X_RESOLUTION
if(Extruder::current->id == 0) // adjust resolution based on active extruder
axisStepsPerMM[X_AXIS] = axisX1StepsPerMM;
else
axisStepsPerMM[X_AXIS] = axisX2StepsPerMM;
invAxisStepsPerMM[X_AXIS] = 1.0 / axisStepsPerMM[X_AXIS];
#endif
xMaxStepsAdj = xMaxSteps = static_cast<int32_t>(axisStepsPerMM[X_AXIS] * (xMin + xLength));
yMaxStepsAdj = yMaxSteps = static_cast<int32_t>(axisStepsPerMM[Y_AXIS] * (yMin + yLength));
zMaxStepsAdj = zMaxSteps = static_cast<int32_t>(axisStepsPerMM[Z_AXIS] * (zMin + zLength));
xMinStepsAdj = xMinSteps = static_cast<int32_t>(axisStepsPerMM[X_AXIS] * xMin);
yMinStepsAdj = yMinSteps = static_cast<int32_t>(axisStepsPerMM[Y_AXIS] * yMin);
zMinStepsAdj = zMinSteps = static_cast<int32_t>(axisStepsPerMM[Z_AXIS] * zMin);
for(fast8_t i = 0; i < NUM_EXTRUDER; i++) {
Extruder &e = extruder[i];
xMaxStepsAdj = RMath::max(xMaxStepsAdj, xMaxSteps - e.xOffset);
xMinStepsAdj = RMath::min(xMinStepsAdj, xMinSteps - e.xOffset);
yMaxStepsAdj = RMath::max(yMaxStepsAdj, yMaxSteps - e.yOffset);
yMinStepsAdj = RMath::min(yMinStepsAdj, yMinSteps - e.yOffset);
zMaxStepsAdj = RMath::max(zMaxStepsAdj, zMaxSteps - e.zOffset);
zMinStepsAdj = RMath::min(zMinStepsAdj, zMinSteps - e.zOffset);
}
#if FEATURE_Z_PROBE
xMaxStepsAdj = RMath::max(xMaxStepsAdj, xMaxSteps - static_cast<int32_t>(EEPROM::zProbeXOffset() * axisStepsPerMM[X_AXIS]));
xMinStepsAdj = RMath::min(xMinStepsAdj, xMinSteps - static_cast<int32_t>(EEPROM::zProbeXOffset() * axisStepsPerMM[X_AXIS]));
yMaxStepsAdj = RMath::max(yMaxStepsAdj, yMaxSteps - static_cast<int32_t>(EEPROM::zProbeYOffset() * axisStepsPerMM[Y_AXIS]));
yMinStepsAdj = RMath::min(yMinStepsAdj, yMinSteps - static_cast<int32_t>(EEPROM::zProbeYOffset() * axisStepsPerMM[Y_AXIS]));
#endif
// For which directions do we need backlash compensation
#if ENABLE_BACKLASH_COMPENSATION
backlashDir &= XYZ_DIRPOS;
if(backlashX != 0) backlashDir |= 8;
if(backlashY != 0) backlashDir |= 16;
if(backlashZ != 0) backlashDir |= 32;
#endif
#endif
for(uint8_t i = 0; i < E_AXIS_ARRAY; i++) {
invAxisStepsPerMM[i] = 1.0f / axisStepsPerMM[i];
#ifdef RAMP_ACCELERATION
/** Acceleration in steps/s^3 in printing mode.*/
maxPrintAccelerationStepsPerSquareSecond[i] = maxAccelerationMMPerSquareSecond[i] * axisStepsPerMM[i];
/** Acceleration in steps/s^2 in movement mode.*/
maxTravelAccelerationStepsPerSquareSecond[i] = maxTravelAccelerationMMPerSquareSecond[i] * axisStepsPerMM[i];
#endif
}
// For numeric stability we need to start accelerations at a minimum speed and hence ensure that the
// jerk is at least 2 * minimum speed.
// For xy moves the minimum speed is multiplied with 1.41 to enforce the condition also for diagonals since the
// driving axis is the problematic speed.
float accel = RMath::max(maxAccelerationMMPerSquareSecond[X_AXIS], maxTravelAccelerationMMPerSquareSecond[X_AXIS]);
float minimumSpeed = 1.41 * accel * sqrt(2.0f / (axisStepsPerMM[X_AXIS] * accel));
accel = RMath::max(maxAccelerationMMPerSquareSecond[Y_AXIS], maxTravelAccelerationMMPerSquareSecond[Y_AXIS]);
float minimumSpeed2 = 1.41 * accel * sqrt(2.0f / (axisStepsPerMM[Y_AXIS] * accel));
if(minimumSpeed2 > minimumSpeed) {
minimumSpeed = minimumSpeed2;
}
if(maxJerk < 2 * minimumSpeed) {// Enforce minimum start speed if target is faster and jerk too low
maxJerk = 2 * minimumSpeed;
Com::printFLN(PSTR("XY jerk was too low, setting to "), maxJerk);
}
accel = RMath::max(maxAccelerationMMPerSquareSecond[Z_AXIS], maxTravelAccelerationMMPerSquareSecond[Z_AXIS]);
#if DRIVE_SYSTEM != DELTA
float minimumZSpeed = 0.5 * accel * sqrt(2.0f / (axisStepsPerMM[Z_AXIS] * accel));
if(maxZJerk < 2 * minimumZSpeed) {
maxZJerk = 2 * minimumZSpeed;
Com::printFLN(PSTR("Z jerk was too low, setting to "), maxZJerk);
}
#endif
/*
maxInterval = F_CPU / (minimumSpeed * axisStepsPerMM[X_AXIS]);
uint32_t tmp = F_CPU / (minimumSpeed * axisStepsPerMM[Y_AXIS]);
if(tmp < maxInterval)
maxInterval = tmp;
#if DRIVE_SYSTEM != DELTA
tmp = F_CPU / (minimumZSpeed * axisStepsPerMM[Z_AXIS]);
if(tmp < maxInterval)
maxInterval = tmp;
#endif
*/
//Com::printFLN(PSTR("Minimum Speed:"),minimumSpeed);
//Com::printFLN(PSTR("Minimum Speed Z:"),minimumZSpeed);
#if DISTORTION_CORRECTION
distortion.updateDerived();
#endif // DISTORTION_CORRECTION
Printer::updateAdvanceFlags();
EVENT_UPDATE_DERIVED;
}
#if AUTOMATIC_POWERUP
void Printer::enablePowerIfNeeded() {
if(Printer::isPowerOn())
return;
SET_OUTPUT(PS_ON_PIN); //GND
Printer::setPowerOn(true);
WRITE(PS_ON_PIN, (POWER_INVERTING ? HIGH : LOW));
HAL::delayMilliseconds(500); // Just to ensure power is up and stable
}
#endif
/**
\brief Stop heater and stepper motors. Disable power,if possible.
*/
void Printer::kill(uint8_t onlySteppers) {
EVENT_KILL(onlySteppers);
if(areAllSteppersDisabled() && onlySteppers) return;
if(Printer::isAllKilled()) return;
#if defined(NUM_MOTOR_DRIVERS) && NUM_MOTOR_DRIVERS > 0
disableAllMotorDrivers();
#endif // defined
disableXStepper();
disableYStepper();
#if !defined(PREVENT_Z_DISABLE_ON_STEPPER_TIMEOUT)
disableZStepper();
#else
if(!onlySteppers)
disableZStepper();
#endif
Extruder::disableAllExtruderMotors();
setAllSteppersDiabled();
unsetHomedAll();
if(!onlySteppers) {
for(uint8_t i = 0; i < NUM_EXTRUDER; i++)
Extruder::setTemperatureForExtruder(0, i);
Extruder::setHeatedBedTemperature(0);
UI_STATUS_UPD_F(Com::translatedF(UI_TEXT_STANDBY_ID));
#if defined(PS_ON_PIN) && PS_ON_PIN>-1 && !defined(NO_POWER_TIMEOUT)
//pinMode(PS_ON_PIN,INPUT);
SET_OUTPUT(PS_ON_PIN); //GND
WRITE(PS_ON_PIN, (POWER_INVERTING ? LOW : HIGH));
Printer::setPowerOn(false);
#endif
Printer::setAllKilled(true);
} else UI_STATUS_UPD_F(Com::translatedF(UI_TEXT_STEPPER_DISABLED_ID));
#if FAN_BOARD_PIN > -1
#if HAVE_HEATED_BED
if(heatedBedController.targetTemperatureC < 15) // turn off FAN_BOARD only if bed heater is off
#endif
pwm_pos[PWM_BOARD_FAN] = BOARD_FAN_MIN_SPEED;
#endif // FAN_BOARD_PIN
Commands::printTemperatures(false);
}
void Printer::updateAdvanceFlags() {
Printer::setAdvanceActivated(false);
#if USE_ADVANCE
for(uint8_t i = 0; i < NUM_EXTRUDER; i++) {
if(extruder[i].advanceL != 0) {
Printer::setAdvanceActivated(true);
}
#if ENABLE_QUADRATIC_ADVANCE
if(extruder[i].advanceK != 0) Printer::setAdvanceActivated(true);
#endif
}
#endif
}
void Printer::moveToParkPosition() {
if(Printer::isHomedAll()) { // for safety move only when homed!
moveToReal(EEPROM::parkX(),EEPROM::parkY(),IGNORE_COORDINATE,IGNORE_COORDINATE, Printer::maxFeedrate[X_AXIS], true);
moveToReal(IGNORE_COORDINATE,IGNORE_COORDINATE,RMath::min(zMin + zLength, currentPosition[Z_AXIS] + EEPROM::parkZ()),IGNORE_COORDINATE, Printer::maxFeedrate[Z_AXIS], true);
}
}
// This is for untransformed move to coordinates in printers absolute Cartesian space
uint8_t Printer::moveTo(float x, float y, float z, float e, float f) {
if(x != IGNORE_COORDINATE)
destinationSteps[X_AXIS] = (x + Printer::offsetX) * axisStepsPerMM[X_AXIS];
if(y != IGNORE_COORDINATE)
destinationSteps[Y_AXIS] = (y + Printer::offsetY) * axisStepsPerMM[Y_AXIS];
if(z != IGNORE_COORDINATE)
destinationSteps[Z_AXIS] = (z + Printer::offsetZ) * axisStepsPerMM[Z_AXIS];
if(e != IGNORE_COORDINATE)
destinationSteps[E_AXIS] = e * axisStepsPerMM[E_AXIS];
else
destinationSteps[E_AXIS] = currentPositionSteps[E_AXIS];
if(f != IGNORE_COORDINATE)
feedrate = f;
#if NONLINEAR_SYSTEM
// Disable software end stop or we get wrong distances when length < real length
if (!PrintLine::queueNonlinearMove(ALWAYS_CHECK_ENDSTOPS, true, false)) {
Com::printWarningFLN(PSTR("moveTo / queueDeltaMove returns error"));
return 0;
}
#else
PrintLine::queueCartesianMove(ALWAYS_CHECK_ENDSTOPS, true);
#endif
updateCurrentPosition(false);
return 1;
}
uint8_t Printer::moveToReal(float x, float y, float z, float e, float f, bool pathOptimize) {
if(x == IGNORE_COORDINATE)
x = currentPosition[X_AXIS];
else
currentPosition[X_AXIS] = x;
if(y == IGNORE_COORDINATE)
y = currentPosition[Y_AXIS];
else
currentPosition[Y_AXIS] = y;
if(z == IGNORE_COORDINATE)
z = currentPosition[Z_AXIS];
else
currentPosition[Z_AXIS] = z;
transformToPrinter(x + Printer::offsetX, y + Printer::offsetY, z + Printer::offsetZ, x, y, z);
z += offsetZ2;
// There was conflicting use of IGNOR_COORDINATE
destinationSteps[X_AXIS] = static_cast<int32_t>(floor(x * axisStepsPerMM[X_AXIS] + 0.5f));
destinationSteps[Y_AXIS] = static_cast<int32_t>(floor(y * axisStepsPerMM[Y_AXIS] + 0.5f));
destinationSteps[Z_AXIS] = static_cast<int32_t>(floor(z * axisStepsPerMM[Z_AXIS] + 0.5f));
if(e != IGNORE_COORDINATE && !Printer::debugDryrun()
#if MIN_EXTRUDER_TEMP > 30
&& (Extruder::current->tempControl.currentTemperatureC > MIN_EXTRUDER_TEMP || Printer::isColdExtrusionAllowed() || Extruder::current->tempControl.sensorType == 0)
#endif
) {
destinationSteps[E_AXIS] = e * axisStepsPerMM[E_AXIS];
} else {
destinationSteps[E_AXIS] = currentPositionSteps[E_AXIS];
}
if(f != IGNORE_COORDINATE)
feedrate = f;
#if NONLINEAR_SYSTEM
if (!PrintLine::queueNonlinearMove(ALWAYS_CHECK_ENDSTOPS, pathOptimize, true)) {
Com::printWarningFLN(PSTR("moveToReal / queueDeltaMove returns error"));
SHOWM(x);
SHOWM(y);
SHOWM(z);
return 0;
}
#else
PrintLine::queueCartesianMove(ALWAYS_CHECK_ENDSTOPS, pathOptimize);
#endif
return 1;
}
void Printer::setOrigin(float xOff, float yOff, float zOff) {
coordinateOffset[X_AXIS] = xOff;// offset from G92
coordinateOffset[Y_AXIS] = yOff;
coordinateOffset[Z_AXIS] = zOff;
}
/** Computes currentPosition from currentPositionSteps including correction for offset. */
void Printer::updateCurrentPosition(bool copyLastCmd) {
#if DUAL_X_AXIS && LAZY_DUAL_X_AXIS
if(!sledParked)
currentPosition[X_AXIS] = static_cast<float>(currentPositionSteps[X_AXIS]) * invAxisStepsPerMM[X_AXIS];
#else
currentPosition[X_AXIS] = static_cast<float>(currentPositionSteps[X_AXIS]) * invAxisStepsPerMM[X_AXIS];
#endif
currentPosition[Y_AXIS] = static_cast<float>(currentPositionSteps[Y_AXIS]) * invAxisStepsPerMM[Y_AXIS];
#if NONLINEAR_SYSTEM
currentPosition[Z_AXIS] = static_cast<float>(currentPositionSteps[Z_AXIS]) * invAxisStepsPerMM[Z_AXIS] - offsetZ2;
#else
currentPosition[Z_AXIS] = static_cast<float>(currentPositionSteps[Z_AXIS] - zCorrectionStepsIncluded) * invAxisStepsPerMM[Z_AXIS] - offsetZ2;
#endif
transformFromPrinter(currentPosition[X_AXIS], currentPosition[Y_AXIS], currentPosition[Z_AXIS],
currentPosition[X_AXIS], currentPosition[Y_AXIS], currentPosition[Z_AXIS]);
currentPosition[X_AXIS] -= Printer::offsetX; // Offset from active extruder or z probe
currentPosition[Y_AXIS] -= Printer::offsetY;
currentPosition[Z_AXIS] -= Printer::offsetZ;
if(copyLastCmd) {
lastCmdPos[X_AXIS] = currentPosition[X_AXIS];
lastCmdPos[Y_AXIS] = currentPosition[Y_AXIS];
lastCmdPos[Z_AXIS] = currentPosition[Z_AXIS];
}
}
void Printer::updateCurrentPositionSteps() {
float x_rotc, y_rotc, z_rotc;
transformToPrinter(currentPosition[X_AXIS] + Printer::offsetX, currentPosition[Y_AXIS] + Printer::offsetY, currentPosition[Z_AXIS] + Printer::offsetZ, x_rotc, y_rotc, z_rotc);
z_rotc += offsetZ2;
currentPositionSteps[X_AXIS] = static_cast<int32_t>(floor(x_rotc * axisStepsPerMM[X_AXIS] + 0.5f));
currentPositionSteps[Y_AXIS] = static_cast<int32_t>(floor(y_rotc * axisStepsPerMM[Y_AXIS] + 0.5f));
currentPositionSteps[Z_AXIS] = static_cast<int32_t>(floor(z_rotc * axisStepsPerMM[Z_AXIS] + 0.5f));
#if NONLINEAR_SYSTEM
transformCartesianStepsToDeltaSteps(Printer::currentPositionSteps, Printer::currentNonlinearPositionSteps);
#endif
#if DRIVE_SYSTEM != DELTA
zCorrectionStepsIncluded = 0;
#endif
}
/** \brief Sets the destination coordinates to values stored in com.
Extracts x,y,z,e,f from g-code considering active units. Converted result is stored in currentPosition and lastCmdPos. Converts
position to destinationSteps including rotation and offsets, excluding distortion correction (which gets added on move queuing).
\param com g-code with new destination position.
\return true if it is a move, false if no move results from coordinates.
*/
uint8_t Printer::setDestinationStepsFromGCode(GCode *com) {
register int32_t p;
float x, y, z;
bool posAllowed = true;
#if FEATURE_RETRACTION
if(com->hasNoXYZ() && com->hasE() && isAutoretract()) { // convert into auto retract
if(relativeCoordinateMode || relativeExtruderCoordinateMode) {
Extruder::current->retract(com->E < 0, false);
} else {
p = convertToMM(com->E * axisStepsPerMM[E_AXIS]); // target position
Extruder::current->retract(p < currentPositionSteps[E_AXIS], false);
}
return 0; // Fake no move so nothing gets added
}
#endif
#if MOVE_X_WHEN_HOMED == 1 || MOVE_Y_WHEN_HOMED == 1 || MOVE_Z_WHEN_HOMED == 1
if(!isNoDestinationCheck()) {
#if MOVE_X_WHEN_HOMED
if(!isXHomed())
com->unsetX();
#endif
#if MOVE_Y_WHEN_HOMED
if(!isYHomed())
com->unsetY();
#endif
#if MOVE_Z_WHEN_HOMED
if(!isZHomed())
com->unsetZ();
#endif
}
#endif
#if DISTORTION_CORRECTION == 0
if(!com->hasNoXYZ()) {
#endif
if(!relativeCoordinateMode) {
if(com->hasX()) lastCmdPos[X_AXIS] = currentPosition[X_AXIS] = convertToMM(com->X) - coordinateOffset[X_AXIS];
if(com->hasY()) lastCmdPos[Y_AXIS] = currentPosition[Y_AXIS] = convertToMM(com->Y) - coordinateOffset[Y_AXIS];
if(com->hasZ()) lastCmdPos[Z_AXIS] = currentPosition[Z_AXIS] = convertToMM(com->Z) - coordinateOffset[Z_AXIS];
} else {
if(com->hasX()) currentPosition[X_AXIS] = (lastCmdPos[X_AXIS] += convertToMM(com->X));
if(com->hasY()) currentPosition[Y_AXIS] = (lastCmdPos[Y_AXIS] += convertToMM(com->Y));
if(com->hasZ()) currentPosition[Z_AXIS] = (lastCmdPos[Z_AXIS] += convertToMM(com->Z));
}
transformToPrinter(lastCmdPos[X_AXIS] + Printer::offsetX, lastCmdPos[Y_AXIS] + Printer::offsetY, lastCmdPos[Z_AXIS] + Printer::offsetZ, x, y, z);
z += offsetZ2;
destinationSteps[X_AXIS] = static_cast<int32_t>(floor(x * axisStepsPerMM[X_AXIS] + 0.5f));
destinationSteps[Y_AXIS] = static_cast<int32_t>(floor(y * axisStepsPerMM[Y_AXIS] + 0.5f));
destinationSteps[Z_AXIS] = static_cast<int32_t>(floor(z * axisStepsPerMM[Z_AXIS] + 0.5f));
#if LAZY_DUAL_X_AXIS
sledParked = false;
#endif
posAllowed = com->hasNoXYZ() || Printer::isPositionAllowed(lastCmdPos[X_AXIS], lastCmdPos[Y_AXIS], lastCmdPos[Z_AXIS]);
#if DISTORTION_CORRECTION == 0
}
#endif
#if DUAL_X_AXIS && LAZY_DUAL_X_AXIS
if(sledParked) {
destinationSteps[X_AXIS] = currentPositionSteps[X_AXIS];
destinationSteps[Y_AXIS] = currentPositionSteps[Y_AXIS];
destinationSteps[Z_AXIS] = currentPositionSteps[Z_AXIS];
}
#endif
if(com->hasE() && !Printer::debugDryrun()) {
p = convertToMM(com->E * axisStepsPerMM[E_AXIS]);
if(relativeCoordinateMode || relativeExtruderCoordinateMode) {
if(
#if MIN_EXTRUDER_TEMP > 20
(Extruder::current->tempControl.currentTemperatureC < MIN_EXTRUDER_TEMP && !Printer::isColdExtrusionAllowed() && Extruder::current->tempControl.sensorType != 0) ||
#endif
fabs(com->E) * extrusionFactor > EXTRUDE_MAXLENGTH)
p = 0;
destinationSteps[E_AXIS] = currentPositionSteps[E_AXIS] + p;
} else {
if(
#if MIN_EXTRUDER_TEMP > 20
(Extruder::current->tempControl.currentTemperatureC < MIN_EXTRUDER_TEMP && !Printer::isColdExtrusionAllowed() && Extruder::current->tempControl.sensorType != 0) ||
#endif
fabs(p - currentPositionSteps[E_AXIS]) * extrusionFactor > EXTRUDE_MAXLENGTH * axisStepsPerMM[E_AXIS])
currentPositionSteps[E_AXIS] = p;
destinationSteps[E_AXIS] = p;
}
} else Printer::destinationSteps[E_AXIS] = Printer::currentPositionSteps[E_AXIS];
if(com->hasF() && com->F > 0.1) {
if(unitIsInches)
feedrate = com->F * 0.0042333f * (float)feedrateMultiply; // Factor is 25.5/60/100
else
feedrate = com->F * (float)feedrateMultiply * 0.00016666666f;
}
if(!posAllowed) {
currentPositionSteps[E_AXIS] = destinationSteps[E_AXIS];
return false; // ignore move
}
return !com->hasNoXYZ() || (com->hasE() && destinationSteps[E_AXIS] != currentPositionSteps[E_AXIS]); // ignore unproductive moves
}
void Printer::setup() {
HAL::stopWatchdog();
for(uint8_t i = 0; i < NUM_PWM; i++) pwm_pos[i] = 0;
#if FEATURE_CONTROLLER == CONTROLLER_VIKI
HAL::delayMilliseconds(100);
#endif // FEATURE_CONTROLLER
#if defined(MB_SETUP)
MB_SETUP;
#endif
#if UI_DISPLAY_TYPE != NO_DISPLAY
Com::selectLanguage(0); // just make sure we have a language in case someone uses it early
#endif
//HAL::delayMilliseconds(500); // add a delay at startup to give hardware time for initalization
#if defined(EEPROM_AVAILABLE) && defined(EEPROM_SPI_ALLIGATOR) && EEPROM_AVAILABLE == EEPROM_SPI_ALLIGATOR
HAL::spiBegin();
#endif
HAL::hwSetup();
EVENT_INITIALIZE_EARLY
#ifdef ANALYZER
// Channel->pin assignments
#if ANALYZER_CH0>=0
SET_OUTPUT(ANALYZER_CH0);
#endif
#if ANALYZER_CH1>=0
SET_OUTPUT(ANALYZER_CH1);
#endif
#if ANALYZER_CH2>=0
SET_OUTPUT(ANALYZER_CH2);
#endif
#if ANALYZER_CH3>=0
SET_OUTPUT(ANALYZER_CH3);
#endif
#if ANALYZER_CH4>=0
SET_OUTPUT(ANALYZER_CH4);
#endif
#if ANALYZER_CH5>=0
SET_OUTPUT(ANALYZER_CH5);
#endif
#if ANALYZER_CH6>=0
SET_OUTPUT(ANALYZER_CH6);
#endif
#if ANALYZER_CH7>=0
SET_OUTPUT(ANALYZER_CH7);
#endif
#endif
#if defined(ENABLE_POWER_ON_STARTUP) && ENABLE_POWER_ON_STARTUP && (PS_ON_PIN>-1)
SET_OUTPUT(PS_ON_PIN); //GND
WRITE(PS_ON_PIN, (POWER_INVERTING ? HIGH : LOW));
Printer::setPowerOn(true);
#else
#if PS_ON_PIN > -1
SET_OUTPUT(PS_ON_PIN); //GND
WRITE(PS_ON_PIN, (POWER_INVERTING ? LOW : HIGH));
Printer::setPowerOn(false);
#else
Printer::setPowerOn(true);
#endif
#endif
#if SDSUPPORT
//power to SD reader
#if SDPOWER > -1
SET_OUTPUT(SDPOWER);
WRITE(SDPOWER, HIGH);
#endif
#if defined(SDCARDDETECT) && SDCARDDETECT > -1
SET_INPUT(SDCARDDETECT);
PULLUP(SDCARDDETECT, HIGH);
#endif
#endif
//Initialize Step Pins
SET_OUTPUT(X_STEP_PIN);
SET_OUTPUT(Y_STEP_PIN);
SET_OUTPUT(Z_STEP_PIN);
endXYZSteps();
//Initialize Dir Pins
#if X_DIR_PIN > -1
SET_OUTPUT(X_DIR_PIN);
#endif
#if Y_DIR_PIN > -1
SET_OUTPUT(Y_DIR_PIN);
#endif
#if Z_DIR_PIN > -1
SET_OUTPUT(Z_DIR_PIN);
#endif
//Steppers default to disabled.
#if X_ENABLE_PIN > -1
SET_OUTPUT(X_ENABLE_PIN);
WRITE(X_ENABLE_PIN, !X_ENABLE_ON);
#endif
#if Y_ENABLE_PIN > -1
SET_OUTPUT(Y_ENABLE_PIN);
WRITE(Y_ENABLE_PIN, !Y_ENABLE_ON);
#endif
#if Z_ENABLE_PIN > -1
SET_OUTPUT(Z_ENABLE_PIN);
WRITE(Z_ENABLE_PIN, !Z_ENABLE_ON);
#endif
#if FEATURE_TWO_XSTEPPER || DUAL_X_AXIS
SET_OUTPUT(X2_STEP_PIN);
SET_OUTPUT(X2_DIR_PIN);
#if X2_ENABLE_PIN > -1
SET_OUTPUT(X2_ENABLE_PIN);
WRITE(X2_ENABLE_PIN, !X_ENABLE_ON);
#endif
#endif
#if FEATURE_TWO_YSTEPPER
SET_OUTPUT(Y2_STEP_PIN);
SET_OUTPUT(Y2_DIR_PIN);
#if Y2_ENABLE_PIN > -1
SET_OUTPUT(Y2_ENABLE_PIN);
WRITE(Y2_ENABLE_PIN, !Y_ENABLE_ON);
#endif
#endif
#if FEATURE_TWO_ZSTEPPER
SET_OUTPUT(Z2_STEP_PIN);
SET_OUTPUT(Z2_DIR_PIN);
#if Z2_ENABLE_PIN > -1
SET_OUTPUT(Z2_ENABLE_PIN);
WRITE(Z2_ENABLE_PIN, !Z_ENABLE_ON);
#endif
#endif
#if FEATURE_THREE_ZSTEPPER
SET_OUTPUT(Z3_STEP_PIN);
SET_OUTPUT(Z3_DIR_PIN);
#if Z3_ENABLE_PIN > -1
SET_OUTPUT(Z3_ENABLE_PIN);
WRITE(Z3_ENABLE_PIN, !Z_ENABLE_ON);
#endif
#endif
#if FEATURE_FOUR_ZSTEPPER
SET_OUTPUT(Z4_STEP_PIN);
SET_OUTPUT(Z4_DIR_PIN);
#if Z4_ENABLE_PIN > -1
SET_OUTPUT(Z4_ENABLE_PIN);
WRITE(Z4_ENABLE_PIN, !Z_ENABLE_ON);
#endif
#endif
#if defined(DOOR_PIN) && DOOR_PIN > -1
SET_INPUT(DOOR_PIN);
#if defined(DOOR_PULLUP) && DOOR_PULLUP
PULLUP(DOOR_PIN, HIGH);
#endif
#endif
Endstops::setup();
#if FEATURE_Z_PROBE && Z_PROBE_PIN>-1
SET_INPUT(Z_PROBE_PIN);
#if Z_PROBE_PULLUP
PULLUP(Z_PROBE_PIN, HIGH);
#endif
#endif // FEATURE_FEATURE_Z_PROBE
#if FAN_PIN > -1 && FEATURE_FAN_CONTROL
SET_OUTPUT(FAN_PIN);
WRITE(FAN_PIN, LOW);
#endif
#if FAN2_PIN > -1 && FEATURE_FAN2_CONTROL
SET_OUTPUT(FAN2_PIN);
WRITE(FAN2_PIN, LOW);
#endif
#if FAN_THERMO_PIN > -1
SET_OUTPUT(FAN_THERMO_PIN);
WRITE(FAN_THERMO_PIN, LOW);
#endif
#if FAN_BOARD_PIN>-1
SET_OUTPUT(FAN_BOARD_PIN);
WRITE(FAN_BOARD_PIN, LOW);
pwm_pos[PWM_BOARD_FAN] = BOARD_FAN_MIN_SPEED;
#endif
#if defined(EXT0_HEATER_PIN) && EXT0_HEATER_PIN>-1
SET_OUTPUT(EXT0_HEATER_PIN);
WRITE(EXT0_HEATER_PIN, HEATER_PINS_INVERTED);
#endif
#if defined(EXT1_HEATER_PIN) && EXT1_HEATER_PIN>-1 && NUM_EXTRUDER>1
SET_OUTPUT(EXT1_HEATER_PIN);
WRITE(EXT1_HEATER_PIN, HEATER_PINS_INVERTED);
#endif
#if defined(EXT2_HEATER_PIN) && EXT2_HEATER_PIN>-1 && NUM_EXTRUDER>2
SET_OUTPUT(EXT2_HEATER_PIN);
WRITE(EXT2_HEATER_PIN, HEATER_PINS_INVERTED);
#endif
#if defined(EXT3_HEATER_PIN) && EXT3_HEATER_PIN>-1 && NUM_EXTRUDER>3
SET_OUTPUT(EXT3_HEATER_PIN);
WRITE(EXT3_HEATER_PIN, HEATER_PINS_INVERTED);
#endif
#if defined(EXT4_HEATER_PIN) && EXT4_HEATER_PIN>-1 && NUM_EXTRUDER>4
SET_OUTPUT(EXT4_HEATER_PIN);
WRITE(EXT4_HEATER_PIN, HEATER_PINS_INVERTED);
#endif
#if defined(EXT5_HEATER_PIN) && EXT5_HEATER_PIN>-1 && NUM_EXTRUDER>5
SET_OUTPUT(EXT5_HEATER_PIN);
WRITE(EXT5_HEATER_PIN, HEATER_PINS_INVERTED);
#endif
#if defined(EXT0_EXTRUDER_COOLER_PIN) && EXT0_EXTRUDER_COOLER_PIN>-1
SET_OUTPUT(EXT0_EXTRUDER_COOLER_PIN);
WRITE(EXT0_EXTRUDER_COOLER_PIN, LOW);
#endif
#if defined(EXT1_EXTRUDER_COOLER_PIN) && EXT1_EXTRUDER_COOLER_PIN > -1 && NUM_EXTRUDER > 1
SET_OUTPUT(EXT1_EXTRUDER_COOLER_PIN);
WRITE(EXT1_EXTRUDER_COOLER_PIN, LOW);
#endif
#if defined(EXT2_EXTRUDER_COOLER_PIN) && EXT2_EXTRUDER_COOLER_PIN > -1 && NUM_EXTRUDER > 2
SET_OUTPUT(EXT2_EXTRUDER_COOLER_PIN);
WRITE(EXT2_EXTRUDER_COOLER_PIN, LOW);
#endif
#if defined(EXT3_EXTRUDER_COOLER_PIN) && EXT3_EXTRUDER_COOLER_PIN > -1 && NUM_EXTRUDER > 3
SET_OUTPUT(EXT3_EXTRUDER_COOLER_PIN);
WRITE(EXT3_EXTRUDER_COOLER_PIN, LOW);
#endif
#if defined(EXT4_EXTRUDER_COOLER_PIN) && EXT4_EXTRUDER_COOLER_PIN > -1 && NUM_EXTRUDER > 4
SET_OUTPUT(EXT4_EXTRUDER_COOLER_PIN);
WRITE(EXT4_EXTRUDER_COOLER_PIN, LOW);
#endif
#if defined(EXT5_EXTRUDER_COOLER_PIN) && EXT5_EXTRUDER_COOLER_PIN > -1 && NUM_EXTRUDER > 5
SET_OUTPUT(EXT5_EXTRUDER_COOLER_PIN);
WRITE(EXT5_EXTRUDER_COOLER_PIN, LOW);
#endif
// Initialize jam sensors
#if defined(EXT0_JAM_PIN) && EXT0_JAM_PIN > -1
SET_INPUT(EXT0_JAM_PIN);
PULLUP(EXT0_JAM_PIN, EXT0_JAM_PULLUP);
#endif // defined
#if defined(EXT1_JAM_PIN) && EXT1_JAM_PIN > -1
SET_INPUT(EXT1_JAM_PIN);
PULLUP(EXT1_JAM_PIN, EXT1_JAM_PULLUP);
#endif // defined
#if defined(EXT2_JAM_PIN) && EXT2_JAM_PIN > -1
SET_INPUT(EXT2_JAM_PIN);
PULLUP(EXT2_JAM_PIN, EXT2_JAM_PULLUP);
#endif // defined
#if defined(EXT3_JAM_PIN) && EXT3_JAM_PIN > -1
SET_INPUT(EXT3_JAM_PIN);
PULLUP(EXT3_JAM_PIN, EXT3_JAM_PULLUP);
#endif // defined
#if defined(EXT4_JAM_PIN) && EXT4_JAM_PIN > -1
SET_INPUT(EXT4_JAM_PIN);
PULLUP(EXT4_JAM_PIN, EXT4_JAM_PULLUP);
#endif // defined
#if defined(EXT5_JAM_PIN) && EXT5_JAM_PIN > -1
SET_INPUT(EXT5_JAM_PIN);
PULLUP(EXT5_JAM_PIN, EXT5_JAM_PULLUP);
#endif // defined
HAL::delayMilliseconds(1);
#if defined(EXT0_JAM_PIN) && EXT0_JAM_PIN > -1
extruder[0].jamLastSignal = READ(EXT0_JAM_PIN);
#endif // defined
#if defined(EXT1_JAM_PIN) && EXT1_JAM_PIN > -1
extruder[1].jamLastSignal = READ(EXT1_JAM_PIN);
#endif // defined
#if defined(EXT2_JAM_PIN) && EXT2_JAM_PIN > -1
extruder[2].jamLastSignal = READ(EXT2_JAM_PIN);
#endif // defined
#if defined(EXT3_JAM_PIN) && EXT3_JAM_PIN > -1
extruder[3].jamLastSignal = READ(EXT3_JAM_PIN);
#endif // defined
#if defined(EXT4_JAM_PIN) && EXT4_JAM_PIN > -1
extruder[4].jamLastSignal = READ(EXT4_JAM_PIN);
#endif // defined
#if defined(EXT5_JAM_PIN) && EXT5_JAM_PIN > -1
extruder[5].jamLastSignal = READ(EXT5_JAM_PIN);
#endif // defined
#if CASE_LIGHTS_PIN >= 0
SET_OUTPUT(CASE_LIGHTS_PIN);
WRITE(CASE_LIGHTS_PIN, CASE_LIGHT_DEFAULT_ON);
#endif // CASE_LIGHTS_PIN
#if defined(UI_VOLTAGE_LEVEL) && defined(EXP_VOLTAGE_LEVEL_PIN) && EXP_VOLTAGE_LEVEL_PIN >-1
SET_OUTPUT(EXP_VOLTAGE_LEVEL_PIN);
WRITE(EXP_VOLTAGE_LEVEL_PIN, UI_VOLTAGE_LEVEL);
#endif // UI_VOLTAGE_LEVEL
#if defined(SUPPORT_LASER) && SUPPORT_LASER
LaserDriver::initialize();
#endif // defined
#if defined(SUPPORT_CNC) && SUPPORT_CNC
CNCDriver::initialize();
#endif // defined
#if GANTRY && !defined(FAST_COREXYZ)
Printer::motorX = 0;
Printer::motorYorZ = 0;
#endif
#ifdef RED_BLUE_STATUS_LEDS
SET_OUTPUT(RED_STATUS_LED);
SET_OUTPUT(BLUE_STATUS_LED);
WRITE(BLUE_STATUS_LED, HIGH);
WRITE(RED_STATUS_LED, LOW);
#endif // RED_BLUE_STATUS_LEDS
#if defined(DRV_TMC2130)
// TMC2130 motor drivers
#if TMC2130_ON_X
Printer::tmc_driver_x = new TMC2130Stepper(X_ENABLE_PIN, X_DIR_PIN, X_STEP_PIN, TMC2130_X_CS_PIN);
configTMC2130(Printer::tmc_driver_x, TMC2130_STEALTHCHOP_X, TMC2130_STALLGUARD_X,
TMC2130_PWM_AMPL_X, TMC2130_PWM_GRAD_X, TMC2130_PWM_AUTOSCALE_X, TMC2130_PWM_FREQ_X);
#endif
#if TMC2130_ON_Y > 0
Printer::tmc_driver_y = new TMC2130Stepper(Y_ENABLE_PIN, Y_DIR_PIN, Y_STEP_PIN, TMC2130_Y_CS_PIN);
configTMC2130(Printer::tmc_driver_y, TMC2130_STEALTHCHOP_Y, TMC2130_STALLGUARD_Y,
TMC2130_PWM_AMPL_Y, TMC2130_PWM_GRAD_Y, TMC2130_PWM_AUTOSCALE_Y, TMC2130_PWM_FREQ_Y);
#endif
#if TMC2130_ON_Z > 0
Printer::tmc_driver_z = new TMC2130Stepper(Z_ENABLE_PIN, Z_DIR_PIN, Z_STEP_PIN, TMC2130_Z_CS_PIN);
configTMC2130(Printer::tmc_driver_z, TMC2130_STEALTHCHOP_Z, TMC2130_STALLGUARD_Z,
TMC2130_PWM_AMPL_Z, TMC2130_PWM_GRAD_Z, TMC2130_PWM_AUTOSCALE_Z, TMC2130_PWM_FREQ_Z);
#endif
#if TMC2130_ON_EXT0 > 0
Printer::tmc_driver_e0 = new TMC2130Stepper(EXT0_ENABLE_PIN, EXT0_DIR_PIN, EXT0_STEP_PIN, TMC2130_EXT0_CS_PIN);
configTMC2130(Printer::tmc_driver_e0, TMC2130_STEALTHCHOP_EXT0, TMC2130_STALLGUARD_EXT0,
TMC2130_PWM_AMPL_EXT0, TMC2130_PWM_GRAD_EXT0, TMC2130_PWM_AUTOSCALE_EXT0, TMC2130_PWM_FREQ_EXT0);
#endif
#if TMC2130_ON_EXT1 > 0
Printer::tmc_driver_e1 = new TMC2130Stepper(EXT1_ENABLE_PIN, EXT1_DIR_PIN, EXT1_STEP_PIN, TMC2130_EXT1_CS_PIN);
configTMC2130(Printer::tmc_driver_e1, TMC2130_STEALTHCHOP_EXT1, TMC2130_STALLGUARD_EXT1,
TMC2130_PWM_AMPL_EXT1, TMC2130_PWM_GRAD_EXT1, TMC2130_PWM_AUTOSCALE_EXT1, TMC2130_PWM_FREQ_EXT1);
#endif
#if TMC2130_ON_EXT2 > 0
Printer::tmc_driver_e2 = new TMC2130Stepper(EXT2_ENABLE_PIN, EXT2_DIR_PIN, EXT2_STEP_PIN, TMC2130_EXT2_CS_PIN);
configTMC2130(Printer::tmc_driver_e2, TMC2130_STEALTHCHOP_EXT2, TMC2130_STALLGUARD_EXT2,
TMC2130_PWM_AMPL_EXT2, TMC2130_PWM_GRAD_EXT2, TMC2130_PWM_AUTOSCALE_EXT2, TMC2130_PWM_FREQ_EXT2);
#endif
#endif // DRV_TMC2130
#if STEPPER_CURRENT_CONTROL != CURRENT_CONTROL_MANUAL
motorCurrentControlInit(); // Set current if it is firmware controlled
#endif
#if defined(NUM_MOTOR_DRIVERS) && NUM_MOTOR_DRIVERS > 0
initializeAllMotorDrivers();
#endif // defined
microstepInit();
#if FEATURE_AUTOLEVEL
resetTransformationMatrix(true);
#endif // FEATURE_AUTOLEVEL
feedrate = 50; ///< Current feedrate in mm/s.
feedrateMultiply = 100;
extrudeMultiply = 100;
lastCmdPos[X_AXIS] = lastCmdPos[Y_AXIS] = lastCmdPos[Z_AXIS] = 0;
#if USE_ADVANCE
#if ENABLE_QUADRATIC_ADVANCE
advanceExecuted = 0;
#endif
advanceStepsSet = 0;
#endif
maxJerk = MAX_JERK;
#if DRIVE_SYSTEM != DELTA
maxZJerk = MAX_ZJERK;
#endif
offsetX = offsetY = offsetZ = 0;
interval = 5000;
stepsPerTimerCall = 1;
msecondsPrinting = 0;
filamentPrinted = 0;
flag0 = PRINTER_FLAG0_STEPPER_DISABLED;
xLength = X_MAX_LENGTH;
yLength = Y_MAX_LENGTH;
zLength = Z_MAX_LENGTH;
xMin = X_MIN_POS;
yMin = Y_MIN_POS;
zMin = Z_MIN_POS;
#if DRIVE_SYSTEM == DELTA
radius0 = ROD_RADIUS;
#endif
#if ENABLE_BACKLASH_COMPENSATION
backlashX = X_BACKLASH;
backlashY = Y_BACKLASH;
backlashZ = Z_BACKLASH;
backlashDir = 0;
#endif
#if USE_ADVANCE
extruderStepsNeeded = 0;
#endif
#if (MOTHERBOARD == 502)
SET_INPUT(FTDI_COM_RESET_PIN);
SET_INPUT(ESP_WIFI_MODULE_COM);
SET_INPUT(MOTOR_FAULT_PIN);
SET_INPUT(MOTOR_FAULT_PIGGY_PIN);
#endif //(MOTHERBOARD == 501) || (MOTHERBOARD == 502)
EEPROM::initBaudrate();
HAL::serialSetBaudrate(baudrate);
Com::printFLN(Com::tStart);
HAL::showStartReason();
Extruder::initExtruder();
// sets auto leveling in eeprom init
EEPROM::init(); // Read settings from eeprom if wanted
UI_INITIALIZE;
for(uint8_t i = 0; i < E_AXIS_ARRAY; i++) {
currentPositionSteps[i] = 0;
}
currentPosition[X_AXIS] = currentPosition[Y_AXIS] = currentPosition[Z_AXIS] = 0.0;
//Commands::printCurrentPosition();
#if DISTORTION_CORRECTION
distortion.init();
#endif // DISTORTION_CORRECTION
updateDerivedParameter();
Commands::checkFreeMemory();
Commands::writeLowestFreeRAM();
HAL::setupTimer();
#if FEATURE_WATCHDOG
HAL::startWatchdog();
#endif // FEATURE_WATCHDOG
#if SDSUPPORT
sd.mount();
#endif
#if NONLINEAR_SYSTEM
transformCartesianStepsToDeltaSteps(Printer::currentPositionSteps, Printer::currentNonlinearPositionSteps);
#if DELTA_HOME_ON_POWER
homeAxis(true, true, true);
#endif
setAutoretract(EEPROM_BYTE(AUTORETRACT_ENABLED));
Commands::printCurrentPosition();
#endif // DRIVE_SYSTEM
Extruder::selectExtruderById(0);
#if FEATURE_SERVO // set servos to neutral positions at power_up
#if defined(SERVO0_NEUTRAL_POS) && SERVO0_NEUTRAL_POS >= 500
HAL::servoMicroseconds(0, SERVO0_NEUTRAL_POS, 1000);
#endif
#if defined(SERVO1_NEUTRAL_POS) && SERVO1_NEUTRAL_POS >= 500
HAL::servoMicroseconds(1, SERVO1_NEUTRAL_POS, 1000);
#endif
#if defined(SERVO2_NEUTRAL_POS) && SERVO2_NEUTRAL_POS >= 500
HAL::servoMicroseconds(2, SERVO2_NEUTRAL_POS, 1000);
#endif
#if defined(SERVO3_NEUTRAL_POS) && SERVO3_NEUTRAL_POS >= 500
HAL::servoMicroseconds(3, SERVO3_NEUTRAL_POS, 1000);
#endif
#endif
EVENT_INITIALIZE;
#ifdef STARTUP_GCODE
GCode::executeFString(Com::tStartupGCode);
#endif
#if EEPROM_MODE != 0 && UI_DISPLAY_TYPE != NO_DISPLAY
if(EEPROM::getStoredLanguage() == 254) {
Com::printFLN(PSTR("Needs language selection"));
uid.showLanguageSelectionWizard();
}
#endif // EEPROM_MODE
}
void Printer::defaultLoopActions() {
Commands::checkForPeriodicalActions(true); //check heater every n milliseconds
UI_MEDIUM; // do check encoder
millis_t curtime = HAL::timeInMilliseconds();
if(PrintLine::hasLines() || isMenuMode(MENU_MODE_SD_PRINTING + MENU_MODE_PAUSED))
previousMillisCmd = curtime;
else {
curtime -= previousMillisCmd;
if(maxInactiveTime != 0 && curtime > maxInactiveTime )
Printer::kill(false);
else
Printer::setAllKilled(false); // prevent repeated kills
if(stepperInactiveTime != 0 && curtime > stepperInactiveTime )
Printer::kill(true);
}
#if SDCARDDETECT > -1 && SDSUPPORT
sd.automount();
#endif
#if defined(EEPROM_AVAILABLE) && EEPROM_AVAILABLE == EEPROM_SDCARD
HAL::syncEEPROM();
#endif
DEBUG_MEMORY;
}
void Printer::MemoryPosition() {
Commands::waitUntilEndOfAllMoves();
updateCurrentPosition(false);
realPosition(memoryX, memoryY, memoryZ);
memoryE = currentPositionSteps[E_AXIS] * invAxisStepsPerMM[E_AXIS];
memoryF = feedrate;
}
void Printer::GoToMemoryPosition(bool x, bool y, bool z, bool e, float feed) {
if(memoryF < 0) return; // Not stored before call, so we ignore it
bool all = !(x || y || z);
moveToReal((all || x ? (lastCmdPos[X_AXIS] = memoryX) : IGNORE_COORDINATE)
, (all || y ? (lastCmdPos[Y_AXIS] = memoryY) : IGNORE_COORDINATE)
, (all || z ? (lastCmdPos[Z_AXIS] = memoryZ) : IGNORE_COORDINATE)
, (e ? memoryE : IGNORE_COORDINATE),
feed);
feedrate = memoryF;
updateCurrentPosition(false);
}
#if DRIVE_SYSTEM == DELTA
void Printer::deltaMoveToTopEndstops(float feedrate) {
for (fast8_t i = 0; i < 3; i++)
Printer::currentPositionSteps[i] = 0;
Printer::stepsRemainingAtXHit = -1;
Printer::stepsRemainingAtYHit = -1;
Printer::stepsRemainingAtZHit = -1;
setHoming(true);
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
PrintLine::moveRelativeDistanceInSteps(0, 0, (zMaxSteps + EEPROM::deltaDiagonalRodLength()*axisStepsPerMM[Z_AXIS]) * 1.5, 0, feedrate, true, true);
offsetX = offsetY = offsetZ = offsetZ2 = 0;
setHoming(false);
}
void Printer::homeXAxis() {
destinationSteps[X_AXIS] = 0;
if (!PrintLine::queueNonlinearMove(true, false, false)) {
Com::printWarningFLN(PSTR("homeXAxis / queueDeltaMove returns error"));
}
}
void Printer::homeYAxis() {
Printer::destinationSteps[Y_AXIS] = 0;
if (!PrintLine::queueNonlinearMove(true, false, false)) {
Com::printWarningFLN(PSTR("homeYAxis / queueDeltaMove returns error"));
}
}
void Printer::homeZAxis() { // Delta z homing
bool homingSuccess = false;
Endstops::resetAccumulator();
deltaMoveToTopEndstops(Printer::homingFeedrate[Z_AXIS]);
// New safe homing routine by Kyrre Aalerud
// This method will safeguard against sticky endstops such as may be gotten cheaply from china.
// This can lead to head crashes and even fire, thus a safer algorithm to ensure the endstops actually respond as expected.
//Endstops::report();
// Check that all endstops (XYZ) were hit
Endstops::fillFromAccumulator();
if (Endstops::xMax() && Endstops::yMax() && Endstops::zMax()) {
// Back off for retest
PrintLine::moveRelativeDistanceInSteps(0, 0, axisStepsPerMM[Z_AXIS] * -ENDSTOP_Z_BACK_MOVE, 0, Printer::homingFeedrate[Z_AXIS] / ENDSTOP_X_RETEST_REDUCTION_FACTOR, true, true);
//Endstops::report();
// Check for proper release of all (XYZ) endstops
if (!(Endstops::xMax() || Endstops::yMax() || Endstops::zMax())) {
// Rehome with reduced speed
Endstops::resetAccumulator();
deltaMoveToTopEndstops(Printer::homingFeedrate[Z_AXIS] / ENDSTOP_Z_RETEST_REDUCTION_FACTOR);
Endstops::fillFromAccumulator();
//Endstops::report();
// Check that all endstops (XYZ) were hit again
if (Endstops::xMax() && Endstops::yMax() && Endstops::zMax()) {
homingSuccess = true; // Assume success in case there is no back move
#if defined(ENDSTOP_Z_BACK_ON_HOME)
if(ENDSTOP_Z_BACK_ON_HOME > 0) {
PrintLine::moveRelativeDistanceInSteps(0, 0, axisStepsPerMM[Z_AXIS] * -ENDSTOP_Z_BACK_ON_HOME, 0, homingFeedrate[Z_AXIS], true, true);
//Endstops::report();
// Check for missing release of any (XYZ) endstop
if (Endstops::xMax() || Endstops::yMax() || Endstops::zMax()) {
homingSuccess = false; // Reset success flag
}
}
#endif
}
}
}
// Check if homing failed. If so, request pause!
if (!homingSuccess) {
setXHomed(false);
setYHomed(false);
setZHomed(false);
GCodeSource::printAllFLN(PSTR("RequestPause:Homing failed!"));
} else {
setXHomed(true);
setYHomed(true);
setZHomed(true);
}
// Correct different end stop heights
// These can be adjusted by two methods. You can use offsets stored by determining the center
// or you can use the xyzMinSteps from G100 calibration. Both have the same effect but only one
// should be measured as both have the same effect.
long dx = -xMinSteps - EEPROM::deltaTowerXOffsetSteps();
long dy = -yMinSteps - EEPROM::deltaTowerYOffsetSteps();
long dz = -zMinSteps - EEPROM::deltaTowerZOffsetSteps();
long dm = RMath::min(dx, dy, dz);
//Com::printFLN(Com::tTower1,dx);
//Com::printFLN(Com::tTower2,dy);
//Com::printFLN(Com::tTower3,dz);
dx -= dm; // now all dxyz are positive
dy -= dm;
dz -= dm;
currentPositionSteps[X_AXIS] = 0; // here we should be
currentPositionSteps[Y_AXIS] = 0;
currentPositionSteps[Z_AXIS] = zMaxSteps;
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
currentNonlinearPositionSteps[A_TOWER] -= dx;
currentNonlinearPositionSteps[B_TOWER] -= dy;
currentNonlinearPositionSteps[C_TOWER] -= dz;
PrintLine::moveRelativeDistanceInSteps(0, 0, dm, 0, homingFeedrate[Z_AXIS], true, false);
currentPositionSteps[X_AXIS] = 0; // now we are really here
currentPositionSteps[Y_AXIS] = 0;
currentPositionSteps[Z_AXIS] = zMaxSteps - zBedOffset * axisStepsPerMM[Z_AXIS]; // Extruder is now exactly in the delta center
coordinateOffset[X_AXIS] = 0;
coordinateOffset[Y_AXIS] = 0;
coordinateOffset[Z_AXIS] = 0;
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
realDeltaPositionSteps[A_TOWER] = currentNonlinearPositionSteps[A_TOWER];
realDeltaPositionSteps[B_TOWER] = currentNonlinearPositionSteps[B_TOWER];
realDeltaPositionSteps[C_TOWER] = currentNonlinearPositionSteps[C_TOWER];
//maxDeltaPositionSteps = currentDeltaPositionSteps[X_AXIS];
#if defined(ENDSTOP_Z_BACK_ON_HOME)
if(ENDSTOP_Z_BACK_ON_HOME > 0)
maxDeltaPositionSteps += axisStepsPerMM[Z_AXIS] * ENDSTOP_Z_BACK_ON_HOME;
#endif
Extruder::selectExtruderById(Extruder::current->id);
#if FEATURE_BABYSTEPPING
Printer::zBabysteps = 0;
#endif
}
// This home axis is for delta
void Printer::homeAxis(bool xaxis, bool yaxis, bool zaxis) { // Delta homing code
bool nocheck = isNoDestinationCheck();
setNoDestinationCheck(true);
#if defined(SUPPORT_LASER) && SUPPORT_LASER
bool oldLaser = LaserDriver::laserOn;
LaserDriver::laserOn = false;
#endif
bool autoLevel = isAutolevelActive();
setAutolevelActive(false);
if (!(X_MAX_PIN > -1 && Y_MAX_PIN > -1 && Z_MAX_PIN > -1
&& MAX_HARDWARE_ENDSTOP_X && MAX_HARDWARE_ENDSTOP_Y && MAX_HARDWARE_ENDSTOP_Z)) {
Com::printErrorFLN(PSTR("Hardware setup inconsistent. Delta cannot home without max endstops."));
}
// The delta has to have home capability to zero and set position,
// so the redundant check is only an opportunity to
// gratuitously fail due to incorrect settings.
// The following movements would be meaningless unless it was zeroed for example.
UI_STATUS_UPD_F(Com::translatedF(UI_TEXT_HOME_DELTA_ID));
// Homing Z axis means that you must home X and Y
EVENT_BEFORE_Z_HOME;
homeZAxis();
moveToReal(0, 0, Printer::zLength - zBedOffset, IGNORE_COORDINATE, homingFeedrate[Z_AXIS]); // Move to designed coordinates including translation
updateCurrentPosition(true);
updateHomedAll();
UI_CLEAR_STATUS
Commands::printCurrentPosition();
setAutolevelActive(autoLevel);
#if defined(SUPPORT_LASER) && SUPPORT_LASER
LaserDriver::laserOn = oldLaser;
#endif
Printer::updateCurrentPosition();
setNoDestinationCheck(nocheck);
}
#else
#if DRIVE_SYSTEM == TUGA // Tuga printer homing
void Printer::homeXAxis() {
long steps;
if ((MIN_HARDWARE_ENDSTOP_X && X_MIN_PIN > -1 && X_HOME_DIR == -1 && MIN_HARDWARE_ENDSTOP_Y && Y_MIN_PIN > -1 && Y_HOME_DIR == -1) ||
(MAX_HARDWARE_ENDSTOP_X && X_MAX_PIN > -1 && X_HOME_DIR == 1 && MAX_HARDWARE_ENDSTOP_Y && Y_MAX_PIN > -1 && Y_HOME_DIR == 1)) {
long offX = 0, offY = 0;
#if NUM_EXTRUDER>1
for(uint8_t i = 0; i < NUM_EXTRUDER; i++) {
#if X_HOME_DIR < 0
offX = RMath::max(offX, extruder[i].xOffset);
offY = RMath::max(offY, extruder[i].yOffset);
#else
offX = RMath::min(offX, extruder[i].xOffset);
offY = RMath::min(offY, extruder[i].yOffset);
#endif
}
// Reposition extruder that way, that all extruders can be selected at home pos.
#endif
UI_STATUS_UPD(UI_TEXT_HOME_X);
steps = (Printer::xMaxSteps - Printer::xMinSteps) * X_HOME_DIR;
currentPositionSteps[X_AXIS] = -steps;
currentPositionSteps[Y_AXIS] = 0;
setHoming(true);
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
PrintLine::moveRelativeDistanceInSteps(2 * steps, 0, 0, 0, homingFeedrate[X_AXIS], true, true);
currentPositionSteps[X_AXIS] = (X_HOME_DIR == -1) ? xMinSteps - offX : xMaxSteps + offX;
currentPositionSteps[Y_AXIS] = 0; //(Y_HOME_DIR == -1) ? yMinSteps-offY : yMaxSteps+offY;
//PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS]*-ENDSTOP_X_BACK_MOVE * X_HOME_DIR,axisStepsPerMM[Y_AXIS]*-ENDSTOP_X_BACK_MOVE * Y_HOME_DIR,0,0,homingFeedrate[X_AXIS]/ENDSTOP_X_RETEST_REDUCTION_FACTOR,true,false);
// PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS]*2*ENDSTOP_X_BACK_MOVE * X_HOME_DIR,axisStepsPerMM[Y_AXIS]*2*ENDSTOP_X_BACK_MOVE * Y_HOME_DIR,0,0,homingFeedrate[X_AXIS]/ENDSTOP_X_RETEST_REDUCTION_FACTOR,true,true);
PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS] * -ENDSTOP_X_BACK_MOVE * X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS] / ENDSTOP_X_RETEST_REDUCTION_FACTOR, true, false);
PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS] * 2 * ENDSTOP_X_BACK_MOVE * X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS] / ENDSTOP_X_RETEST_REDUCTION_FACTOR, true, true);
setHoming(false);
#if defined(ENDSTOP_X_BACK_ON_HOME)
if(ENDSTOP_X_BACK_ON_HOME > 0)
PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS] * -ENDSTOP_X_BACK_ON_HOME * X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS], true, false);
// PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS]*-ENDSTOP_X_BACK_ON_HOME * X_HOME_DIR,axisStepsPerMM[Y_AXIS]*-ENDSTOP_Y_BACK_ON_HOME * Y_HOME_DIR,0,0,homingFeedrate[X_AXIS],true,false);
#endif
currentPositionSteps[X_AXIS] = (X_HOME_DIR == -1) ? xMinSteps - offX : xMaxSteps + offX;
currentPositionSteps[Y_AXIS] = 0; //(Y_HOME_DIR == -1) ? yMinSteps-offY : yMaxSteps+offY;
coordinateOffset[X_AXIS] = 0;
coordinateOffset[Y_AXIS] = 0;
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
#if NUM_EXTRUDER>1
PrintLine::moveRelativeDistanceInSteps((Extruder::current->xOffset - offX) * X_HOME_DIR, (Extruder::current->yOffset - offY) * Y_HOME_DIR, 0, 0, homingFeedrate[X_AXIS], true, false);
#endif
setXHomed(true);
setYHomed(true);
}
}
void Printer::homeYAxis() {
// Dummy function x and y homing must occur together
}
#else // Cartesian printer
void Printer::homeXAxis() {
#if defined(SENSORLESS_HOMING) && TMC2130_ON_X
while(!Printer::tmc_driver_x->stst()); // Wait for motor stand-still
uint32_t coolstep_speed = Printer::tmc_driver_x->coolstep_min_speed();
uint32_t stealth_max_sp = Printer::tmc_driver_x->stealth_max_speed();
bool stealth_state = Printer::tmc_driver_x->stealthChop();
Printer::tmcPrepareHoming(Printer::tmc_driver_x, TMC2130_TCOOLTHRS_X);
#endif
bool nocheck = isNoDestinationCheck();
setNoDestinationCheck(true);
long steps;
UI_STATUS_UPD_F(Com::translatedF(UI_TEXT_HOME_X_ID));
Commands::waitUntilEndOfAllMoves();
setHoming(true);
#if DUAL_X_AXIS && NUM_EXTRUDER == 2
Extruder *curExtruder = Extruder::current;
Extruder::current = &extruder[0];
steps = (Printer::xMaxSteps - Printer::xMinSteps);
currentPositionSteps[X_AXIS] = steps;
PrintLine::moveRelativeDistanceInSteps(-2 * steps * -X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS], true, true); // first contact
PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS] * ENDSTOP_X_BACK_MOVE * -X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS], true, false); // back move
PrintLine::moveRelativeDistanceInSteps(-axisStepsPerMM[X_AXIS] * 2 * ENDSTOP_X_BACK_MOVE * -X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS] / ENDSTOP_X_RETEST_REDUCTION_FACTOR, true, true); // final contact
#if defined(ENDSTOP_X_BACK_ON_HOME)
if(ENDSTOP_X_BACK_ON_HOME > 0)
PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS] * ENDSTOP_X_BACK_ON_HOME * -X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS], true, false);
#endif
Extruder::current = &extruder[1];
currentPositionSteps[X_AXIS] = -steps;
PrintLine::moveRelativeDistanceInSteps(2 * steps * -X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS], true, true);
PrintLine::moveRelativeDistanceInSteps(-axisStepsPerMM[X_AXIS] * ENDSTOP_X_BACK_MOVE * -X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS], true, false); // back move
PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS] * 2 * ENDSTOP_X_BACK_MOVE * -X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS] / ENDSTOP_X_RETEST_REDUCTION_FACTOR, true, true);
#if defined(ENDSTOP_X_BACK_ON_HOME)
if(ENDSTOP_X_BACK_ON_HOME > 0)
PrintLine::moveRelativeDistanceInSteps(-axisStepsPerMM[X_AXIS] * ENDSTOP_X_BACK_ON_HOME * -X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS], true, false);
#endif
Extruder::current = curExtruder;
#if LAZY_DUAL_X_AXIS
currentPositionSteps[X_AXIS] = xMinSteps + Extruder::current->xOffset;
sledParked = true;
currentPosition[X_AXIS] = lastCmdPos[X_AXIS] = xMin;
#else
// Now position current extrude on x = 0
PrintLine::moveRelativeDistanceInSteps(-Extruder::current->xOffset, 0, 0, 0, homingFeedrate[X_AXIS], true, true);
currentPositionSteps[X_AXIS] = xMinSteps;
#endif // LAZY_DUAL_X_AXIS
updateCurrentPosition(false);
offsetX = 0;
setXHomed(true);
#else // DUAL_AXIS
if ((MIN_HARDWARE_ENDSTOP_X && X_MIN_PIN > -1 && X_HOME_DIR == -1) || (MAX_HARDWARE_ENDSTOP_X && X_MAX_PIN > -1 && X_HOME_DIR == 1)) {
coordinateOffset[X_AXIS] = 0;
long offX = 0;
#if NUM_EXTRUDER > 1
for(uint8_t i = 0; i < NUM_EXTRUDER; i++)
#if X_HOME_DIR < 0
offX = RMath::max(offX, extruder[i].xOffset);
#else
offX = RMath::min(offX, extruder[i].xOffset);
#endif
// Reposition extruder that way, that all extruders can be selected at home position.
#endif // NUM_EXTRUDER > 1
steps = (Printer::xMaxSteps - Printer::xMinSteps) * X_HOME_DIR;
currentPositionSteps[X_AXIS] = -steps;
#if NONLINEAR_SYSTEM
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
#endif
PrintLine::moveRelativeDistanceInSteps(2 * steps, 0, 0, 0, homingFeedrate[X_AXIS], true, true);
currentPositionSteps[X_AXIS] = (X_HOME_DIR == -1) ? xMinSteps - offX : xMaxSteps + offX;
#if NONLINEAR_SYSTEM
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
#endif
PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS] * -ENDSTOP_X_BACK_MOVE * X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS] / ENDSTOP_X_RETEST_REDUCTION_FACTOR, true, false);
PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS] * 2 * ENDSTOP_X_BACK_MOVE * X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS] / ENDSTOP_X_RETEST_REDUCTION_FACTOR, true, true);
#if defined(ENDSTOP_X_BACK_ON_HOME)
if(ENDSTOP_X_BACK_ON_HOME > 0)
PrintLine::moveRelativeDistanceInSteps(axisStepsPerMM[X_AXIS] * -ENDSTOP_X_BACK_ON_HOME * X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS], true, true);
#endif
currentPositionSteps[X_AXIS] = (X_HOME_DIR == -1) ? xMinSteps - offX : xMaxSteps + offX;
#if NONLINEAR_SYSTEM
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
#endif
#if NUM_EXTRUDER > 1
#if X_HOME_DIR < 0
PrintLine::moveRelativeDistanceInSteps((Extruder::current->xOffset - offX) * X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS], true, true);
#else
PrintLine::moveRelativeDistanceInSteps(-(Extruder::current->xOffset - offX) * X_HOME_DIR, 0, 0, 0, homingFeedrate[X_AXIS], true, true);
#endif
#endif
setXHomed(true);
}
#endif // ELSE dual x axis
setNoDestinationCheck(nocheck);
setHoming(false);
#if defined(SENSORLESS_HOMING) && TMC2130_ON_X
while(!Printer::tmc_driver_x->stst()); // Wait for motor stand-still
Printer::tmc_driver_x->coolstep_min_speed(coolstep_speed);
Printer::tmc_driver_x->stealth_max_speed(stealth_max_sp);
Printer::tmc_driver_x->stealthChop(stealth_state);
#endif
}
void Printer::homeYAxis() {
#if defined(SENSORLESS_HOMING) && TMC2130_ON_Y
while(!Printer::tmc_driver_y->stst()); // Wait for motor stand-still
uint32_t coolstep_speed = Printer::tmc_driver_y->coolstep_min_speed();
uint32_t stealth_max_sp = Printer::tmc_driver_y->stealth_max_speed();
bool stealth_state = Printer::tmc_driver_y->stealthChop();
Printer::tmcPrepareHoming(Printer::tmc_driver_y, TMC2130_TCOOLTHRS_Y);
#endif
long steps;
if ((MIN_HARDWARE_ENDSTOP_Y && Y_MIN_PIN > -1 && Y_HOME_DIR == -1) || (MAX_HARDWARE_ENDSTOP_Y && Y_MAX_PIN > -1 && Y_HOME_DIR == 1)) {
coordinateOffset[Y_AXIS] = 0;
long offY = 0;
#if NUM_EXTRUDER > 1
for(uint8_t i = 0; i < NUM_EXTRUDER; i++)
#if Y_HOME_DIR < 0
offY = RMath::max(offY, extruder[i].yOffset);
#else
offY = RMath::min(offY, extruder[i].yOffset);
#endif
// Reposition extruder that way, that all extruders can be selected at home pos.
#endif
UI_STATUS_UPD_F(Com::translatedF(UI_TEXT_HOME_Y_ID));
steps = (yMaxSteps - Printer::yMinSteps) * Y_HOME_DIR;
currentPositionSteps[Y_AXIS] = -steps;
setHoming(true);
#if NONLINEAR_SYSTEM
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
#endif
PrintLine::moveRelativeDistanceInSteps(0, 2 * steps, 0, 0, homingFeedrate[Y_AXIS], true, true);
currentPositionSteps[Y_AXIS] = (Y_HOME_DIR == -1) ? yMinSteps - offY : yMaxSteps + offY;
#if NONLINEAR_SYSTEM
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
#endif
PrintLine::moveRelativeDistanceInSteps(0, axisStepsPerMM[Y_AXIS] * -ENDSTOP_Y_BACK_MOVE * Y_HOME_DIR, 0, 0, homingFeedrate[Y_AXIS] / ENDSTOP_X_RETEST_REDUCTION_FACTOR, true, false);
PrintLine::moveRelativeDistanceInSteps(0, axisStepsPerMM[Y_AXIS] * 2 * ENDSTOP_Y_BACK_MOVE * Y_HOME_DIR, 0, 0, homingFeedrate[Y_AXIS] / ENDSTOP_X_RETEST_REDUCTION_FACTOR, true, true);
setHoming(false);
#if defined(ENDSTOP_Y_BACK_ON_HOME)
if(ENDSTOP_Y_BACK_ON_HOME > 0)
PrintLine::moveRelativeDistanceInSteps(0, axisStepsPerMM[Y_AXIS] * -ENDSTOP_Y_BACK_ON_HOME * Y_HOME_DIR, 0, 0, homingFeedrate[Y_AXIS], true, false);
#endif
currentPositionSteps[Y_AXIS] = (Y_HOME_DIR == -1) ? yMinSteps - offY : yMaxSteps + offY;
#if NONLINEAR_SYSTEM
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
#endif
#if NUM_EXTRUDER > 1
#if Y_HOME_DIR < 0
PrintLine::moveRelativeDistanceInSteps(0, (Extruder::current->yOffset - offY) * Y_HOME_DIR, 0, 0, homingFeedrate[Y_AXIS], true, false);
#else
PrintLine::moveRelativeDistanceInSteps(0, -(Extruder::current->yOffset - offY) * Y_HOME_DIR, 0, 0, homingFeedrate[Y_AXIS], true, false);
#endif
#endif
setYHomed(true);
}
#if defined(SENSORLESS_HOMING) && TMC2130_ON_Y
while(!Printer::tmc_driver_y->stst()); // Wait for motor stand-still
Printer::tmc_driver_y->coolstep_min_speed(coolstep_speed);
Printer::tmc_driver_y->stealth_max_speed(stealth_max_sp);
Printer::tmc_driver_y->stealthChop(stealth_state);
#endif
}
#endif
/** \brief homes z axis.
Homing z axis is the most complicated homing part as it needs to correct for several parameters depending on rotation correction,
distortion correction, position, homing direction, sensor type and bed coating. Because we get lots of support questions from "wrong"
behavior due to misunderstandings of all these dependencies, I will try to describe the function as detailed as possible.
## Step 1: Test if homing is possible at all
Test if homing in Z_HOME_DIR has a matching hardware endstop. If not, no z homing is possible at all.
## Step 2: Activate z-probe if required
If homing to z min using a z-probe, activate the probe. Requires a position where this is possible, since probe offset could prevent the
move. Hence in this case x and y must be homed first and a z homing position given and reached before calling this function.
## Step 3: Fast homing to sensor
A move of 2 * z_length is send to printer. The move will stop when the endstop triggers.
## Step 4: Untrigger sensor
Move in opposite direction ENDSTOP_Z_BACK_MOVE mm to disable the endstop signal safely.
## Step 5: Retest endstop slowly
For best precision we rerun step 3 with 1/ENDSTOP_Z_RETEST_REDUCTION_FACTOR factor for speed. This should give a very accurate trigge rposition.
## Step 6: Deactivate z-probe if it was activated in step 2
## Step 7: Correct Z position
zCorrection sums up several influences:
- -axisStepsPerMM[Z_AXIS] * EEPROM::zProbeHeight() to compensate for z-prove trigger offset if probe was used.
- -axisStepsPerMM[Z_AXIS] * ENDSTOP_Z_BACK_ON_HOME * Z_HOME_DIR to add wanted extra distance ENDSTOP_Z_BACK_ON_HOME.
- axisStepsPerMM[Z_AXIS] * zBedOffset to correct for bed coating if correction mode Z_PROBE_Z_OFFSET_MODE == 0 and z min homing.
and moves the z axis up that distance.
## Step 8: Set position in CMC
For z min homing set currentPositionSteps[Z_AXIS] to zMinSteps. For z max homing set it to zMaxSteps - bed coating.
Set z offset according to selected tool z offset, if extruder is not sensor.
If distortion correction is enabled, set zCorrectionStepsIncluded and add value to currentPositionSteps.
#step 9: Compute RWC and correct rotation influence
Compute real position from position in steps. If rotation is on we did measure with a z-probe,
this result is wrong and we need to correct by the z change between origin and current position.
currentPositionSteps[Z_AXIS] -= (axisStepsPerMM[Z_AXIS] * currentPosition[Z_AXIS] - zMinSteps);
currentPosition[Z_AXIS] = zMin;
## Step 10: Update NMC for nonlinear systems
## Step 11: Set babysteps to 0
*/
void Printer::homeZAxis() { // Cartesian homing
#if defined(SENSORLESS_HOMING) && TMC2130_ON_Z
while(!Printer::tmc_driver_z->stst()); // Wait for motor stand-still
uint32_t coolstep_speed = Printer::tmc_driver_z->coolstep_min_speed();
uint32_t stealth_max_sp = Printer::tmc_driver_z->stealth_max_speed();
bool stealth_state = Printer::tmc_driver_z->stealthChop();
tmcPrepareHoming(Printer::tmc_driver_z, TMC2130_TCOOLTHRS_Z);
#endif
long steps;
if ((MIN_HARDWARE_ENDSTOP_Z && Z_MIN_PIN > -1 && Z_HOME_DIR == -1) || (MAX_HARDWARE_ENDSTOP_Z && Z_MAX_PIN > -1 && Z_HOME_DIR == 1)) {
offsetZ2 = 0;
#if Z_HOME_DIR < 0 && Z_PROBE_PIN == Z_MIN_PIN && FEATURE_Z_PROBE
Printer::startProbing(true);
#endif
coordinateOffset[Z_AXIS] = 0; // G92 Z offset
UI_STATUS_UPD_F(Com::translatedF(UI_TEXT_HOME_Z_ID));
steps = (zMaxSteps - zMinSteps) * Z_HOME_DIR;
currentPositionSteps[Z_AXIS] = -steps;
setHoming(true);
#if defined(Z_PROBE_DELAY) && Z_PROBE_DELAY > 0 && Z_MIN_PIN == Z_PROBE_PIN && Z_HOME_DIR == -1
HAL::delayMilliseconds(Z_PROBE_DELAY);
#endif
#if NONLINEAR_SYSTEM
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
#endif
PrintLine::moveRelativeDistanceInSteps(0, 0, 2 * steps, 0, homingFeedrate[Z_AXIS], true, true);
currentPositionSteps[Z_AXIS] = (Z_HOME_DIR == -1) ? zMinSteps : zMaxSteps;
#if NONLINEAR_SYSTEM
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
#endif
PrintLine::moveRelativeDistanceInSteps(0, 0, axisStepsPerMM[Z_AXIS] * -ENDSTOP_Z_BACK_MOVE * Z_HOME_DIR, 0, homingFeedrate[Z_AXIS] / ENDSTOP_Z_RETEST_REDUCTION_FACTOR, true, false);
#if defined(ZHOME_WAIT_UNSWING) && ZHOME_WAIT_UNSWING > 0
HAL::delayMilliseconds(ZHOME_WAIT_UNSWING);
#endif
#if defined(Z_PROBE_DELAY) && Z_PROBE_DELAY > 0 && Z_MIN_PIN == Z_PROBE_PIN && Z_HOME_DIR == -1
HAL::delayMilliseconds(Z_PROBE_DELAY);
#endif
#if Z_HOME_DIR < 0 && Z_PROBE_PIN == Z_MIN_PIN && FEATURE_Z_PROBE
#ifdef Z_PROBE_RUN_AFTER_EVERY_PROBE
GCode::executeFString(PSTR(Z_PROBE_RUN_AFTER_EVERY_PROBE));
#endif
#endif
PrintLine::moveRelativeDistanceInSteps(0, 0, axisStepsPerMM[Z_AXIS] * 2 * ENDSTOP_Z_BACK_MOVE * Z_HOME_DIR, 0, homingFeedrate[Z_AXIS] / ENDSTOP_Z_RETEST_REDUCTION_FACTOR, true, true);
#if Z_HOME_DIR < 0 && Z_PROBE_PIN == Z_MIN_PIN && FEATURE_Z_PROBE
Printer::finishProbing();
#endif
setHoming(false);
int32_t zCorrection = 0;
#if Z_HOME_DIR < 0 && MIN_HARDWARE_ENDSTOP_Z && FEATURE_Z_PROBE && Z_PROBE_PIN == Z_MIN_PIN
// Fix error from z probe testing
zCorrection -= axisStepsPerMM[Z_AXIS] * EEPROM::zProbeHeight();
// Correct from bed rotation
//updateCurrentPosition(true);
//float xt,yt,zt;
//transformToPrinter(currentPosition[X_AXIS],currentPosition[Y_AXIS],0,xt,yt,zt);
//zCorrection -= zt;
#endif
#if defined(ENDSTOP_Z_BACK_ON_HOME)
// If we want to go up a bit more for some reason
if(ENDSTOP_Z_BACK_ON_HOME > 0)
zCorrection -= axisStepsPerMM[Z_AXIS] * ENDSTOP_Z_BACK_ON_HOME * Z_HOME_DIR;
#endif
#if Z_HOME_DIR < 0
// Fix bed coating
#if Z_PROBE_Z_OFFSET_MODE == 0 // Only if measure through coating e.g. inductive
zCorrection += axisStepsPerMM[Z_AXIS] * zBedOffset;
#endif
#endif
//Com::printFLN(PSTR("Z-Correction-Steps:"),zCorrection); // TEST
PrintLine::moveRelativeDistanceInSteps(0, 0, zCorrection, 0, homingFeedrate[Z_AXIS], true, false);
currentPositionSteps[Z_AXIS] = ((Z_HOME_DIR == -1) ? zMinSteps : zMaxSteps - zBedOffset * axisStepsPerMM[Z_AXIS]);
#if NUM_EXTRUDER > 0
#if (EXTRUDER_IS_Z_PROBE == 0 || Z_HOME_DIR > 0)
// currentPositionSteps[Z_AXIS] -= Extruder::current->zOffset;
Printer::offsetZ = -Extruder::current->zOffset * Printer::invAxisStepsPerMM[Z_AXIS];
#endif
#endif
#if DISTORTION_CORRECTION && Z_HOME_DIR < 0 && Z_PROBE_PIN == Z_MIN_PIN && FEATURE_Z_PROBE
// Special case where z probe is z min end stop and distortion correction is enabled
if(Printer::distortion.isEnabled()) {
Printer::zCorrectionStepsIncluded = Printer::distortion.correct(Printer::currentPositionSteps[X_AXIS], currentPositionSteps[Y_AXIS], currentPositionSteps[Z_AXIS]);
currentPositionSteps[Z_AXIS] += Printer::zCorrectionStepsIncluded;
}
#endif
updateCurrentPosition(true);
#if Z_HOME_DIR < 0 && Z_PROBE_PIN == Z_MIN_PIN && FEATURE_Z_PROBE
// If we have software leveling enabled and are not at 0,0 z position is not zero, but we measured
// for z = 0, so we need to correct for rotation.
currentPositionSteps[Z_AXIS] -= (axisStepsPerMM[Z_AXIS] * currentPosition[Z_AXIS] - zMinSteps);
currentPosition[Z_AXIS] = zMin;
#endif
#if NONLINEAR_SYSTEM
transformCartesianStepsToDeltaSteps(currentPositionSteps, currentNonlinearPositionSteps);
#endif
setZHomed(true);
#if FEATURE_BABYSTEPPING
Printer::zBabysteps = 0;
#endif
}
#if defined(SENSORLESS_HOMING) && TMC2130_ON_Z
while(!Printer::tmc_driver_z->stst()); // Wait for motor stand-still
Printer::tmc_driver_z->coolstep_min_speed(coolstep_speed);
Printer::tmc_driver_z->stealth_max_speed(stealth_max_sp);
Printer::tmc_driver_z->stealthChop(stealth_state);
#endif
}
/** \brief Main function for all homing operations.
For homing operations only this function should be used. It calls Printer::homeXAxis, Printer::homeYAxis and Printer::homeZAxis
after doing some initialization work. The order of operation and some extra functions are controlled by HOMING_ORDER.
\param xaxis True if homing of x axis is wanted.
\param yaxis True if homing of y axis is wanted.
\param zaxis True if homing of z axis is wanted.
*/
void Printer::homeAxis(bool xaxis, bool yaxis, bool zaxis) { // home non-delta printer
bool nocheck = isNoDestinationCheck();
setNoDestinationCheck(true);
#if defined(SUPPORT_LASER) && SUPPORT_LASER
bool oldLaser = LaserDriver::laserOn;
LaserDriver::laserOn = false;
#endif
float startX, startY, startZ;
realPosition(startX, startY, startZ);
#if !defined(HOMING_ORDER)
#define HOMING_ORDER HOME_ORDER_XYZ
#endif
#if Z_HOME_DIR < 0
#if ZHOME_PRE_RAISE == 1
if(zaxis && Endstops::zProbe())
PrintLine::moveRelativeDistanceInSteps(0, 0, ZHOME_PRE_RAISE_DISTANCE * axisStepsPerMM[Z_AXIS], 0, homingFeedrate[Z_AXIS], true, true);
#elif ZHOME_PRE_RAISE == 2
if(zaxis)
PrintLine::moveRelativeDistanceInSteps(0, 0, ZHOME_PRE_RAISE_DISTANCE * axisStepsPerMM[Z_AXIS], 0, homingFeedrate[Z_AXIS], true, true);
#endif
#endif
#if Z_HOME_DIR < 0 && Z_PROBE_PIN == Z_MIN_PIN && FEATURE_Z_PROBE
#if HOMING_ORDER != HOME_ORDER_XYZ && HOMING_ORDER != HOME_ORDER_YXZ && HOMING_ORDER != HOME_ORDER_ZXYTZ && HOMING_ORDER != HOME_ORDER_XYTZ
#error Illegal homing order for z probe based homing!
#endif
if(zaxis) { // we need to know xy position for z probe to work properly
if(!xaxis && !isXHomed())
xaxis = true;
if(!yaxis && !isYHomed())
yaxis = true;
}
#endif
if(zaxis) {
EVENT_BEFORE_Z_HOME;
}
#if HOMING_ORDER == HOME_ORDER_XYZ
if(xaxis) homeXAxis();
if(yaxis) homeYAxis();
if(zaxis) homeZAxis();
#elif HOMING_ORDER == HOME_ORDER_XZY
if(xaxis) homeXAxis();
if(zaxis) homeZAxis();
if(yaxis) homeYAxis();
#elif HOMING_ORDER == HOME_ORDER_YXZ
if(yaxis) homeYAxis();
if(xaxis) homeXAxis();
if(zaxis) homeZAxis();
#elif HOMING_ORDER == HOME_ORDER_YZX
if(yaxis) homeYAxis();
if(zaxis) homeZAxis();
if(xaxis) homeXAxis();
#elif HOMING_ORDER == HOME_ORDER_ZXY
if(zaxis) homeZAxis();
if(xaxis) homeXAxis();
if(yaxis) homeYAxis();
#elif HOMING_ORDER == HOME_ORDER_ZYX
if(zaxis) homeZAxis();
if(yaxis) homeYAxis();
if(xaxis) homeXAxis();
#elif HOMING_ORDER == HOME_ORDER_ZXYTZ || HOMING_ORDER == HOME_ORDER_XYTZ
{
#if ZHOME_MIN_TEMPERATURE > 20
float actTemp[NUM_EXTRUDER];
for(int i = 0; i < NUM_EXTRUDER; i++)
actTemp[i] = extruder[i].tempControl.targetTemperatureC;
#endif
if(zaxis) {
#if HOMING_ORDER == HOME_ORDER_ZXYTZ
homeZAxis();
Printer::moveToReal(IGNORE_COORDINATE, IGNORE_COORDINATE, ZHOME_HEAT_HEIGHT, IGNORE_COORDINATE, homingFeedrate[Z_AXIS]);
#endif
Commands::waitUntilEndOfAllMoves();
#if ZHOME_MIN_TEMPERATURE > 20
#if ZHOME_HEAT_ALL
for(int i = 0; i < NUM_EXTRUDER; i++) {
Extruder::setTemperatureForExtruder(RMath::max(actTemp[i], static_cast<float>(ZHOME_MIN_TEMPERATURE)), i, false, false);
}
for(int i = 0; i < NUM_EXTRUDER; i++) {
if(extruder[i].tempControl.currentTemperatureC < ZHOME_MIN_TEMPERATURE)
Extruder::setTemperatureForExtruder(RMath::max(actTemp[i], static_cast<float>(ZHOME_MIN_TEMPERATURE)), i, false, true);
}
#else
if(extruder[Extruder::current->id].tempControl.currentTemperatureC < ZHOME_MIN_TEMPERATURE)
Extruder::setTemperatureForExtruder(RMath::max(actTemp[Extruder::current->id], static_cast<float>(ZHOME_MIN_TEMPERATURE)), Extruder::current->id, false, true);
#endif
#endif
}
#if ZHOME_X_POS == IGNORE_COORDINATE
if(xaxis)
#else
if(xaxis || zaxis)
#endif
{
homeXAxis();
//#if ZHOME_X_POS == IGNORE_COORDINATE
if(X_HOME_DIR < 0) startX = Printer::xMin;
else startX = Printer::xMin + Printer::xLength;
//#else
// startX = ZHOME_X_POS;
//#endif
}
#if ZHOME_Y_POS == IGNORE_COORDINATE
if(yaxis)
#else
if(yaxis || zaxis)
#endif
{
homeYAxis();
//#if ZHOME_Y_POS == IGNORE_COORDINATE
if(Y_HOME_DIR < 0) startY = Printer::yMin;
else startY = Printer::yMin + Printer::yLength;
//#else
// startY = ZHOME_Y_POS;
//#endif
}
if(zaxis) {
#if ZHOME_X_POS != IGNORE_COORDINATE || ZHOME_Y_POS != IGNORE_COORDINATE
moveToReal(ZHOME_X_POS, ZHOME_Y_POS, IGNORE_COORDINATE, IGNORE_COORDINATE, homingFeedrate[X_AXIS]); // correct rotation!
Commands::waitUntilEndOfAllMoves();
#endif
homeZAxis(); // real z distance at that point to zero
if(Z_HOME_DIR < 0) startZ = Printer::zMin;
else startZ = Printer::zMin + Printer::zLength - zBedOffset;
moveToReal(IGNORE_COORDINATE, IGNORE_COORDINATE, ZHOME_HEAT_HEIGHT, IGNORE_COORDINATE, homingFeedrate[Z_AXIS]); // correct rotation!
Commands::waitUntilEndOfAllMoves();
#if ZHOME_MIN_TEMPERATURE > 20
#if ZHOME_HEAT_ALL
for(int i = 0; i < NUM_EXTRUDER; i++)
Extruder::setTemperatureForExtruder(actTemp[i], i, false, false);
for(int i = 0; i < NUM_EXTRUDER; i++)
Extruder::setTemperatureForExtruder(actTemp[i], i, false, actTemp[i] > MAX_ROOM_TEMPERATURE);
#else
Extruder::setTemperatureForExtruder(actTemp[Extruder::current->id], Extruder::current->id, false, actTemp[Extruder::current->id] > MAX_ROOM_TEMPERATURE);
#endif
#endif
}
}
#endif // elif HOMING_ORDER == HOME_ORDER_ZXYTZ || HOMING_ORDER == HOME_ORDER_XYTZ
#if HOMING_ORDER != HOME_ORDER_ZXYTZ && HOMING_ORDER != HOME_ORDER_XYTZ
if(xaxis) {
#if DUAL_X_AXIS
startX = currentPosition[X_AXIS];
#else
if(X_HOME_DIR < 0) startX = Printer::xMin;
else startX = Printer::xMin + Printer::xLength;
#endif // else DUAL_X_AXIS
}
if(yaxis) {
if(Y_HOME_DIR < 0) startY = Printer::yMin;
else startY = Printer::yMin + Printer::yLength;
}
if(zaxis) {
if(Z_HOME_DIR < 0) startZ = Printer::zMin;
else startZ = Printer::zMin + Printer::zLength - Printer::zBedOffset;
}
#endif // HOMING_ORDER != HOME_ORDER_ZXYTZ
updateCurrentPosition(true);
#if defined(Z_UP_AFTER_HOME) && Z_HOME_DIR < 0
#ifdef HOME_ZUP_FIRST
PrintLine::moveRelativeDistanceInSteps(0, 0, axisStepsPerMM[Z_AXIS]*Z_UP_AFTER_HOME * Z_HOME_DIR, 0, homingFeedrate[Z_AXIS], true, false);
#endif
if(zaxis)
startZ = Z_UP_AFTER_HOME;
#endif
moveToReal(startX, startY, startZ, IGNORE_COORDINATE, homingFeedrate[X_AXIS]);
#if (DUAL_X_AXIS && LAZY_DUAL_X_AXIS)
moveToReal(startX, startY, startZ, IGNORE_COORDINATE, homingFeedrate[X_AXIS]);
if(!sledParked && xaxis) { // park sled
homeXAxis();
}
#endif
updateCurrentPosition(true);
#if DUAL_X_AXIS && LAZY_DUAL_X_AXIS == 1
lastCmdPos[X_AXIS] = xMin;
#endif
updateHomedAll();
UI_CLEAR_STATUS
Commands::printCurrentPosition();
#if defined(SUPPORT_LASER) && SUPPORT_LASER
LaserDriver::laserOn = oldLaser;
#endif
setNoDestinationCheck(nocheck);
Printer::updateCurrentPosition();
}
#endif // Not delta printer
/** \brief Execute a open baby step.
If zBabystepsMissing is not 0 this will do a z step in the desired direction. The old movement directions
get restored after execution.
*/
void Printer::zBabystep() {
#if FEATURE_BABYSTEPPING
bool dir = zBabystepsMissing > 0;
if(dir) zBabystepsMissing--;
else zBabystepsMissing++;
#if DRIVE_SYSTEM == DELTA
Printer::enableXStepper();
Printer::enableYStepper();
#endif
Printer::enableZStepper();
Printer::unsetAllSteppersDisabled();
#if DRIVE_SYSTEM == DELTA
bool xDir = Printer::getXDirection();
bool yDir = Printer::getYDirection();
#endif
bool zDir = Printer::getZDirection();
#if DRIVE_SYSTEM == DELTA
Printer::setXDirection(dir);
Printer::setYDirection(dir);
#endif
Printer::setZDirection(dir);
#if defined(DIRECTION_DELAY) && DIRECTION_DELAY > 0
HAL::delayMicroseconds(DIRECTION_DELAY);
#else
HAL::delayMicroseconds(10);
#endif
#if DRIVE_SYSTEM == DELTA
startXStep();
startYStep();
#endif // Drive system 3
startZStep();
HAL::delayMicroseconds(STEPPER_HIGH_DELAY + 2);
Printer::endXYZSteps();
HAL::delayMicroseconds(10);
#if DRIVE_SYSTEM == 3
Printer::setXDirection(xDir);
Printer::setYDirection(yDir);
#endif
Printer::setZDirection(zDir);
#if defined(DIRECTION_DELAY) && DIRECTION_DELAY > 0
HAL::delayMicroseconds(DIRECTION_DELAY);
#endif
//HAL::delayMicroseconds(STEPPER_HIGH_DELAY + 1);
#endif
}
void Printer::setCaseLight(bool on) {
#if CASE_LIGHTS_PIN > -1
WRITE(CASE_LIGHTS_PIN, on);
reportCaseLightStatus();
#endif
}
void Printer::reportCaseLightStatus() {
#if CASE_LIGHTS_PIN > -1
if(READ(CASE_LIGHTS_PIN))
Com::printInfoFLN(PSTR("Case lights on"));
else
Com::printInfoFLN(PSTR("Case lights off"));
#else
Com::printInfoFLN(PSTR("No case lights"));
#endif
}
void Printer::handleInterruptEvent() {
if(interruptEvent == 0) return;
int event = interruptEvent;
interruptEvent = 0;
switch(event) {
#if EXTRUDER_JAM_CONTROL
case PRINTER_INTERRUPT_EVENT_JAM_DETECTED:
if(isJamcontrolDisabled()) break;
EVENT_JAM_DETECTED;
Com::printFLN(PSTR("important:Extruder jam detected"));
UI_ERROR_P(Com::translatedF(UI_TEXT_EXTRUDER_JAM_ID));
#if JAM_ACTION == 1 // start dialog
Printer::setUIErrorMessage(false);
#if UI_DISPLAY_TYPE != NO_DISPLAY
uid.executeAction(UI_ACTION_WIZARD_JAM_EOF, true);
#endif
#elif JAM_ACTION == 2 // pause host/print
#if SDSUPPORT
if(sd.sdmode == 2) {
sd.pausePrint(true);
break;
}
#endif // SDSUPPORT
GCodeSource::printAllFLN(PSTR("RequestPause:Extruder Jam Detected!"));
#endif // JAM_ACTION
EVENT_JAM_DETECTED_END;
break;
case PRINTER_INTERRUPT_EVENT_JAM_SIGNAL0:
case PRINTER_INTERRUPT_EVENT_JAM_SIGNAL1:
case PRINTER_INTERRUPT_EVENT_JAM_SIGNAL2:
case PRINTER_INTERRUPT_EVENT_JAM_SIGNAL3:
case PRINTER_INTERRUPT_EVENT_JAM_SIGNAL4:
case PRINTER_INTERRUPT_EVENT_JAM_SIGNAL5: {
if(isJamcontrolDisabled()) break;
fast8_t extruderIndex = event - PRINTER_INTERRUPT_EVENT_JAM_SIGNAL0;
Extruder &ext = extruder[extruderIndex];
int32_t steps = abs(extruder[extruderIndex].jamStepsOnSignal);
EVENT_JAM_SIGNAL_CHANGED(extruderIndex, steps);
if(steps > ext.jamSlowdownSteps && !ext.tempControl.isSlowedDown()) {
extruder[extruderIndex].tempControl.setSlowedDown(true);
Commands::changeFeedrateMultiply(ext.jamSlowdownTo);
//UI_ERROR_P(Com::tFilamentSlipping);
UI_MESSAGE(4);
}
if(isDebugJam()) {
Com::printF(PSTR("Jam signal steps:"), steps);
int32_t percent = static_cast<int32_t>(steps) * 100 / JAM_STEPS;
Com::printF(PSTR(" / "), percent);
Com::printFLN(PSTR("% on "), (int)extruderIndex);
}
}
break;
#endif // EXTRUDER_JAM_CONTROL case PRINTER_INTERRUPT_EVENT_JAM_DETECTED:
}
}
#define START_EXTRUDER_CONFIG(i) Com::printF(Com::tConfig);Com::printF(Com::tExtrDot,i+1);Com::print(':');
void Printer::showConfiguration() {
Com::config(PSTR("Baudrate:"), baudrate);
#ifndef EXTERNALSERIAL
Com::config(PSTR("InputBuffer:"), SERIAL_BUFFER_SIZE - 1);
#endif
Com::config(PSTR("NumExtruder:"), NUM_EXTRUDER);
Com::config(PSTR("MixingExtruder:"), MIXING_EXTRUDER);
Com::config(PSTR("HeatedBed:"), HAVE_HEATED_BED);
Com::config(PSTR("SDCard:"), SDSUPPORT);
Com::config(PSTR("Fan:"), FAN_PIN > -1 && FEATURE_FAN_CONTROL);
#if FEATURE_FAN2_CONTROL && defined(FAN2_PIN) && FAN2_PIN > -1
Com::config(PSTR("Fan2:1"));
#else
Com::config(PSTR("Fan2:0"));
#endif
Com::config(PSTR("LCD:"), FEATURE_CONTROLLER != NO_CONTROLLER);
Com::config(PSTR("SoftwarePowerSwitch:"), PS_ON_PIN > -1);
Com::config(PSTR("XHomeDir:"), X_HOME_DIR);
Com::config(PSTR("YHomeDir:"), Y_HOME_DIR);
Com::config(PSTR("ZHomeDir:"), Z_HOME_DIR);
#if DRIVE_SYSTEM == DELTA
Com::config(PSTR("XHomePos:"), 0, 2);
Com::config(PSTR("YHomePos:"), 0, 2);
Com::config(PSTR("ZHomePos:"), zMin + zLength, 3);
#else
Com::config(PSTR("XHomePos:"), xMin + (X_HOME_DIR > 0 ? xLength : 0), 2);
Com::config(PSTR("YHomePos:"), yMin + (Y_HOME_DIR > 0 ? yLength : 0), 2);
Com::config(PSTR("ZHomePos:"), zMin + (Z_HOME_DIR > 0 ? zLength : 0), 3);
#endif
Com::config(PSTR("SupportG10G11:"), FEATURE_RETRACTION);
Com::config(PSTR("SupportLocalFilamentchange:"), FEATURE_RETRACTION);
Com::config(PSTR("CaseLights:"), CASE_LIGHTS_PIN > -1);
Com::config(PSTR("ZProbe:"), FEATURE_Z_PROBE);
Com::config(PSTR("Autolevel:"), FEATURE_AUTOLEVEL);
Com::config(PSTR("EEPROM:"), EEPROM_MODE != 0);
Com::config(PSTR("PrintlineCache:"), PRINTLINE_CACHE_SIZE);
Com::config(PSTR("JerkXY:"), maxJerk);
Com::config(PSTR("KeepAliveInterval:"), KEEP_ALIVE_INTERVAL);
#if DRIVE_SYSTEM != DELTA
Com::config(PSTR("JerkZ:"), maxZJerk);
#endif
#if FEATURE_RETRACTION
Com::config(PSTR("RetractionLength:"), EEPROM_FLOAT(RETRACTION_LENGTH));
Com::config(PSTR("RetractionLongLength:"), EEPROM_FLOAT(RETRACTION_LONG_LENGTH));
Com::config(PSTR("RetractionSpeed:"), EEPROM_FLOAT(RETRACTION_SPEED));
Com::config(PSTR("RetractionZLift:"), EEPROM_FLOAT(RETRACTION_Z_LIFT));
Com::config(PSTR("RetractionUndoExtraLength:"), EEPROM_FLOAT(RETRACTION_UNDO_EXTRA_LENGTH));
Com::config(PSTR("RetractionUndoExtraLongLength:"), EEPROM_FLOAT(RETRACTION_UNDO_EXTRA_LONG_LENGTH));
Com::config(PSTR("RetractionUndoSpeed:"), EEPROM_FLOAT(RETRACTION_UNDO_SPEED));
#endif // FEATURE_RETRACTION
Com::config(PSTR("XMin:"), xMin);
Com::config(PSTR("YMin:"), yMin);
Com::config(PSTR("ZMin:"), zMin);
Com::config(PSTR("XMax:"), xMin + xLength);
Com::config(PSTR("YMax:"), yMin + yLength);
Com::config(PSTR("ZMax:"), zMin + zLength);
Com::config(PSTR("XSize:"), xLength);
Com::config(PSTR("YSize:"), yLength);
Com::config(PSTR("ZSize:"), zLength);
Com::config(PSTR("XPrintAccel:"), maxAccelerationMMPerSquareSecond[X_AXIS]);
Com::config(PSTR("YPrintAccel:"), maxAccelerationMMPerSquareSecond[Y_AXIS]);
Com::config(PSTR("ZPrintAccel:"), maxAccelerationMMPerSquareSecond[Z_AXIS]);
Com::config(PSTR("XTravelAccel:"), maxTravelAccelerationMMPerSquareSecond[X_AXIS]);
Com::config(PSTR("YTravelAccel:"), maxTravelAccelerationMMPerSquareSecond[Y_AXIS]);
Com::config(PSTR("ZTravelAccel:"), maxTravelAccelerationMMPerSquareSecond[Z_AXIS]);
#if DRIVE_SYSTEM == DELTA
Com::config(PSTR("PrinterType:Delta"));
#else
Com::config(PSTR("PrinterType:Cartesian"));
#endif // DRIVE_SYSTEM
Com::config(PSTR("MaxBedTemp:"), HEATED_BED_MAX_TEMP);
for(fast8_t i = 0; i < NUM_EXTRUDER; i++) {
START_EXTRUDER_CONFIG(i)
Com::printFLN(PSTR("Jerk:"), extruder[i].maxStartFeedrate);
START_EXTRUDER_CONFIG(i)
Com::printFLN(PSTR("MaxSpeed:"), extruder[i].maxFeedrate);
START_EXTRUDER_CONFIG(i)
Com::printFLN(PSTR("Acceleration:"), extruder[i].maxAcceleration);
START_EXTRUDER_CONFIG(i)
Com::printFLN(PSTR("Diameter:"), extruder[i].diameter);
START_EXTRUDER_CONFIG(i)
Com::printFLN(PSTR("MaxTemp:"), MAXTEMP);
}
}
#if JSON_OUTPUT
void Printer::showJSONStatus(int type) {
bool firstOccurrence;
Com::printF(PSTR("{\"status\": \""));
if (PrintLine::linesCount == 0) {
Com::print('I'); // IDLING
#if SDSUPPORT
} else if (sd.sdactive) {
Com::print('P'); // SD PRINTING
#endif
} else {
Com::print('B'); // SOMETHING ELSE, BUT SOMETHIG
}
// "heaters": [27.5, 30.3, 30.6],
Com::printF(PSTR("\",\"heaters\":["));
#if HAVE_HEATED_BED
Com::print(heatedBedController.currentTemperatureC);
#else
Com::print((int)0);
#endif
for (int i = 0; i < NUM_EXTRUDER; i++) {
Com::print(',');
Com::print(extruder[i].tempControl.currentTemperatureC);
}
// "active": [65.0, 195.0, 0.0],
Com::printF(PSTR("],\"active\":["));
#if HAVE_HEATED_BED
Com::print(heatedBedController.targetTemperatureC);
#else
Com::print((int)0);
#endif
for (int i = 0; i < NUM_EXTRUDER; i++) {
Com::print(',');
Com::print(extruder[i].tempControl.targetTemperatureC);
}
// "standby": [-273.1, 0.0, 150.0],
Com::printF(PSTR("],\"standby\":["));
#if HAVE_HEATED_BED
Com::print(heatedBedController.targetTemperatureC);
#else
Com::print((int)0);
#endif
for (int i = 0; i < NUM_EXTRUDER; i++) {
Com::print(',');
Com::print(extruder[i].tempControl.targetTemperatureC);
}
// "hstat": [0, 0, 0],
// hstat is 0 for heater off, 1 for standby, 2 for active and 3 for fault. We have just added 4 for "being auto-tuned'
Com::printF(PSTR("],\"hstat\":["));
#if HAVE_HEATED_BED
if(heatedBedController.isSensorDefect() || heatedBedController.isSensorDecoupled())
Com::print((int)3);
else
Com::print((int)(heatedBedController.targetTemperatureC < 30 ? 0 : 2));
#else
Com::print((int)0);
#endif
for (int i = 0; i < NUM_EXTRUDER; i++) {
Com::print(',');
if(extruder[i].tempControl.isSensorDefect() || extruder[i].tempControl.isSensorDecoupled())
Com::print((int)3);
else
Com::print((int)(extruder[i].tempControl.targetTemperatureC < 30 ? 0 : 2));
}
// "pos": [1.00, 205.00, 6.48],
Com::printF(PSTR("],\"pos\":["));
Com::print(currentPosition[X_AXIS]); // X
Com::print(',');
Com::print(currentPosition[Y_AXIS]); // Y
Com::print(',');
Com::print(currentPosition[Z_AXIS]); // Z
// "extr": [0.0, 0.0],
Com::printF(PSTR("],\"extr\":["));
for (int i = 0; i < NUM_EXTRUDER; i++) {
if (i) Com::print(',');
Com::printFloat(extruder[i].tempControl.currentTemperatureC,1);
}
// "sfactor": 100.00,
Com::printF(PSTR("],\"sfactor\":"), Printer::feedrateMultiply);
// "efactor": [100.00, 100.00],
Com::printF(PSTR(",\"efactor\":["));
for (int i = 0; i < NUM_EXTRUDER; i++) {
if (i) Com::print(',');
Com::print((int)Printer::extrudeMultiply);
}
// "tool": 0,
Com::printF(PSTR("],\"tool\":"), Extruder::current->id);
//"probe": "4",
Com::printF(PSTR(",\"probe\":"));
if(Endstops::zProbe())
Com::print((int)0);
else
Com::print((int)1000);
// "fanPercent": [0.00, 100.00],
Com::printF(PSTR(",\"fanPercent\":["));
#if FEATURE_FAN_CONTROL
Com::print(getFanSpeed() / 2.55f);
#endif
#if FEATURE_FAN2_CONTROL
Com::printF(Com::tComma, getFan2Speed() / 2.55f);
#endif
Com::printF(PSTR("]"));
// "fanRPM": 0,
// "homed": [1, 1, 1],
Com::printF(PSTR(",\"homed\":["));
Com::print((int)isXHomed());
Com::print(',');
Com::print(isYHomed());
Com::print(',');
Com::print(isZHomed());
Com::printF(PSTR("]"));
if(type == 1) {
// "geometry": "cartesian",
#if DRIVE_SYSTEM == DELTA
Com::printF(PSTR(",\"geometry\":\"Delta\""));
#else
Com::printF(PSTR(",\"geometry\":\"Cartesian\""));
#endif
// "myName": "Ormerod"
Com::printF(PSTR(",\"myName\":\"" UI_PRINTER_NAME "\""));
Com::printF(PSTR(",\"firmwareName\":\"Repetier\""));
}
Com::printF(PSTR(",\"coords\": {"));
Com::printF(PSTR("\"axesHomed\":["));
Com::print((int)isXHomed());
Com::print(',');
Com::print(isYHomed());
Com::print(',');
Com::print(isZHomed());
Com::printF(PSTR("],\"extr\":["));
firstOccurrence = true;
for (int i = 0; i < NUM_EXTRUDER; i++) {
if (!firstOccurrence) Com::print(',');
Com::print(extruder[i].extrudePosition / extruder[i].stepsPerMM);
firstOccurrence = false;
}
Com::printF(PSTR("],\"xyz\":["));
Com::print(currentPosition[X_AXIS]); // X
Com::print(',');
Com::print(currentPosition[Y_AXIS]); // Y
Com::print(',');
Com::print(currentPosition[Z_AXIS]); // Z
Com::printF(PSTR("]},\"currentTool\":"));
Com::print(Extruder::current->id);
Com::printF(PSTR(",\"params\": {\"atxPower\":"));
Com::print(isPowerOn() ? '1' : '0');
Com::printF(PSTR(",\"fanPercent\":["));
#if FEATURE_FAN_CONTROL
Com::print(getFanSpeed() / 2.55f);
#endif
#if FEATURE_FAN2_CONTROL
Com::printF(Com::tComma, getFan2Speed() / 2.55f);
#endif
Com::printF(PSTR("],\"speedFactor\":"));
Com::print(Printer::feedrateMultiply);
Com::printF(PSTR(",\"extrFactors\":["));
firstOccurrence = true;
for (int i = 0; i < NUM_EXTRUDER; i++) {
if (!firstOccurrence) Com::print(',');
Com::print((int)Printer::extrudeMultiply); // Really *100? 100 is normal
firstOccurrence = false;
}
Com::printF(PSTR("]},"));
// SEQ??
Com::printF(PSTR("\"temps\": {"));
#if HAVE_HEATED_BED
Com::printF(PSTR("\"bed\": {\"current\":"));
Com::print(heatedBedController.currentTemperatureC);
Com::printF(PSTR(",\"active\":"));
Com::print(heatedBedController.targetTemperatureC);
Com::printF(PSTR(",\"state\":"));
Com::print(heatedBedController.targetTemperatureC > 0 ? '2' : '1');
Com::printF(PSTR("},"));
#endif
Com::printF(PSTR("\"heads\": {\"current\": ["));
firstOccurrence = true;
for (int i = 0; i < NUM_EXTRUDER; i++) {
if (!firstOccurrence) Com::print(',');
Com::print(extruder[i].tempControl.currentTemperatureC);
firstOccurrence = false;
}
Com::printF(PSTR("],\"active\": ["));
firstOccurrence = true;
for (int i = 0; i < NUM_EXTRUDER; i++) {
if (!firstOccurrence) Com::print(',');
Com::print(extruder[i].tempControl.targetTemperatureC);
firstOccurrence = false;
}
Com::printF(PSTR("],\"state\": ["));
firstOccurrence = true;
for (int i = 0; i < NUM_EXTRUDER; i++) {
if (!firstOccurrence) Com::print(',');
Com::print(extruder[i].tempControl.targetTemperatureC > EXTRUDER_FAN_COOL_TEMP ? '2' : '1');
firstOccurrence = false;
}
Com::printF(PSTR("]}},\"time\":"));
Com::print(HAL::timeInMilliseconds());
switch (type) {
default:
case 0:
case 1:
break;
case 2:
// UNTIL PRINT ESTIMATE TIMES ARE IMPLEMENTED
// NO DURATION INFO IS SUPPORTED
Com::printF(PSTR(",\"coldExtrudeTemp\":0,\"coldRetractTemp\":0.0,\"geometry\":\""));
#if (DRIVE_SYSTEM == DELTA)
Com::printF(PSTR("delta"));
#elif (DRIVE_SYSTEM == CARTESIAN || DRIVE_SYSTEM == GANTRY_FAKE)
Com::printF(PSTR("cartesian"));
#elif ((DRIVE_SYSTEM == XY_GANTRY) || (DRIVE_SYSTEM == YX_GANTRY))
Com::printF(PSTR("coreXY"));
#elif (DRIVE_SYSTEM == XZ_GANTRY)
Com::printF(PSTR("coreXZ"));
#endif
Com::printF(PSTR("\",\"name\":\""));
Com::printF(PSTR(UI_PRINTER_NAME));
Com::printF(PSTR("\",\"tools\":["));
firstOccurrence = true;
for (int i = 0; i < NUM_EXTRUDER; i++) {
if (!firstOccurrence) Com::print(',');
Com::printF(PSTR("{\"number\":"));
Com::print(i);
Com::printF(PSTR(",\"heaters\":[1],\"drives\":[1]"));
Com::print('}');
firstOccurrence = false;
}
Com::printF(PSTR("]"));
break;
case 3:
Com::printF(PSTR(",\"currentLayer\":"));
#if SDSUPPORT
if (sd.sdactive && sd.fileInfo.layerHeight > 0) { // ONLY CAN TELL WHEN SD IS PRINTING
Com::print((int) (currentPosition[Z_AXIS] / sd.fileInfo.layerHeight));
} else Com::print('0');
#else
Com::printF(PSTR("-1"));
#endif
Com::printF(PSTR(",\"extrRaw\":["));
firstOccurrence = true;
for (int i = 0; i < NUM_EXTRUDER; i++) {
if (!firstOccurrence) Com::print(',');
Com::print(extruder[i].extrudePosition * Printer::extrudeMultiply);
firstOccurrence = false;
}
Com::printF(PSTR("],"));
#if SDSUPPORT
if (sd.sdactive) {
Com::printF(PSTR("\"fractionPrinted\":"));
float fraction;
if (sd.filesize < 2000000) fraction = sd.sdpos / sd.filesize;
else fraction = (sd.sdpos >> 8) / (sd.filesize >> 8);
Com::print((float) floor(fraction * 1000) / 1000); // ONE DECIMAL, COULD BE DONE BY SHIFTING, BUT MEH
Com::print(',');
}
#endif
Com::printF(PSTR("\"firstLayerHeight\":"));
#if SDSUPPORT
if (sd.sdactive) {
Com::print(sd.fileInfo.layerHeight);
} else Com::print('0');
#else
Com::print('0');
#endif
break;
case 4:
case 5:
Com::printF(PSTR(",\"axisMins\":["));
Com::print((int) X_MIN_POS);
Com::print(',');
Com::print((int) Y_MIN_POS);
Com::print(',');
Com::print((int) Z_MIN_POS);
Com::printF(PSTR("],\"axisMaxes\":["));
Com::print((int) X_MAX_LENGTH);
Com::print(',');
Com::print((int) Y_MAX_LENGTH);
Com::print(',');
Com::print((int) Z_MAX_LENGTH);
Com::printF(PSTR("],\"accelerations\":["));
Com::print(maxAccelerationMMPerSquareSecond[X_AXIS]);
Com::print(',');
Com::print(maxAccelerationMMPerSquareSecond[Y_AXIS]);
Com::print(',');
Com::print(maxAccelerationMMPerSquareSecond[Z_AXIS]);
for (int i = 0; i < NUM_EXTRUDER; i++) {
Com::print(',');
Com::print(extruder[i].maxAcceleration);
}
Com::printF(PSTR("],\"firmwareElectronics\":\""));
#ifdef RAMPS_V_1_3
Com::printF(PSTR("RAMPS"));
#elif (CPU_ARCH == ARCH_ARM)
Com::printF(PSTR("Arduino Due"));
#else
Com::printF(PSTR("AVR"));
#endif
Com::printF(PSTR("\",\"firmwareName\":\"Repetier\",\"firmwareVersion\":\""));
Com::printF(PSTR(REPETIER_VERSION));
Com::printF(PSTR("\",\"minFeedrates\":[0,0,0"));
for (int i = 0; i < NUM_EXTRUDER; i++) {
Com::printF(PSTR(",0"));
}
Com::printF(PSTR("],\"maxFeedrates\":["));
Com::print(maxFeedrate[X_AXIS]);
Com::print(',');
Com::print(maxFeedrate[Y_AXIS]);
Com::print(',');
Com::print(maxFeedrate[Z_AXIS]);
for (int i = 0; i < NUM_EXTRUDER; i++) {
Com::print(',');
Com::print(extruder[i].maxFeedrate);
}
Com::printF(PSTR("]"));
break;
}
Com::printFLN(PSTR("}"));
}
#endif // JSON_OUTPUT
void Printer::pausePrint() {
#if SDSUPPORT
if(Printer::isMenuMode(MENU_MODE_SD_PRINTING)) {
sd.pausePrint(true);
} else
#endif
if(Printer::isMenuMode(MENU_MODE_PRINTING)) {
GCodeSource::printAllFLN(PSTR("RequestPause:"));
Printer::setMenuMode(MENU_MODE_PAUSED, true);
#if !defined(DISABLE_PRINTMODE_ON_PAUSE) || DISABLE_PRINTMODE_ON_PAUSE==1
Printer::setPrinting(false);
#endif
}
}
void Printer::continuePrint() {
#if SDSUPPORT
if(Printer::isMenuMode(MENU_MODE_SD_PRINTING + MENU_MODE_PAUSED)) {
sd.continuePrint(true);
} else
#endif
if(Printer::isMenuMode(MENU_MODE_PAUSED)) {
GCodeSource::printAllFLN(PSTR("RequestContinue:"));
}
setMenuMode(MENU_MODE_PAUSED, false);
}
void Printer::stopPrint() {
flashSource.close(); // stop flash printing if busy
#if SDSUPPORT
if(Printer::isMenuMode(MENU_MODE_SD_PRINTING)) {
sd.stopPrint();
} else
#endif
{
GCodeSource::printAllFLN(PSTR("RequestStop:"));
}
if(!isUIErrorMessage()) {
UI_RESET_MENU
}
}
#if defined(DRV_TMC2130)
void Printer::configTMC2130(TMC2130Stepper* tmc_driver, bool tmc_stealthchop, int8_t tmc_sgt,
uint8_t tmc_pwm_ampl, uint8_t tmc_pwm_grad, bool tmc_pwm_autoscale, uint8_t tmc_pwm_freq) {
while(!tmc_driver->stst()); // Wait for motor stand-still
tmc_driver->begin(); // Initiate pins and registries
// Using internal reference should be good enough and work on more drivers
// tmc_driver->I_scale_analog(true); // Set current reference source
tmc_driver->interpolate(true); // Set internal micro step interpolation
tmc_driver->pwm_ampl(tmc_pwm_ampl); // Chopper PWM amplitude
tmc_driver->pwm_grad(tmc_pwm_grad); // Velocity gradient for chopper PWM amplitude
tmc_driver->pwm_autoscale(tmc_pwm_autoscale); // Chopper PWM autos scaling
tmc_driver->pwm_freq(tmc_pwm_freq); // Chopper PWM frequency selection
tmc_driver->stealthChop(tmc_stealthchop); // Enable extremely quiet stepping
tmc_driver->sg_stall_value(tmc_sgt); // StallGuard sensitivity
}
#if defined(SENSORLESS_HOMING)
void Printer::tmcPrepareHoming(TMC2130Stepper* tmc_driver, uint32_t coolstep_sp_min) {
while(!tmc_driver->stst()); // Wait for motor stand-still
tmc_driver->stealth_max_speed(0); // Upper speed limit for stealthChop
tmc_driver->stealthChop(false); // Turn off stealthChop
tmc_driver->coolstep_min_speed(coolstep_sp_min);// Minimum speed for StallGuard triggering
tmc_driver->sg_filter(false); // Turn off StallGuard filtering
tmc_driver->diag1_stall(true); // Signal StallGuard on DIAG1 pin
#if MOTHERBOARD != 310 // Rambo Einsy has diag0 and diag1 bound together so this could cause a defect
tmc_driver->diag1_active_high(true); // StallGuard pulses active high
#endif
}
#endif
#endif