void CardReader::unparseKeyLine(const char *key, char *value) { if (!cardOK || !isFileOpen()) return; file.writeError = false; file.write(key); if (file.writeError) { ECHO_LM(ER, MSG_SD_ERR_WRITE_TO_FILE); return; } file.writeError = false; file.write("="); if (file.writeError) { ECHO_LM(ER, MSG_SD_ERR_WRITE_TO_FILE); return; } file.writeError = false; file.write(value); if (file.writeError) { ECHO_LM(ER, MSG_SD_ERR_WRITE_TO_FILE); return; } file.writeError = false; file.write("\n"); if (file.writeError) { ECHO_LM(ER, MSG_SD_ERR_WRITE_TO_FILE); return; } }
void CardReader::initsd() { cardOK = false; if (root.isOpen()) root.close(); #ifdef SDSLOW #define SPI_SPEED SPI_HALF_SPEED #else #define SPI_SPEED SPI_FULL_SPEED #endif if (!card.init(SPI_SPEED,SDSS) #if defined(LCD_SDSS) && (LCD_SDSS != SDSS) && !card.init(SPI_SPEED, LCD_SDSS) #endif ) { ECHO_LM(DB, MSG_SD_INIT_FAIL); } else if (!volume.init(&card)) { ECHO_LM(ER, MSG_SD_VOL_INIT_FAIL); } else if (!root.openRoot(&volume)) { ECHO_LM(ER, MSG_SD_OPENROOT_FAIL); } else { cardOK = true; ECHO_LM(DB, MSG_SD_CARD_OK); } workDir = root; curDir = &root; /* if (!workDir.openRoot(&volume)) { ECHO_EM(MSG_SD_WORKDIR_FAIL); } */ }
void CardReader::initsd() { cardOK = false; if (root.isOpen()) root.close(); #if ENABLED(SDEXTRASLOW) #define SPI_SPEED SPI_QUARTER_SPEED #elif ENABLED(SDSLOW) #define SPI_SPEED SPI_HALF_SPEED #else #define SPI_SPEED SPI_FULL_SPEED #endif if(!fat.begin(SDSS, SPI_SPEED) #if defined(LCD_SDSS) && (LCD_SDSS != SDSS) && !fat.begin(LCD_SDSS, SPI_SPEED) #endif ) { ECHO_LM(ER, SERIAL_SD_INIT_FAIL); } else { cardOK = true; ECHO_LM(DB, SERIAL_SD_CARD_OK); } fat.chdir(true); root = *fat.vwd(); workDir = root; curDir = &root; }
void ConfigSD_PrintSettings(bool forReplay) { // Always have this function, even with SD_SETTINGS disabled, the current values will be shown #if HAS(POWER_CONSUMPTION_SENSOR) if (!forReplay) { ECHO_LM(INFO, "Watt/h consumed:"); } ECHO_LVM(INFO, power_consumption_hour," Wh"); #endif if (!forReplay) { ECHO_LM(INFO, "Power on time:"); } char time[30]; unsigned int day = printer_usage_seconds / 60 / 60 / 24, hours = (printer_usage_seconds / 60 / 60) % 24, minutes = (printer_usage_seconds / 60) % 60; sprintf_P(time, PSTR(" %i " MSG_END_DAY " %i " MSG_END_HOUR " %i " MSG_END_MINUTE), day, hours, minutes); ECHO_LT(INFO, time); if (!forReplay) { ECHO_LM(INFO, "Filament printed:"); } char lung[30]; unsigned int kmeter = (long)printer_usage_filament / 1000 / 1000, meter = ((long)printer_usage_filament / 1000) % 1000, centimeter = ((long)printer_usage_filament / 10) % 100, millimeter = ((long)printer_usage_filament) % 10; sprintf_P(lung, PSTR(" %i Km %i m %i cm %i mm"), kmeter, meter, centimeter, millimeter); ECHO_LT(INFO, lung); }
/** * Configuration on SD card * * Author: Simone Primarosa * */ void ConfigSD_ResetDefault() { #if HAS(POWER_CONSUMPTION_SENSOR) power_consumption_hour = 0; #endif print_job_counter.initStats(); ECHO_LM(OK, "Hardcoded SD Default Settings Loaded"); }
/** * Configuration on SD card * * Author: Simone Primarosa * */ void ConfigSD_ResetDefault() { #if HAS(POWER_CONSUMPTION_SENSOR) power_consumption_hour = 0; #endif printer_usage_seconds = 0; printer_usage_filament = 0; ECHO_LM(OK, "Hardcoded SD Default Settings Loaded"); }
bool NexUpload::_checkFile(void) { ECHO_LMT(DB, "Start checkFile ", _file_name); if (!card.selectFile(_file_name)) { ECHO_LM(ER, "file is not exit"); return 0; } _unuploadByte = card.fileSize; return 1; }
void NexUpload::startUpload(void) { if (!_checkFile()) { ECHO_LM(ER, "The file is error"); return; } if (_getBaudrate() == 0) { ECHO_LM(ER, "baudrate error"); return; } if (!_setUploadBaudrate(_upload_baudrate)) { ECHO_LM(ER, "modify baudrate error"); return; } if (!_uploadTftFile()) { ECHO_LM(ER, "upload file error"); return; } card.closeFile(); ECHO_LM(DB, "upload ok"); }
void _EEPROM_writeData(int& pos, uint8_t* value, uint8_t size) { uint8_t c; while(size--) { eeprom_write_byte((unsigned char*)pos, *value); c = eeprom_read_byte((unsigned char*)pos); if (c != *value) { ECHO_LM(ER, SERIAL_ERR_EEPROM_WRITE); } pos++; value++; }; }
void CardReader::write_command(char* buf) { char* begin = buf; char* npos = 0; char* end = buf + strlen(buf) - 1; file.writeError = false; if ((npos = strchr(buf, 'N')) != NULL) { begin = strchr(npos, ' ') + 1; end = strchr(npos, '*') - 1; } end[1] = '\r'; end[2] = '\n'; end[3] = '\0'; file.write(begin); if (file.writeError) { ECHO_LM(ER, SERIAL_SD_ERR_WRITE_TO_FILE); } }
/** * M502 - Reset Configuration */ void Config_ResetDefault() { float tmp1[] = DEFAULT_AXIS_STEPS_PER_UNIT; float tmp2[] = DEFAULT_MAX_FEEDRATE; float tmp3[] = DEFAULT_MAX_ACCELERATION; float tmp4[] = DEFAULT_RETRACT_ACCELERATION; float tmp5[] = DEFAULT_EJERK; float tmp6[] = DEFAULT_Kp; float tmp7[] = DEFAULT_Ki; float tmp8[] = DEFAULT_Kd; float tmp9[] = DEFAULT_Kc; #if ENABLED(HOTEND_OFFSET_X) && ENABLED(HOTEND_OFFSET_Y) && ENABLED(HOTEND_OFFSET_Z) float tmp10[] = HOTEND_OFFSET_X; float tmp11[] = HOTEND_OFFSET_Y; float tmp12[] = HOTEND_OFFSET_Z; #endif #if MB(ALLIGATOR) float tmp13[] = MOTOR_CURRENT; for (int8_t i = 0; i < 3 + DRIVER_EXTRUDERS; i++) motor_current[i] = tmp13[i]; #endif for (int8_t i = 0; i < 3 + EXTRUDERS; i++) { planner.axis_steps_per_mm[i] = tmp1[i]; planner.max_feedrate[i] = tmp2[i]; planner.max_acceleration_mm_per_s2[i] = tmp3[i]; } for (int8_t i = 0; i < EXTRUDERS; i++) { planner.retract_acceleration[i] = tmp4[i]; planner.max_e_jerk[i] = tmp5[i]; } for (int8_t i = 0; i < HOTENDS; i++) { #if ENABLED(HOTEND_OFFSET_X) && ENABLED(HOTEND_OFFSET_Y) && ENABLED(HOTEND_OFFSET_Z) hotend_offset[X_AXIS][i] = tmp10[i]; hotend_offset[Y_AXIS][i] = tmp11[i]; hotend_offset[Z_AXIS][i] = tmp12[i]; #else hotend_offset[X_AXIS][i] = 0; hotend_offset[Y_AXIS][i] = 0; hotend_offset[Z_AXIS][i] = 0; #endif } #if MECH(SCARA) for (int8_t i = 0; i < NUM_AXIS; i++) { if (i < COUNT(axis_scaling)) axis_scaling[i] = 1; } #endif // steps per sq second need to be updated to agree with the units per sq second planner.reset_acceleration_rates(); planner.acceleration = DEFAULT_ACCELERATION; planner.travel_acceleration = DEFAULT_TRAVEL_ACCELERATION; planner.min_feedrate = DEFAULT_MINIMUMFEEDRATE; planner.min_segment_time = DEFAULT_MINSEGMENTTIME; planner.min_travel_feedrate = DEFAULT_MINTRAVELFEEDRATE; planner.max_xy_jerk = DEFAULT_XYJERK; planner.max_z_jerk = DEFAULT_ZJERK; home_offset[X_AXIS] = home_offset[Y_AXIS] = home_offset[Z_AXIS] = 0; #if ENABLED(MESH_BED_LEVELING) mbl.reset(); #endif #if HAS(BED_PROBE) zprobe_zoffset = Z_PROBE_OFFSET_FROM_NOZZLE; #endif #if MECH(DELTA) delta_radius = DEFAULT_DELTA_RADIUS; delta_diagonal_rod = DELTA_DIAGONAL_ROD; endstop_adj[0] = TOWER_A_ENDSTOP_ADJ; endstop_adj[1] = TOWER_B_ENDSTOP_ADJ; endstop_adj[2] = TOWER_C_ENDSTOP_ADJ; tower_adj[0] = TOWER_A_POSITION_ADJ; tower_adj[1] = TOWER_B_POSITION_ADJ; tower_adj[2] = TOWER_C_POSITION_ADJ; tower_adj[3] = TOWER_A_RADIUS_ADJ; tower_adj[4] = TOWER_B_RADIUS_ADJ; tower_adj[5] = TOWER_C_RADIUS_ADJ; diagrod_adj[0] = TOWER_A_DIAGROD_ADJ; diagrod_adj[1] = TOWER_B_DIAGROD_ADJ; diagrod_adj[2] = TOWER_C_DIAGROD_ADJ; #endif #if ENABLED(ULTIPANEL) plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP; plaPreheatHPBTemp = PLA_PREHEAT_HPB_TEMP; plaPreheatFanSpeed = PLA_PREHEAT_FAN_SPEED; absPreheatHotendTemp = ABS_PREHEAT_HOTEND_TEMP; absPreheatHPBTemp = ABS_PREHEAT_HPB_TEMP; absPreheatFanSpeed = ABS_PREHEAT_FAN_SPEED; gumPreheatHotendTemp = GUM_PREHEAT_HOTEND_TEMP; gumPreheatHPBTemp = GUM_PREHEAT_HPB_TEMP; gumPreheatFanSpeed = GUM_PREHEAT_FAN_SPEED; #endif #if HAS(LCD_CONTRAST) lcd_contrast = DEFAULT_LCD_CONTRAST; #endif #if ENABLED(PIDTEMP) for (int8_t h = 0; h < HOTENDS; h++) { Kp[h] = tmp6[h]; Ki[h] = scalePID_i(tmp7[h]); Kd[h] = scalePID_d(tmp8[h]); Kc[h] = tmp9[h]; } #if ENABLED(PID_ADD_EXTRUSION_RATE) lpq_len = 20; // default last-position-queue size #endif #endif // PIDTEMP #if ENABLED(PIDTEMPBED) bedKp = DEFAULT_bedKp; bedKi = scalePID_i(DEFAULT_bedKi); bedKd = scalePID_d(DEFAULT_bedKd); #endif #if ENABLED(PIDTEMPCHAMBER) chamberKp = DEFAULT_chamberKp; chamberKi = scalePID_i(DEFAULT_chamberKi); chamberKd = scalePID_d(DEFAULT_chamberKd); #endif #if ENABLED(PIDTEMPCOOLER) coolerKp = DEFAULT_coolerKp; coolerKi = scalePID_i(DEFAULT_coolerKi); coolerKd = scalePID_d(DEFAULT_coolerKd); #endif #if ENABLED(FWRETRACT) autoretract_enabled = false; retract_length = RETRACT_LENGTH; #if EXTRUDERS > 1 retract_length_swap = RETRACT_LENGTH_SWAP; #endif retract_feedrate = RETRACT_FEEDRATE; retract_zlift = RETRACT_ZLIFT; retract_recover_length = RETRACT_RECOVER_LENGTH; #if EXTRUDERS > 1 retract_recover_length_swap = RETRACT_RECOVER_LENGTH_SWAP; #endif retract_recover_feedrate = RETRACT_RECOVER_FEEDRATE; #endif volumetric_enabled = false; #if ENABLED(IDLE_OOZING_PREVENT) IDLE_OOZING_enabled = true; #endif Config_Postprocess(); ECHO_LM(DB, "Hardcoded Default Settings Loaded"); }
/** * M501 - Retrieve Configuration */ void Config_RetrieveSettings() { int i = EEPROM_OFFSET; char stored_ver[6]; uint16_t stored_checksum; EEPROM_READ_VAR(i, stored_ver); EEPROM_READ_VAR(i, stored_checksum); if (DEBUGGING(INFO)) { ECHO_SMV(INFO, "Version: [", version); ECHO_MV("] Stored version: [", stored_ver); ECHO_EM("]"); } if (strncmp(version, stored_ver, 5) != 0) { Config_ResetDefault(); } else { float dummy = 0; eeprom_checksum = 0; // clear before reading first "real data" // version number match EEPROM_READ_VAR(i, planner.axis_steps_per_mm); EEPROM_READ_VAR(i, planner.max_feedrate); EEPROM_READ_VAR(i, planner.max_acceleration_mm_per_s2); EEPROM_READ_VAR(i, planner.acceleration); EEPROM_READ_VAR(i, planner.retract_acceleration); EEPROM_READ_VAR(i, planner.travel_acceleration); EEPROM_READ_VAR(i, planner.min_feedrate); EEPROM_READ_VAR(i, planner.min_travel_feedrate); EEPROM_READ_VAR(i, planner.min_segment_time); EEPROM_READ_VAR(i, planner.max_xy_jerk); EEPROM_READ_VAR(i, planner.max_z_jerk); EEPROM_READ_VAR(i, planner.max_e_jerk); EEPROM_READ_VAR(i, home_offset); EEPROM_READ_VAR(i, hotend_offset); #if ENABLED(MESH_BED_LEVELING) uint8_t mesh_num_x = 0, mesh_num_y = 0; EEPROM_READ_VAR(i, mbl.status); EEPROM_READ_VAR(i, mbl.z_offset); EEPROM_READ_VAR(i, mesh_num_x); EEPROM_READ_VAR(i, mesh_num_y); EEPROM_READ_VAR(i, mbl.z_values); #endif #if HEATER_USES_AD595 EEPROM_READ_VAR(i, ad595_offset); EEPROM_READ_VAR(i, ad595_gain); for (int8_t h = 0; h < HOTENDS; h++) if (ad595_gain[h] == 0) ad595_gain[h] == TEMP_SENSOR_AD595_GAIN; #endif #if MECH(DELTA) EEPROM_READ_VAR(i, endstop_adj); EEPROM_READ_VAR(i, delta_radius); EEPROM_READ_VAR(i, delta_diagonal_rod); EEPROM_READ_VAR(i, sw_endstop_max); EEPROM_READ_VAR(i, tower_adj); EEPROM_READ_VAR(i, diagrod_adj); #endif //DELTA #if HASNT(BED_PROBE) float zprobe_zoffset = 0; #endif EEPROM_READ_VAR(i, zprobe_zoffset); #if DISABLED(ULTIPANEL) int plaPreheatHotendTemp, plaPreheatHPBTemp, plaPreheatFanSpeed, absPreheatHotendTemp, absPreheatHPBTemp, absPreheatFanSpeed, gumPreheatHotendTemp, gumPreheatHPBTemp, gumPreheatFanSpeed; #endif EEPROM_READ_VAR(i, plaPreheatHotendTemp); EEPROM_READ_VAR(i, plaPreheatHPBTemp); EEPROM_READ_VAR(i, plaPreheatFanSpeed); EEPROM_READ_VAR(i, absPreheatHotendTemp); EEPROM_READ_VAR(i, absPreheatHPBTemp); EEPROM_READ_VAR(i, absPreheatFanSpeed); EEPROM_READ_VAR(i, gumPreheatHotendTemp); EEPROM_READ_VAR(i, gumPreheatHPBTemp); EEPROM_READ_VAR(i, gumPreheatFanSpeed); #if ENABLED(PIDTEMP) for (int8_t h = 0; h < HOTENDS; h++) { EEPROM_READ_VAR(i, PID_PARAM(Kp, h)); EEPROM_READ_VAR(i, PID_PARAM(Ki, h)); EEPROM_READ_VAR(i, PID_PARAM(Kd, h)); EEPROM_READ_VAR(i, PID_PARAM(Kc, h)); } #endif // PIDTEMP #if DISABLED(PID_ADD_EXTRUSION_RATE) int lpq_len; #endif EEPROM_READ_VAR(i, lpq_len); #if ENABLED(PIDTEMPBED) EEPROM_READ_VAR(i, bedKp); EEPROM_READ_VAR(i, bedKi); EEPROM_READ_VAR(i, bedKd); #endif #if ENABLED(PIDTEMPCHAMBER) EEPROM_READ_VAR(i, chamberKp); EEPROM_READ_VAR(i, chamberKi); EEPROM_READ_VAR(i, chamberKd); #endif #if ENABLED(PIDTEMPCOOLER) EEPROM_READ_VAR(i, coolerKp); EEPROM_READ_VAR(i, coolerKi); EEPROM_READ_VAR(i, coolerKd); #endif #if HASNT(LCD_CONTRAST) int lcd_contrast; #endif EEPROM_READ_VAR(i, lcd_contrast); #if MECH(SCARA) EEPROM_READ_VAR(i, axis_scaling); // 3 floats #endif #if ENABLED(FWRETRACT) EEPROM_READ_VAR(i, autoretract_enabled); EEPROM_READ_VAR(i, retract_length); #if EXTRUDERS > 1 EEPROM_READ_VAR(i, retract_length_swap); #else EEPROM_READ_VAR(i, dummy); #endif EEPROM_READ_VAR(i, retract_feedrate); EEPROM_READ_VAR(i, retract_zlift); EEPROM_READ_VAR(i, retract_recover_length); #if EXTRUDERS > 1 EEPROM_READ_VAR(i, retract_recover_length_swap); #else EEPROM_READ_VAR(i, dummy); #endif EEPROM_READ_VAR(i, retract_recover_feedrate); #endif // FWRETRACT EEPROM_READ_VAR(i, volumetric_enabled); for (int8_t e = 0; e < EXTRUDERS; e++) EEPROM_READ_VAR(i, filament_size[e]); #if ENABLED(IDLE_OOZING_PREVENT) EEPROM_READ_VAR(i, IDLE_OOZING_enabled); #endif #if MB(ALLIGATOR) EEPROM_READ_VAR(i, motor_current); #endif if (eeprom_checksum == stored_checksum) { Config_Postprocess(); ECHO_SV(DB, version); ECHO_MV(" stored settings retrieved (", i); ECHO_EM(" bytes)"); } else { ECHO_LM(ER, "EEPROM checksum mismatch"); Config_ResetDefault(); } } #if ENABLED(EEPROM_CHITCHAT) Config_PrintSettings(); #endif }
/** * Print Configuration Settings - M503 */ void Config_PrintSettings(bool forReplay) { // Always have this function, even with EEPROM_SETTINGS disabled, the current values will be shown if (!forReplay) { ECHO_LM(CFG, "Steps per unit:"); } ECHO_SMV(CFG, " M92 X", axis_steps_per_unit[X_AXIS]); ECHO_MV(" Y", axis_steps_per_unit[Y_AXIS]); ECHO_MV(" Z", axis_steps_per_unit[Z_AXIS]); ECHO_EMV(" E", axis_steps_per_unit[E_AXIS]); #if EXTRUDERS > 1 for (short i = 1; i < EXTRUDERS; i++) { ECHO_SMV(CFG, " M92 T", i); ECHO_EMV(" E", axis_steps_per_unit[E_AXIS + i]); } #endif //EXTRUDERS > 1 #if MECH(SCARA) if (!forReplay) { ECHO_LM(CFG, "Scaling factors:"); } ECHO_SMV(CFG, " M365 X", axis_scaling[X_AXIS]); ECHO_MV(" Y", axis_scaling[Y_AXIS]); ECHO_EMV(" Z", axis_scaling[Z_AXIS]); #endif // SCARA if (!forReplay) { ECHO_LM(CFG, "Maximum feedrates (mm/s):"); } ECHO_SMV(CFG, " M203 X", max_feedrate[X_AXIS]); ECHO_MV(" Y", max_feedrate[Y_AXIS] ); ECHO_MV(" Z", max_feedrate[Z_AXIS] ); ECHO_EMV(" E", max_feedrate[E_AXIS]); #if EXTRUDERS > 1 for (short i = 1; i < EXTRUDERS; i++) { ECHO_SMV(CFG, " M203 T", i); ECHO_EMV(" E", max_feedrate[E_AXIS + i]); } #endif //EXTRUDERS > 1 if (!forReplay) { ECHO_LM(CFG, "Maximum Acceleration (mm/s2):"); } ECHO_SMV(CFG, " M201 X", max_acceleration_units_per_sq_second[X_AXIS] ); ECHO_MV(" Y", max_acceleration_units_per_sq_second[Y_AXIS] ); ECHO_MV(" Z", max_acceleration_units_per_sq_second[Z_AXIS] ); ECHO_EMV(" E", max_acceleration_units_per_sq_second[E_AXIS]); #if EXTRUDERS > 1 for (int8_t i = 1; i < EXTRUDERS; i++) { ECHO_SMV(CFG, " M201 T", i); ECHO_EMV(" E", max_acceleration_units_per_sq_second[E_AXIS + i]); } #endif //EXTRUDERS > 1 ECHO_E; if (!forReplay) { ECHO_LM(CFG, "Accelerations: P=printing, V=travel and T* R=retract"); } ECHO_SMV(CFG," M204 P", acceleration); ECHO_EMV(" V", travel_acceleration); #if EXTRUDERS > 0 for (int8_t i = 0; i < EXTRUDERS; i++) { ECHO_SMV(CFG, " M204 T", i); ECHO_EMV(" R", retract_acceleration[i]); } #endif if (!forReplay) { ECHO_LM(CFG, "Advanced variables: S=Min feedrate (mm/s), V=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)"); } ECHO_SMV(CFG, " M205 S", minimumfeedrate ); ECHO_MV(" V", mintravelfeedrate ); ECHO_MV(" B", minsegmenttime ); ECHO_MV(" X", max_xy_jerk ); ECHO_MV(" Z", max_z_jerk); ECHO_EMV(" E", max_e_jerk[0]); #if (EXTRUDERS > 1) for(int8_t i = 1; i < EXTRUDERS; i++) { ECHO_SMV(CFG, " M205 T", i); ECHO_EMV(" E" , max_e_jerk[i]); } #endif if (!forReplay) { ECHO_LM(CFG, "Home offset (mm):"); } ECHO_SMV(CFG, " M206 X", home_offset[X_AXIS] ); ECHO_MV(" Y", home_offset[Y_AXIS] ); ECHO_EMV(" Z", home_offset[Z_AXIS] ); if (!forReplay) { ECHO_LM(CFG, "Hotend offset (mm):"); } for (int8_t h = 0; h < HOTENDS; h++) { ECHO_SMV(CFG, " M218 T", h); ECHO_MV(" X", hotend_offset[X_AXIS][h]); ECHO_MV(" Y", hotend_offset[Y_AXIS][h]); ECHO_EMV(" Z", hotend_offset[Z_AXIS][h]); } #if HEATER_USES_AD595 if (!forReplay) { ECHO_LM(CFG, "AD595 Offset and Gain:"); } for (int8_t h = 0; h < HOTENDS; h++) { ECHO_SMV(CFG, " M595 T", h); ECHO_MV(" O", ad595_offset[h]); ECHO_EMV(", S", ad595_gain[h]); } #endif // HEATER_USES_AD595 #if MECH(DELTA) if (!forReplay) { ECHO_LM(CFG, "Delta Geometry adjustment:"); } ECHO_SMV(CFG, " M666 A", tower_adj[0], 3); ECHO_MV(" B", tower_adj[1], 3); ECHO_MV(" C", tower_adj[2], 3); ECHO_MV(" I", tower_adj[3], 3); ECHO_MV(" J", tower_adj[4], 3); ECHO_MV(" K", tower_adj[5], 3); ECHO_MV(" U", diagrod_adj[0], 3); ECHO_MV(" V", diagrod_adj[1], 3); ECHO_MV(" W", diagrod_adj[2], 3); ECHO_MV(" R", delta_radius); ECHO_MV(" D", delta_diagonal_rod); ECHO_EMV(" H", sw_endstop_max[2]); if (!forReplay) { ECHO_LM(CFG, "Endstop Offsets:"); } ECHO_SMV(CFG, " M666 X", endstop_adj[X_AXIS]); ECHO_MV(" Y", endstop_adj[Y_AXIS]); ECHO_EMV(" Z", endstop_adj[Z_AXIS]); if (!forReplay) { ECHO_LM(CFG, "Z-Probe Offset:"); } ECHO_SMV(CFG, " M666 P X", z_probe_offset[0]); ECHO_MV(" Y", z_probe_offset[1]); ECHO_EMV(" Z", z_probe_offset[2]); #elif ENABLED(Z_DUAL_ENDSTOPS) if (!forReplay) { ECHO_LM(CFG, "Z2 Endstop adjustement (mm):"); } ECHO_LMV(CFG, " M666 Z", z_endstop_adj ); #elif ENABLED(AUTO_BED_LEVELING_FEATURE) if (!forReplay) { ECHO_LM(CFG, "Z Probe offset (mm)"); } ECHO_LMV(CFG, " M666 P", zprobe_zoffset); #endif #if ENABLED(ULTIPANEL) if (!forReplay) { ECHO_LM(CFG, "Material heatup parameters:"); } ECHO_SMV(CFG, " M145 S0 H", plaPreheatHotendTemp); ECHO_MV(" B", plaPreheatHPBTemp); ECHO_MV(" F", plaPreheatFanSpeed); ECHO_EM(" (Material PLA)"); ECHO_SMV(CFG, " M145 S1 H", absPreheatHotendTemp); ECHO_MV(" B", absPreheatHPBTemp); ECHO_MV(" F", absPreheatFanSpeed); ECHO_EM(" (Material ABS)"); ECHO_SMV(CFG, " M145 S2 H", gumPreheatHotendTemp); ECHO_MV(" B", gumPreheatHPBTemp); ECHO_MV(" F", gumPreheatFanSpeed); ECHO_EM(" (Material GUM)"); #endif // ULTIPANEL #if ENABLED(PIDTEMP) || ENABLED(PIDTEMPBED) if (!forReplay) { ECHO_LM(CFG, "PID settings:"); } #if ENABLED(PIDTEMP) for (uint8_t h = 0; h < HOTENDS; h++) { ECHO_SMV(CFG, " M301 H", h); ECHO_MV(" P", PID_PARAM(Kp, h)); ECHO_MV(" I", unscalePID_i(PID_PARAM(Ki, h))); ECHO_MV(" D", unscalePID_d(PID_PARAM(Kd, h))); #if ENABLED(PID_ADD_EXTRUSION_RATE) ECHO_MV(" C", PID_PARAM(Kc, h)); #endif ECHO_E; } #if ENABLED(PID_ADD_EXTRUSION_RATE) ECHO_SMV(CFG, " M301 L", lpq_len); #endif #endif #if ENABLED(PIDTEMPBED) ECHO_SMV(CFG, " M304 P", bedKp); // for compatibility with hosts, only echos values for E0 ECHO_MV(" I", unscalePID_i(bedKi)); ECHO_EMV(" D", unscalePID_d(bedKd)); #endif #endif #if ENABLED(FWRETRACT) if (!forReplay) { ECHO_LM(CFG, "Retract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)"); } ECHO_SMV(CFG, " M207 S", retract_length); ECHO_MV(" F", retract_feedrate*60); ECHO_EMV(" Z", retract_zlift); if (!forReplay) { ECHO_LM(CFG, "Recover: S=Extra length (mm) F:Speed (mm/m)"); } ECHO_SMV(CFG, " M208 S", retract_recover_length); ECHO_MV(" F", retract_recover_feedrate*60); if (!forReplay) { ECHO_LM(CFG, "Auto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries"); } ECHO_LMV(CFG, " M209 S", autoretract_enabled); #if EXTRUDERS > 1 if (!forReplay) { ECHO_LM(CFG, "Multi-extruder settings:"); ECHO_LMV(CFG, " Swap retract length (mm): ", retract_length_swap); ECHO_LMV(CFG, " Swap rec. addl. length (mm): ", retract_recover_length_swap); } #endif // EXTRUDERS > 1 #endif // FWRETRACT if (volumetric_enabled) { if (!forReplay) { ECHO_LM(CFG, "Filament settings:"); } ECHO_LMV(CFG, " M200 D", filament_size[0]); #if EXTRUDERS > 1 ECHO_LMV(CFG, " M200 T1 D", filament_size[1]); #if EXTRUDERS > 2 ECHO_LMV(CFG, " M200 T2 D", filament_size[2]); #if EXTRUDERS > 3 ECHO_LMV(CFG, " M200 T3 D", filament_size[3]); #endif #endif #endif } else { if (!forReplay) { ECHO_LM(CFG, "Filament settings: Disabled"); } } #if MB(ALLIGATOR) if (!forReplay) { ECHO_LM(CFG, "Current:"); } ECHO_SMV(CFG, " M906 X", motor_current[X_AXIS]); ECHO_MV(" Y", motor_current[Y_AXIS]); ECHO_MV(" Z", motor_current[Z_AXIS]); ECHO_EMV(" E", motor_current[E_AXIS]); #if DRIVER_EXTRUDERS > 1 for (uint8_t i = 1; i < DRIVER_EXTRUDERS; i++) { ECHO_SMV(CFG, " M906 T", i); ECHO_EMV(" E", motor_current[E_AXIS + i]); } #endif // DRIVER_EXTRUDERS > 1 #endif // ALLIGATOR ConfigSD_PrintSettings(forReplay); }
/** * Reset Configuration Settings - M502 */ void Config_ResetDefault() { float tmp1[] = DEFAULT_AXIS_STEPS_PER_UNIT; float tmp2[] = DEFAULT_MAX_FEEDRATE; float tmp3[] = DEFAULT_MAX_ACCELERATION; float tmp4[] = DEFAULT_RETRACT_ACCELERATION; float tmp5[] = DEFAULT_EJERK; #if ENABLED(PIDTEMP) float tmp6[] = DEFAULT_Kp; float tmp7[] = DEFAULT_Ki; float tmp8[] = DEFAULT_Kd; float tmp9[] = DEFAULT_Kc; #endif // PIDTEMP #if ENABLED(HOTEND_OFFSET_X) && ENABLED(HOTEND_OFFSET_Y) && ENABLED(HOTEND_OFFSET_Z) float tmp10[] = HOTEND_OFFSET_X; float tmp11[] = HOTEND_OFFSET_Y; float tmp12[] = HOTEND_OFFSET_Z; #else float tmp10[] = {0}; float tmp11[] = {0}; float tmp12[] = {0}; #endif #if MB(ALLIGATOR) float tmp13[] = MOTOR_CURRENT; #endif for (int8_t i = 0; i < 3 + EXTRUDERS; i++) { short max_i; max_i = sizeof(tmp1) / sizeof(*tmp1); if(i < max_i) axis_steps_per_unit[i] = tmp1[i]; else axis_steps_per_unit[i] = tmp1[max_i - 1]; max_i = sizeof(tmp2) / sizeof(*tmp2); if(i < max_i) max_feedrate[i] = tmp2[i]; else max_feedrate[i] = tmp2[max_i - 1]; max_i = sizeof(tmp3) / sizeof(*tmp3); if(i < max_i) max_acceleration_units_per_sq_second[i] = tmp3[i]; else max_acceleration_units_per_sq_second[i] = tmp3[max_i - 1]; if(i < EXTRUDERS) { max_i = sizeof(tmp4) / sizeof(*tmp4); if(i < max_i) retract_acceleration[i] = tmp4[i]; else retract_acceleration[i] = tmp4[max_i - 1]; max_i = sizeof(tmp5) / sizeof(*tmp5); if(i < max_i) max_e_jerk[i] = tmp5[i]; else max_e_jerk[i] = tmp5[max_i - 1]; max_i = sizeof(tmp10) / sizeof(*tmp10); if(i < max_i) hotend_offset[X_AXIS][i] = tmp10[i]; else hotend_offset[X_AXIS][i] = 0; max_i = sizeof(tmp11) / sizeof(*tmp11); if(i < max_i) hotend_offset[Y_AXIS][i] = tmp11[i]; else hotend_offset[Y_AXIS][i] = 0; max_i = sizeof(tmp12) / sizeof(*tmp12); if(i < max_i) hotend_offset[Z_AXIS][i] = tmp12[i]; else hotend_offset[Z_AXIS][i] = 0; } #if MB(ALLIGATOR) max_i = sizeof(tmp13) / sizeof(*tmp13); if(i < max_i) motor_current[i] = tmp13[i]; else motor_current[i] = tmp13[max_i - 1]; #endif } #if MECH(SCARA) for (int8_t i = 0; i < NUM_AXIS; i++) { if (i < COUNT(axis_scaling)) axis_scaling[i] = 1; } #endif // steps per sq second need to be updated to agree with the units per sq second reset_acceleration_rates(); acceleration = DEFAULT_ACCELERATION; travel_acceleration = DEFAULT_TRAVEL_ACCELERATION; minimumfeedrate = DEFAULT_MINIMUMFEEDRATE; minsegmenttime = DEFAULT_MINSEGMENTTIME; mintravelfeedrate = DEFAULT_MINTRAVELFEEDRATE; max_xy_jerk = DEFAULT_XYJERK; max_z_jerk = DEFAULT_ZJERK; home_offset[X_AXIS] = home_offset[Y_AXIS] = home_offset[Z_AXIS] = 0; #if ENABLED(AUTO_BED_LEVELING_FEATURE) zprobe_zoffset = Z_PROBE_OFFSET_FROM_EXTRUDER; #elif !MECH(DELTA) zprobe_zoffset = 0; #endif #if MECH(DELTA) delta_radius = DEFAULT_DELTA_RADIUS; delta_diagonal_rod = DELTA_DIAGONAL_ROD; endstop_adj[0] = TOWER_A_ENDSTOP_ADJ; endstop_adj[1] = TOWER_B_ENDSTOP_ADJ; endstop_adj[2] = TOWER_C_ENDSTOP_ADJ; tower_adj[0] = TOWER_A_POSITION_ADJ; tower_adj[1] = TOWER_B_POSITION_ADJ; tower_adj[2] = TOWER_C_POSITION_ADJ; tower_adj[3] = TOWER_A_RADIUS_ADJ; tower_adj[4] = TOWER_B_RADIUS_ADJ; tower_adj[5] = TOWER_C_RADIUS_ADJ; diagrod_adj[0] = TOWER_A_DIAGROD_ADJ; diagrod_adj[1] = TOWER_B_DIAGROD_ADJ; diagrod_adj[2] = TOWER_C_DIAGROD_ADJ; z_probe_offset[0] = X_PROBE_OFFSET_FROM_EXTRUDER; z_probe_offset[1] = Y_PROBE_OFFSET_FROM_EXTRUDER; z_probe_offset[2] = Z_PROBE_OFFSET_FROM_EXTRUDER; set_delta_constants(); #endif #if ENABLED(ULTIPANEL) plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP; plaPreheatHPBTemp = PLA_PREHEAT_HPB_TEMP; plaPreheatFanSpeed = PLA_PREHEAT_FAN_SPEED; absPreheatHotendTemp = ABS_PREHEAT_HOTEND_TEMP; absPreheatHPBTemp = ABS_PREHEAT_HPB_TEMP; absPreheatFanSpeed = ABS_PREHEAT_FAN_SPEED; gumPreheatHotendTemp = GUM_PREHEAT_HOTEND_TEMP; gumPreheatHPBTemp = GUM_PREHEAT_HPB_TEMP; gumPreheatFanSpeed = GUM_PREHEAT_FAN_SPEED; #endif #if HAS(LCD_CONTRAST) lcd_contrast = DEFAULT_LCD_CONTRAST; #endif #if ENABLED(PIDTEMP) for (int8_t h = 0; h < HOTENDS; h++) { Kp[h] = tmp6[h]; Ki[h] = scalePID_i(tmp7[h]); Kd[h] = scalePID_d(tmp8[h]); Kc[h] = tmp9[h]; } #if ENABLED(PID_ADD_EXTRUSION_RATE) lpq_len = 20; // default last-position-queue size #endif // call updatePID (similar to when we have processed M301) updatePID(); #endif // PIDTEMP #if ENABLED(PIDTEMPBED) bedKp = DEFAULT_bedKp; bedKi = scalePID_i(DEFAULT_bedKi); bedKd = scalePID_d(DEFAULT_bedKd); #endif #if ENABLED(FWRETRACT) autoretract_enabled = false; retract_length = RETRACT_LENGTH; #if EXTRUDERS > 1 retract_length_swap = RETRACT_LENGTH_SWAP; #endif retract_feedrate = RETRACT_FEEDRATE; retract_zlift = RETRACT_ZLIFT; retract_recover_length = RETRACT_RECOVER_LENGTH; #if EXTRUDERS > 1 retract_recover_length_swap = RETRACT_RECOVER_LENGTH_SWAP; #endif retract_recover_feedrate = RETRACT_RECOVER_FEEDRATE; #endif volumetric_enabled = false; calculate_volumetric_multipliers(); #if ENABLED(IDLE_OOZING_PREVENT) IDLE_OOZING_enabled = true; #endif ECHO_LM(DB, "Hardcoded Default Settings Loaded"); }
void lcd_init() { HAL::delayMilliseconds(2000); for (uint8_t i = 0; i < 10; i++) { NextionON = nexInit(); if (NextionON) break; delay(1000); } if (!NextionON) { ECHO_LM(DB, "Nextion LCD not connected!"); } else { ECHO_LM(DB, "Nextion LCD connected!"); Pstart.attachPop(ExitPopCallback); Exit1.attachPop(ExitPopCallback); Exit3.attachPop(ExitPopCallback); #if ENABLED(NEXTION_GFX) gfx.color_set(VC_AXIS + X_AXIS, 63488); gfx.color_set(VC_AXIS + Y_AXIS, 2016); gfx.color_set(VC_AXIS + Z_AXIS, 31); gfx.color_set(VC_MOVE, 2047); gfx.color_set(VC_TOOL, 65535); #endif #if ENABLED(SDSUPPORT) MSD1.attachPop(setpageSDPopCallback); MSD3.attachPop(setpageSDPopCallback); MSD5.attachPop(setpageSDPopCallback); MSD6.attachPop(setpageSDPopCallback); sdlist.attachPop(sdlistPopCallback); ScrollUp.attachPop(sdlistPopCallback); ScrollDown.attachPop(sdlistPopCallback); Exit2.attachPop(ExitPopCallback); NPlay.attachPop(PlayPausePopCallback); NStop.attachPop(StopPopCallback); #endif #if HAS_TEMP_0 hot0.attachPop(hotPopCallback, &hot0); #endif #if HAS_TEMP_1 hot1.attachPop(hotPopCallback, &hot1); #endif #if HAS_TEMP_2 || HAS_TEMP_BED hot2.attachPop(hotPopCallback, &hot2); #endif Fanpic.attachPop(setfanPopCallback, &Fanpic); m11.attachPop(sethotPopCallback, &m11); tup.attachPop(settempPopCallback, &tup); tdown.attachPop(settempPopCallback, &tdown); XYHome.attachPop(setmovePopCallback); XYUp.attachPop(setmovePopCallback); XYRight.attachPop(setmovePopCallback); XYDown.attachPop(setmovePopCallback); XYLeft.attachPop(setmovePopCallback); ZHome.attachPop(setmovePopCallback); ZUp.attachPop(setmovePopCallback); ZDown.attachPop(setmovePopCallback); SpeedOk.attachPop(ExitPopCallback); Benter.attachPop(setgcodePopCallback); startimer.enable(); } }
void plan_buffer_line(const float& x, const float& y, const float& z, const float& e, float feed_rate, const uint8_t extruder, const uint8_t driver) #endif // AUTO_BED_LEVELING_FEATURE { #if ENABLED(ZWOBBLE) // Calculate ZWobble zwobble.InsertCorrection(z); #endif #if ENABLED(HYSTERESIS) // Calculate Hysteresis hysteresis.InsertCorrection(x, y, z, e); #endif // Calculate the buffer head after we push this byte int next_buffer_head = next_block_index(block_buffer_head); // If the buffer is full: good! That means we are well ahead of the robot. // Rest here until there is room in the buffer. while (block_buffer_tail == next_buffer_head) idle(); #if ENABLED(AUTO_BED_LEVELING_FEATURE) apply_rotation_xyz(plan_bed_level_matrix, x, y, z); #endif // The target position of the tool in absolute steps // Calculate target position in absolute steps //this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow long target[NUM_AXIS]; target[X_AXIS] = lround(x * axis_steps_per_unit[X_AXIS]); target[Y_AXIS] = lround(y * axis_steps_per_unit[Y_AXIS]); target[Z_AXIS] = lround(z * axis_steps_per_unit[Z_AXIS]); target[E_AXIS] = lround(e * axis_steps_per_unit[E_AXIS + extruder]); // If changing extruder have to recalculate current position based on // the steps-per-mm value for the new extruder. #if EXTRUDERS > 1 if(last_extruder != extruder && axis_steps_per_unit[E_AXIS + extruder] != axis_steps_per_unit[E_AXIS + last_extruder]) { float factor = float(axis_steps_per_unit[E_AXIS + extruder]) / float(axis_steps_per_unit[E_AXIS + last_extruder]); position[E_AXIS] = lround(position[E_AXIS] * factor); } #endif long dx = target[X_AXIS] - position[X_AXIS], dy = target[Y_AXIS] - position[Y_AXIS], dz = target[Z_AXIS] - position[Z_AXIS], de = target[E_AXIS] - position[E_AXIS]; #if MECH(COREXY) long da = dx + COREX_YZ_FACTOR * dy; long db = dx - COREX_YZ_FACTOR * dy; #elif MECH(COREXZ) long da = dx + COREX_YZ_FACTOR * dz; long dc = dx - COREX_YZ_FACTOR * dz; #endif #if ENABLED(PREVENT_DANGEROUS_EXTRUDE) if (de) { #if ENABLED(NPR2) if (extruder != 1) #endif { if (degHotend(extruder) < extrude_min_temp && !(debugLevel & DEBUG_DRYRUN)) { position[E_AXIS] = target[E_AXIS]; //behave as if the move really took place, but ignore E part de = 0; // no difference ECHO_LM(ER, SERIAL_ERR_COLD_EXTRUDE_STOP); } } #if ENABLED(PREVENT_LENGTHY_EXTRUDE) if (labs(de) > axis_steps_per_unit[E_AXIS + extruder] * (EXTRUDE_MAXLENGTH)) { #if ENABLED(EASY_LOAD) if (!allow_lengthy_extrude_once) { #endif position[E_AXIS] = target[E_AXIS]; // Behave as if the move really took place, but ignore E part de = 0; // no difference ECHO_LM(ER, SERIAL_ERR_LONG_EXTRUDE_STOP); #if ENABLED(EASY_LOAD) } allow_lengthy_extrude_once = false; #endif } #endif // PREVENT_LENGTHY_EXTRUDE } #endif // PREVENT_DANGEROUS_EXTRUDE // Prepare to set up new block block_t* block = &block_buffer[block_buffer_head]; // Mark block as not busy (Not executed by the stepper interrupt) block->busy = false; // Number of steps for each axis #if MECH(COREXY) // corexy planning // these equations follow the form of the dA and dB equations on http://www.corexy.com/theory.html block->steps[A_AXIS] = labs(da); block->steps[B_AXIS] = labs(db); block->steps[Z_AXIS] = labs(dz); #elif MECH(COREXZ) // corexz planning block->steps[A_AXIS] = labs(da); block->steps[Y_AXIS] = labs(dy); block->steps[C_AXIS] = labs(dc); #else // default non-h-bot planning block->steps[X_AXIS] = labs(dx); block->steps[Y_AXIS] = labs(dy); block->steps[Z_AXIS] = labs(dz); #endif block->steps[E_AXIS] = labs(de); block->steps[E_AXIS] *= volumetric_multiplier[extruder]; block->steps[E_AXIS] *= extruder_multiplier[extruder]; block->steps[E_AXIS] /= 100; block->step_event_count = max(block->steps[X_AXIS], max(block->steps[Y_AXIS], max(block->steps[Z_AXIS], block->steps[E_AXIS]))); // Bail if this is a zero-length block if (block->step_event_count <= DROP_SEGMENTS) return; block->fan_speed = fanSpeed; #if ENABLED(BARICUDA) block->valve_pressure = ValvePressure; block->e_to_p_pressure = EtoPPressure; #endif // For a mixing extruder, get steps for each #if ENABLED(COLOR_MIXING_EXTRUDER) for (uint8_t i = 0; i < DRIVER_EXTRUDERS; i++) block->mix_event_count[i] = block->step_event_count / mixing_factor[i]; #endif // Add update block variables for LASER BEAM control #if ENABLED(LASERBEAM) block->laser_ttlmodulation = laser_ttl_modulation; #endif // Compute direction bits for this block uint8_t dirb = 0; #if MECH(COREXY) if (dx < 0) SBI(dirb, X_HEAD); // Save the real Extruder (head) direction in X Axis if (dy < 0) SBI(dirb, Y_HEAD); // ...and Y if (dz < 0) SBI(dirb, Z_AXIS); if (da < 0) SBI(dirb, A_AXIS); // Motor A direction if (db < 0) SBI(dirb, B_AXIS); // Motor B direction #elif MECH(COREXZ) if (dx < 0) SBI(dirb, X_HEAD); // Save the real Extruder (head) direction in X Axis if (dy < 0) SBI(dirb, Y_AXIS); if (dz < 0) SBI(dirb, Z_HEAD); // ...and Z if (da < 0) SBI(dirb, A_AXIS); // Motor A direction if (dc < 0) SBI(dirb, C_AXIS); // Motor B direction #else if (dx < 0) SBI(dirb, X_AXIS); if (dy < 0) SBI(dirb, Y_AXIS); if (dz < 0) SBI(dirb, Z_AXIS); #endif if (de < 0) SBI(dirb, E_AXIS); block->direction_bits = dirb; block->active_driver = driver; // Enable active axes #if MECH(COREXY) if (block->steps[A_AXIS] || block->steps[B_AXIS]) { enable_x(); enable_y(); } #if DISABLED(Z_LATE_ENABLE) if (block->steps[Z_AXIS]) enable_z(); #endif #elif MECH(COREXZ) if (block->steps[A_AXIS] || block->steps[C_AXIS]) { enable_x(); enable_z(); } if (block->steps[Y_AXIS]) enable_y(); #else if (block->steps[X_AXIS]) enable_x(); if (block->steps[Y_AXIS]) enable_y(); #if DISABLED(Z_LATE_ENABLE) if (block->steps[Z_AXIS]) enable_z(); #endif #endif // Enable extruder(s) if (block->steps[E_AXIS]) { #if DISABLED(MKR4) && DISABLED(NPR2) if (DISABLE_INACTIVE_EXTRUDER) { //enable only selected extruder for (int i = 0; i < EXTRUDERS; i++) if (g_uc_extruder_last_move[i] > 0) g_uc_extruder_last_move[i]--; switch(extruder) { case 0: enable_e0(); g_uc_extruder_last_move[0] = (BLOCK_BUFFER_SIZE) * 2; #if EXTRUDERS > 1 if (g_uc_extruder_last_move[1] == 0) disable_e1(); #if EXTRUDERS > 2 if (g_uc_extruder_last_move[2] == 0) disable_e2(); #if EXTRUDERS > 3 if (g_uc_extruder_last_move[3] == 0) disable_e3(); #if EXTRUDERS > 4 if (g_uc_extruder_last_move[4] == 0) disable_e4(); #if EXTRUDERS > 5 if (g_uc_extruder_last_move[5] == 0) disable_e5(); #endif #endif #endif #endif #endif break; #if EXTRUDERS > 1 case 1: enable_e1(); g_uc_extruder_last_move[1] = (BLOCK_BUFFER_SIZE) * 2; if (g_uc_extruder_last_move[0] == 0) disable_e0(); #if EXTRUDERS > 2 if (g_uc_extruder_last_move[2] == 0) disable_e2(); #if EXTRUDERS > 3 if (g_uc_extruder_last_move[3] == 0) disable_e3(); #if EXTRUDERS > 4 if (g_uc_extruder_last_move[4] == 0) disable_e4(); #if EXTRUDERS > 5 if (g_uc_extruder_last_move[5] == 0) disable_e5(); #endif #endif #endif #endif break; #if EXTRUDERS > 2 case 2: enable_e2(); g_uc_extruder_last_move[2] = (BLOCK_BUFFER_SIZE) * 2; if (g_uc_extruder_last_move[0] == 0) disable_e0(); if (g_uc_extruder_last_move[1] == 0) disable_e1(); #if EXTRUDERS > 3 if (g_uc_extruder_last_move[3] == 0) disable_e3(); #if EXTRUDERS > 4 if (g_uc_extruder_last_move[4] == 0) disable_e4(); #if EXTRUDERS > 5 if (g_uc_extruder_last_move[5] == 0) disable_e5(); #endif #endif #endif break; #if EXTRUDERS > 3 case 3: enable_e3(); g_uc_extruder_last_move[3] = (BLOCK_BUFFER_SIZE) * 2; if (g_uc_extruder_last_move[0] == 0) disable_e0(); if (g_uc_extruder_last_move[1] == 0) disable_e1(); if (g_uc_extruder_last_move[2] == 0) disable_e2(); #if EXTRUDERS > 4 if (g_uc_extruder_last_move[4] == 0) disable_e4(); #if EXTRUDERS > 5 if (g_uc_extruder_last_move[5] == 0) disable_e5(); #endif #endif break; #if EXTRUDERS > 4 case 4: enable_e4(); g_uc_extruder_last_move[4] = (BLOCK_BUFFER_SIZE) * 2; if (g_uc_extruder_last_move[0] == 0) disable_e0(); if (g_uc_extruder_last_move[1] == 0) disable_e1(); if (g_uc_extruder_last_move[2] == 0) disable_e2(); if (g_uc_extruder_last_move[3] == 0) disable_e3(); #if EXTRUDERS > 5 if (g_uc_extruder_last_move[5] == 0) disable_e5(); #endif break; #if EXTRUDERS > 5 case 4: enable_e5(); g_uc_extruder_last_move[5] = (BLOCK_BUFFER_SIZE) * 2; if (g_uc_extruder_last_move[0] == 0) disable_e0(); if (g_uc_extruder_last_move[1] == 0) disable_e1(); if (g_uc_extruder_last_move[2] == 0) disable_e2(); if (g_uc_extruder_last_move[3] == 0) disable_e3(); if (g_uc_extruder_last_move[4] == 0) disable_e4(); break; #endif // EXTRUDERS > 5 #endif // EXTRUDERS > 4 #endif // EXTRUDERS > 3 #endif // EXTRUDERS > 2 #endif // EXTRUDERS > 1 } } else //enable all { enable_e0(); enable_e1(); enable_e2(); enable_e3(); enable_e4(); enable_e5(); } #else //MKR4 or NPr2 switch(extruder) { case 0: enable_e0(); break; case 1: enable_e1(); break; case 2: enable_e0(); break; case 3: enable_e1(); break; } #endif //!MKR4 && !NPR2 } if (block->steps[E_AXIS]) NOLESS(feed_rate, minimumfeedrate); else NOLESS(feed_rate, mintravelfeedrate); /** * This part of the code calculates the total length of the movement. * For cartesian bots, the X_AXIS is the real X movement and same for Y_AXIS. * But for corexy bots, that is not true. The "X_AXIS" and "Y_AXIS" motors (that should be named to A_AXIS * and B_AXIS) cannot be used for X and Y length, because A=X+Y and B=X-Y. * So we need to create other 2 "AXIS", named X_HEAD and Y_HEAD, meaning the real displacement of the Head. * Having the real displacement of the head, we can calculate the total movement length and apply the desired speed. */ #if MECH(COREXY) float delta_mm[6]; delta_mm[X_HEAD] = dx / axis_steps_per_unit[A_AXIS]; delta_mm[Y_HEAD] = dy / axis_steps_per_unit[B_AXIS]; delta_mm[Z_AXIS] = dz / axis_steps_per_unit[Z_AXIS]; delta_mm[A_AXIS] = da / axis_steps_per_unit[A_AXIS]; delta_mm[B_AXIS] = db / axis_steps_per_unit[B_AXIS]; #elif MECH(COREXZ) float delta_mm[6]; delta_mm[X_HEAD] = dx / axis_steps_per_unit[A_AXIS]; delta_mm[Y_AXIS] = dy / axis_steps_per_unit[Y_AXIS]; delta_mm[Z_HEAD] = dz / axis_steps_per_unit[C_AXIS]; delta_mm[A_AXIS] = da / axis_steps_per_unit[A_AXIS]; delta_mm[C_AXIS] = dc / axis_steps_per_unit[C_AXIS]; #else float delta_mm[4]; delta_mm[X_AXIS] = dx / axis_steps_per_unit[X_AXIS]; delta_mm[Y_AXIS] = dy / axis_steps_per_unit[Y_AXIS]; delta_mm[Z_AXIS] = dz / axis_steps_per_unit[Z_AXIS]; #endif delta_mm[E_AXIS] = (de / axis_steps_per_unit[E_AXIS + extruder]) * volumetric_multiplier[extruder] * extruder_multiplier[extruder] / 100.0; if (block->steps[X_AXIS] <= DROP_SEGMENTS && block->steps[Y_AXIS] <= DROP_SEGMENTS && block->steps[Z_AXIS] <= DROP_SEGMENTS) { block->millimeters = fabs(delta_mm[E_AXIS]); } else { block->millimeters = sqrt( #if MECH(COREXY) square(delta_mm[X_HEAD]) + square(delta_mm[Y_HEAD]) + square(delta_mm[Z_AXIS]) #elif MECH(COREXZ) square(delta_mm[X_HEAD]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_HEAD]) #else square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_AXIS]) #endif ); } float inverse_millimeters = 1.0 / block->millimeters; // Inverse millimeters to remove multiple divides // Calculate speed in mm/second for each axis. No divide by zero due to previous checks. float inverse_second = feed_rate * inverse_millimeters; int moves_queued = movesplanned(); // Slow down when the buffer starts to empty, rather than wait at the corner for a buffer refill #if ENABLED(OLD_SLOWDOWN) || ENABLED(SLOWDOWN) bool mq = moves_queued > 1 && moves_queued < (BLOCK_BUFFER_SIZE) / 2; #if ENABLED(OLD_SLOWDOWN) if (mq) feed_rate *= 2.0 * moves_queued / (BLOCK_BUFFER_SIZE); #endif #if ENABLED(SLOWDOWN) // segment time im micro seconds unsigned long segment_time = lround(1000000.0 / inverse_second); if (mq) { if (segment_time < minsegmenttime) { // buffer is draining, add extra time. The amount of time added increases if the buffer is still emptied more. inverse_second = 1000000.0 / (segment_time + lround(2 * (minsegmenttime - segment_time) / moves_queued)); #if ENABLED(XY_FREQUENCY_LIMIT) segment_time = lround(1000000.0 / inverse_second); #endif } } #endif #endif block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0 block->nominal_rate = ceil(block->step_event_count * inverse_second); // (step/sec) Always > 0 #if ENABLED(FILAMENT_SENSOR) //FMM update ring buffer used for delay with filament measurements if (extruder == FILAMENT_SENSOR_EXTRUDER_NUM && delay_index2 > -1) { //only for extruder with filament sensor and if ring buffer is initialized const int MMD = MAX_MEASUREMENT_DELAY + 1, MMD10 = MMD * 10; delay_dist += delta_mm[E_AXIS]; // increment counter with next move in e axis while (delay_dist >= MMD10) delay_dist -= MMD10; // loop around the buffer while (delay_dist < 0) delay_dist += MMD10; delay_index1 = delay_dist / 10.0; // calculate index delay_index1 = constrain(delay_index1, 0, MAX_MEASUREMENT_DELAY); // (already constrained above) if (delay_index1 != delay_index2) { // moved index meas_sample = widthFil_to_size_ratio() - 100; // Subtract 100 to reduce magnitude - to store in a signed char while (delay_index1 != delay_index2) { // Increment and loop around buffer if (++delay_index2 >= MMD) delay_index2 -= MMD; delay_index2 = constrain(delay_index2, 0, MAX_MEASUREMENT_DELAY); measurement_delay[delay_index2] = meas_sample; } } } #endif // Calculate and limit speed in mm/sec for each axis float current_speed[NUM_AXIS]; float speed_factor = 1.0; //factor <=1 do decrease speed for (int i = 0; i < NUM_AXIS; i++) { current_speed[i] = delta_mm[i] * inverse_second; float cs = fabs(current_speed[i]), mf = max_feedrate[i]; if (cs > mf) speed_factor = min(speed_factor, mf / cs); } // Max segement time in us. #if ENABLED(XY_FREQUENCY_LIMIT) // Check and limit the xy direction change frequency unsigned char direction_change = block->direction_bits ^ old_direction_bits; old_direction_bits = block->direction_bits; segment_time = lround((float)segment_time / speed_factor); long xs0 = axis_segment_time[X_AXIS][0], xs1 = axis_segment_time[X_AXIS][1], xs2 = axis_segment_time[X_AXIS][2], ys0 = axis_segment_time[Y_AXIS][0], ys1 = axis_segment_time[Y_AXIS][1], ys2 = axis_segment_time[Y_AXIS][2]; if (TEST(direction_change, X_AXIS)) { xs2 = axis_segment_time[X_AXIS][2] = xs1; xs1 = axis_segment_time[X_AXIS][1] = xs0; xs0 = 0; } xs0 = axis_segment_time[X_AXIS][0] = xs0 + segment_time; if (TEST(direction_change, Y_AXIS)) { ys2 = axis_segment_time[Y_AXIS][2] = axis_segment_time[Y_AXIS][1]; ys1 = axis_segment_time[Y_AXIS][1] = axis_segment_time[Y_AXIS][0]; ys0 = 0; } ys0 = axis_segment_time[Y_AXIS][0] = ys0 + segment_time; long max_x_segment_time = max(xs0, max(xs1, xs2)), max_y_segment_time = max(ys0, max(ys1, ys2)), min_xy_segment_time = min(max_x_segment_time, max_y_segment_time); if (min_xy_segment_time < MAX_FREQ_TIME) { float low_sf = speed_factor * min_xy_segment_time / (MAX_FREQ_TIME); speed_factor = min(speed_factor, low_sf); } #endif // XY_FREQUENCY_LIMIT // Correct the speed if (speed_factor < 1.0) { for (unsigned char i = 0; i < NUM_AXIS; i++) current_speed[i] *= speed_factor; block->nominal_speed *= speed_factor; block->nominal_rate *= speed_factor; } // Compute and limit the acceleration rate for the trapezoid generator. float steps_per_mm = block->step_event_count / block->millimeters; long bsx = block->steps[X_AXIS], bsy = block->steps[Y_AXIS], bsz = block->steps[Z_AXIS], bse = block->steps[E_AXIS]; if (bsx == 0 && bsy == 0 && bsz == 0) { block->acceleration_st = ceil(retract_acceleration[extruder] * steps_per_mm); // convert to: acceleration steps/sec^2 } else if (bse == 0) { block->acceleration_st = ceil(travel_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 } else { block->acceleration_st = ceil(acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 } // Limit acceleration per axis unsigned long acc_st = block->acceleration_st, xsteps = axis_steps_per_sqr_second[X_AXIS], ysteps = axis_steps_per_sqr_second[Y_AXIS], zsteps = axis_steps_per_sqr_second[Z_AXIS], esteps = axis_steps_per_sqr_second[E_AXIS + extruder]; if ((float)acc_st * bsx / block->step_event_count > xsteps) acc_st = xsteps; if ((float)acc_st * bsy / block->step_event_count > ysteps) acc_st = ysteps; if ((float)acc_st * bsz / block->step_event_count > zsteps) acc_st = zsteps; if ((float)acc_st * bse / block->step_event_count > esteps) acc_st = esteps; block->acceleration_st = acc_st; block->acceleration = acc_st / steps_per_mm; #ifdef __SAM3X8E__ block->acceleration_rate = (long)(acc_st * (4294967296.0 / (HAL_TIMER_RATE))); #else block->acceleration_rate = (long)(acc_st * 16777216.0 / (F_CPU / 8.0)); #endif #if 0 // Use old jerk for now // Compute path unit vector double unit_vec[3]; unit_vec[X_AXIS] = delta_mm[X_AXIS] * inverse_millimeters; unit_vec[Y_AXIS] = delta_mm[Y_AXIS] * inverse_millimeters; unit_vec[Z_AXIS] = delta_mm[Z_AXIS] * inverse_millimeters; // Compute maximum allowable entry speed at junction by centripetal acceleration approximation. // Let a circle be tangent to both previous and current path line segments, where the junction // deviation is defined as the distance from the junction to the closest edge of the circle, // colinear with the circle center. The circular segment joining the two paths represents the // path of centripetal acceleration. Solve for max velocity based on max acceleration about the // radius of the circle, defined indirectly by junction deviation. This may be also viewed as // path width or max_jerk in the previous grbl version. This approach does not actually deviate // from path, but used as a robust way to compute cornering speeds, as it takes into account the // nonlinearities of both the junction angle and junction velocity. double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed // Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles. if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) { // Compute cosine of angle between previous and current path. (prev_unit_vec is negative) // NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity. double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS] - previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS] - previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ; // Skip and use default max junction speed for 0 degree acute junction. if (cos_theta < 0.95) { vmax_junction = min(previous_nominal_speed, block->nominal_speed); // Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds. if (cos_theta > -0.95) { // Compute maximum junction velocity based on maximum acceleration and junction deviation double sin_theta_d2 = sqrt(0.5 * (1.0 - cos_theta)); // Trig half angle identity. Always positive. vmax_junction = min(vmax_junction, sqrt(block->acceleration * junction_deviation * sin_theta_d2 / (1.0 - sin_theta_d2))); } } } #endif // Start with a safe speed float vmax_junction = max_xy_jerk / 2; float vmax_junction_factor = 1.0; float mz2 = max_z_jerk / 2, me2 = max_e_jerk[extruder] / 2; float csz = current_speed[Z_AXIS], cse = current_speed[E_AXIS]; if (fabs(csz) > mz2) vmax_junction = min(vmax_junction, mz2); if (fabs(cse) > me2) vmax_junction = min(vmax_junction, me2); vmax_junction = min(vmax_junction, block->nominal_speed); float safe_speed = vmax_junction; if ((moves_queued > 1) && (previous_nominal_speed > 0.0001)) { float dsx = current_speed[X_AXIS] - previous_speed[X_AXIS], dsy = current_speed[Y_AXIS] - previous_speed[Y_AXIS], dsz = fabs(csz - previous_speed[Z_AXIS]), dse = fabs(cse - previous_speed[E_AXIS]), jerk = sqrt(dsx * dsx + dsy * dsy); // if ((fabs(previous_speed[X_AXIS]) > 0.0001) || (fabs(previous_speed[Y_AXIS]) > 0.0001)) { vmax_junction = block->nominal_speed; // } if (jerk > max_xy_jerk) vmax_junction_factor = max_xy_jerk / jerk; if (dsz > max_z_jerk) vmax_junction_factor = min(vmax_junction_factor, max_z_jerk / dsz); if (dse > max_e_jerk[extruder]) vmax_junction_factor = min(vmax_junction_factor, max_e_jerk[extruder] / dse); vmax_junction = min(previous_nominal_speed, vmax_junction * vmax_junction_factor); // Limit speed to max previous speed } block->max_entry_speed = vmax_junction; // Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED. double v_allowable = max_allowable_speed(-block->acceleration, MINIMUM_PLANNER_SPEED, block->millimeters); block->entry_speed = min(vmax_junction, v_allowable); // Initialize planner efficiency flags // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds. // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then // the current block and next block junction speeds are guaranteed to always be at their maximum // junction speeds in deceleration and acceleration, respectively. This is due to how the current // block nominal speed limits both the current and next maximum junction speeds. Hence, in both // the reverse and forward planners, the corresponding block junction speed will always be at the // the maximum junction speed and may always be ignored for any speed reduction checks. block->nominal_length_flag = (block->nominal_speed <= v_allowable); block->recalculate_flag = true; // Always calculate trapezoid for new block // Update previous path unit_vector and nominal speed memcpy(previous_speed, current_speed, sizeof(previous_speed)); // previous_speed[] = current_speed[] previous_nominal_speed = block->nominal_speed; #if ENABLED(ADVANCE) // Calculate advance rate if (!bse || (!bsx && !bsy && !bsz)) { block->advance_rate = 0; block->advance = 0; } else { long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st); float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * (cse * cse * EXTRUSION_AREA * EXTRUSION_AREA) * 256; block->advance = advance; block->advance_rate = acc_dist ? advance / (float)acc_dist : 0; } /* ECHO_SMV(OK, "advance :", block->advance/256); ECHO_EMV("advance rate :", block->advance_rate/256); */ #endif // ADVANCE calculate_trapezoid_for_block(block, block->entry_speed / block->nominal_speed, safe_speed / block->nominal_speed); // Move buffer head block_buffer_head = next_buffer_head; // Update position memcpy(position, target, sizeof(target)); // position[] = target[] planner_recalculate(); st_wake_up(); } // plan_buffer_line()
void PID_autotune(float temp, int hotend, int ncycles) { float input = 0.0; int cycles = 0; bool heating = true; millis_t temp_ms = millis(), t1 = temp_ms, t2 = temp_ms; long t_high = 0, t_low = 0; long bias, d; float Ku, Tu; float Kp_temp, Ki_temp, Kd_temp; float max = 0, min = 10000; #if HAS_AUTO_FAN millis_t next_auto_fan_check_ms = temp_ms + 2500; #endif if (hotend >= HOTENDS #if !HAS_TEMP_BED || hotend < 0 #endif ) { ECHO_LM(ER, MSG_PID_BAD_EXTRUDER_NUM); return; } ECHO_LM(DB, MSG_PID_AUTOTUNE_START); if (hotend < 0) { ECHO_SM(DB, "BED"); } else { ECHO_SMV(DB, "Hotend: ", hotend); } ECHO_MV(" Temp: ", temp); ECHO_EMV(" Cycles: ", ncycles); disable_all_heaters(); // switch off all heaters. if (hotend < 0) soft_pwm_bed = bias = d = MAX_BED_POWER / 2; else soft_pwm[hotend] = bias = d = PID_MAX / 2; // PID Tuning loop for (;;) { millis_t ms = millis(); if (temp_meas_ready) { // temp sample ready updateTemperaturesFromRawValues(); input = (hotend<0)?current_temperature_bed:current_temperature[hotend]; max = max(max, input); min = min(min, input); #if HAS_AUTO_FAN if (ms > next_auto_fan_check_ms) { checkExtruderAutoFans(); next_auto_fan_check_ms = ms + 2500; } #endif if (heating && input > temp) { if (ms > t2 + 5000) { heating = false; if (hotend < 0) soft_pwm_bed = (bias - d) >> 1; else soft_pwm[hotend] = (bias - d) >> 1; t1 = ms; t_high = t1 - t2; max = temp; } } if (!heating && input < temp) { if (ms > t1 + 5000) { heating = true; t2 = ms; t_low = t2 - t1; if (cycles > 0) { long max_pow = hotend < 0 ? MAX_BED_POWER : PID_MAX; bias += (d*(t_high - t_low))/(t_low + t_high); bias = constrain(bias, 20, max_pow - 20); d = (bias > max_pow / 2) ? max_pow - 1 - bias : bias; ECHO_MV(MSG_BIAS, bias); ECHO_MV(MSG_D, d); ECHO_MV(MSG_T_MIN, min); ECHO_MV(MSG_T_MAX, max); if (cycles > 2) { Ku = (4.0 * d) / (3.14159265 * (max - min) / 2.0); Tu = ((float)(t_low + t_high) / 1000.0); ECHO_MV(MSG_KU, Ku); ECHO_EMV(MSG_TU, Tu); Kp_temp = 0.6 * Ku; Ki_temp = 2 * Kp_temp / Tu; Kd_temp = Kp_temp * Tu / 8; ECHO_EM(MSG_CLASSIC_PID); ECHO_MV(MSG_KP, Kp_temp); ECHO_MV(MSG_KI, Ki_temp); ECHO_EMV(MSG_KD, Kd_temp); } else { ECHO_E; } } if (hotend < 0) soft_pwm_bed = (bias + d) >> 1; else soft_pwm[hotend] = (bias + d) >> 1; cycles++; min = temp; }