def updateStatus(self, status): self.printerState = status["state"] self.pState.set_value( "%8s" % self.stateNames[status["state"]]) self.pState.update() self.updateTemps(status["t0"], status["t1"], status["targetT1"]) self.swapSize.set_value( "%8s" % str(status["Swap"])) self.swapSize.update() self.sdrSize.set_value( "%8s" % str(status["SDReader"])) self.sdrSize.update() self.sbSisze.set_value( "%8s" % str(status["StepBuffer"])) self.sbSisze.update() self.underrun.set_value( "%8s" % str(status["StepBufUnderRuns"])) self.underrun.update() st = status["targetExtrusionSpeed"] sa = status["actualExtrusionSpeed"] grip = 100.0 if st: grip = (sa*100.0) / st rt = st * MatProfile.getMatArea() ra = sa * MatProfile.getMatArea() self.extRate.set_value( "%8.1f / %4.1f" % (ra, rt) ) self.extRate.update() self.extGrip.set_value( "%4.1f %%" % grip ) self.extGrip.update()
def initParser(args, mode=None, gui=None): printerProfileName = "UM2" # xxx get from commandline args # profile = profile.Profile(printerProfileName) # parser.setProfile(profile) # Create printer profile singleton instance PrinterProfile(printerProfileName) # Create material profile singleton instance mat = MatProfile(args.mat, args.smat) # Overwrite settings from profile with command line arguments: if args.t0: mat.override("bedTemp", args.t0) if args.t1: mat.override("hotendBaseTemp", args.t1) nozzle = NozzleProfile(args.nozzle) # Create the Printer singleton instance printer = Printer(gui) # Create the planner singleton instance planner = Planner(args, gui) # Create parser singleton instance # parser = gcodeparser.UM2GcodeParser() parser = gcodeparser.UM2GcodeParser() return (parser, planner, printer)
def layerChange(self, layer): self.advance.layerChange(layer) if layer == 0: print "layer 0, increasing temp by", Layer0TempIncrease self.l0TempIncrease = Layer0TempIncrease else: self.l0TempIncrease = 0 if layer == 2: self.partNumber -= 1 if self.partNumber: return # Reduce bedtemp bedTemp = MatProfile.getBedTempReduced() self.gui.log("Layer2, reducing bedtemp to: ", bedTemp) self.addSynchronizedCommand(CmdSyncTargetTemp, p1=packedvalue.uint8_t(HeaterBed), p2=packedvalue.uint16_t(bedTemp))
def prime(parser): planner = parser.planner # printer = planner.printer parser.execute_line("G0 F%f Y0 Z%f" % (planner.HOMING_FEEDRATE[X_AXIS]*60, ddprintconstants.PRIMING_HEIGHT)) pos = parser.getRealPos() aFilament = MatProfile.getMatArea() parser.execute_line("G0 F%f A%f" % ( ((ddprintconstants.PRIMING_MM3_PER_SEC / aFilament) * 60), pos[A_AXIS] + (ddprintconstants.PRIMING_MM3 / aFilament))) # Set E to 0 current_position = parser.getRealPos() current_position[A_AXIS] = 0.0 parser.set_position(current_position) # # Retract # # parser.execute_line("G10") # Wipe priming material if not ultigcode flavor if not parser.ultiGcodeFlavor: # parser.execute_line("G10") # parser.execute_line("G0 F%f X50 Z0.5" % (planner.HOMING_FEEDRATE[X_AXIS]*60)) parser.execute_line("G0 F9000 X20 Z0.1")
def printTempTable(printer, temp, tempTable): of = open("/tmp/temptable_printer.txt", "w") of.write("# xxx mat, nozzle, settings...\n") of.write("# basetemp: %d, autoTempFactor: %f\n" % (temp, 0)) of.write("# temp rate steprate timer\n") print "TempTable (basetemp: %d):" % temp mmpermm3 = 1 / MatProfile.getMatArea() spm = PrinterProfile.getStepsPerMM(A_AXIS) for timerValue in tempTable: steprate = fTimer / timerValue speed = (steprate / spm) / mmpermm3 print " Temp: %d, max extrusion: %.1f mm³/s, steps/s: %d, timervalue: %d" % (temp, speed, int(steprate), timerValue) of.write("%d %4.1f %d %d\n" % (temp, speed, int(steprate), timerValue)) temp += 2 of.close()
def doAutoTemp(self, moves): # Sum up path time and extrusion volume of moves tsum = 0 vsum = 0 for move in moves: tsum += move.accelData.getTime() vsum += move.getExtrusionVolume(MatProfile.get()) avgERate = vsum / tsum print "Average extrusion rate: ", avgERate, "mm³/s", "layer 0 increase: ", self.planner.l0TempIncrease # Compute temperature for this segment and add tempcommand into the stream. newTemp = \ MatProfile.getTempForFlowrate(avgERate * (1.0+AutotempSafetyMargin), PrinterProfile.getHwVersion(), NozzleProfile.getSize()) + \ self.planner.l0TempIncrease # Don't go below startTemp from material profile newTemp = max(newTemp, MatProfile.getHotendStartTemp()) # Don't go above max temp from material profile newTemp = min(newTemp, MatProfile.getHotendMaxTemp()) if newTemp != self.lastTemp: # and self.mode != "pre": print "Newtemp:", avgERate, newTemp # Schedule target temp command self.planner.addSynchronizedCommand( CmdSyncTargetTemp, p1=packedvalue.uint8_t(HeaterEx1), p2=packedvalue.uint16_t(newTemp), moveNumber=move.moveNumber) self.lastTemp = int(newTemp) if debugAutoTemp: print "AutoTemp: collected moves with %.2f s duration." % tsum print "AutoTemp: max. extrusion rate: %.2f mm³/s." % avgERate print "AutoTemp: new temp: %d." % newTemp
def initParser(args, mode=None, gui=None): printerProfileName = "UM2" # xxx todo: get from commandline args # Create printer profile singleton instance printerProfile = PrinterProfile(printerProfileName) # Create material profile singleton instance mat = MatProfile(args.mat, args.smat) # Overwrite settings from printer profile with command line arguments: if args.retractLength: printerProfile.override("RetractLength", args.retractLength) # Overwrite settings from material profile with command line arguments: if args.t0: mat.override("bedTemp", args.t0) if args.t1: mat.override("hotendStartTemp", args.t1) nozzle = NozzleProfile(args.nozzle) # Create the Printer singleton instance printer = Printer(gui) # Create the planner singleton instance planner = Planner(args, gui) # Create parser singleton instance parser = gcodeparser.UM2GcodeParser() return (parser, planner, printer)
def __init__(self): if UM2GcodeParser.__single: raise RuntimeError('A UM2GcodeParser already exists') UM2GcodeParser.__single = self self.reset() self.commands = { # G0 and G1 are the same "G0": self.g0, "G1": self.g0, "G4": self.g4_dwell, "G10": self.g10_retract, "G11": self.g11_retract_recover, "G21": self.g21_metric_values, "G28": self.g28_home, "G29": self.g29_autolevel, "G80": self.g80_bed_leveling, "G90": self.g90_abs_values, "G91": self.g91_rel_values, "G92": self.g92_set_pos, "M25": self.m25_stop_reading, "M82": self.m82_extruder_abs_values, "M83": self.m83_extruder_relative_values, "M84": self.m84_disable_motors, "M104": self.m104_extruder_temp, "M106": self.m106_fan_on, "M107": self.m107_fan_off, "M109": self.m109_extruder_temp_wait, "M117": self.m117_message, "M140": self.m140_bed_temp, "M190": self.m190_bed_temp_wait, "M204": self.m204_set_accel, "M501": self.m501_reset_params, "M502": self.m502_reset_params, "M900": self.m900_set_kAdvance, "M907": self.m907_motor_current, "T0": self.t0, "U": self.unknown, # unknown command for testing purposes } # Apply material flow parameter from material profile self.e_to_filament_length = MatProfile.getFlow() / 100.0 self.steps_per_mm = PrinterProfile.getStepsPerMMVector() self.mm_per_step = map(lambda dim: 1.0 / self.steps_per_mm[dim], range(5)) self.maxFeedrateVector = PrinterProfile.getMaxFeedrateVector() self.planner = Planner.get()
def genTempTable(printer): baseTemp = MatProfile.getHotendBaseTemp() area04 = pow(0.4, 2)*math.pi/4 extrusionLow = MatProfile.getBaseExtrusionRate() * (NozzleProfile.getArea() / area04) f = MatProfile.getAutoTempFactor() mmpermm3 = 1 / MatProfile.getMatArea() spm = PrinterProfile.getStepsPerMM(A_AXIS) of = open("/tmp/temptable0.txt", "w") of.write("# xxx mat, nozzle, settings...\n") of.write("# basetemp: %d, autoTempFactor: %f\n" % (baseTemp, f)) of.write("# temp rate steprate timer\n") print "TempTable (basetemp: %d):" % baseTemp table = [] for i in range(NExtrusionLimit): t = baseTemp + i*2 dspeed = i*2 / f speed = extrusionLow + dspeed steprate = speed * mmpermm3 * spm tvs = 1.0/steprate timerValue = int(fTimer / steprate) print " Temp: %d, max extrusion: %.1f mm³/s, steps/s: %d, steprate: %d us, timervalue: %d" % (t, speed, int(steprate), int(tvs*1000000), timerValue) table.append(timerValue) of.write("%d %4.1f %d %d\n" % (t, speed, int(steprate), timerValue)) of.close() return (baseTemp, table)
def __init__(self, planner): self.planner = planner self.path = [] self.count = -10 # AutoTemp if UseExtrusionAutoTemp: self.lastTemp = MatProfile.getHotendStartTemp() # Some statistics self.maxExtrusionRate = MaxExtrusionRate()
def preParse(self, fn): # Copy file to prevet problems with overwritten files # while reading. tmpfname = ("/tmp/%d_" % id(fn)) + os.path.basename(fn) shutil.copyfile(fn, tmpfname) f = open(fn) print "Unlinking temp. copy of gcode input: ", tmpfname os.unlink(tmpfname) self.numParts = 0 print "pre-parsing ", fn for line in f: line = line.strip() if line.startswith(";"): upperLine = line.upper() # Cura: "LAYER:" if "LAYER:" in upperLine: layerNum = getCuraLayer(line) if layerNum == 1: self.numParts += 1 self.planner.newPart(self.numParts) # # Simplify3D: "; LAYER " # elif "; LAYER " in upperLine: # layerNum = getSimplifyLayer(line) # if layerNum == 1: # self.numParts += 1 # self.planner.newPart(self.numParts) # Simplify3D: "; skirt " elif upperLine.startswith("; SKIRT"): self.numParts += 1 self.planner.newPart(self.numParts) # ;FLAVOR:UltiGCode elif "FLAVOR:ULTIGCODE" in upperLine: self.ultiGcodeFlavor = True # To compute extrude length from volume (see getValues()): # V = A * h, h = V / A, A = pi/4 * diameter² # self.e_to_filament_length *= 4 / (math.pi * pow(MatProfile.getMatDiameter(), 2)) aFilament = MatProfile.getMatArea() self.e_to_filament_length = self.e_to_filament_length / aFilament print "pre-parsing # parts:", self.numParts f.seek(0) # rewind return f
def heatHotend(args, parser): planner = parser.planner printer = planner.printer printer.commandInit(args) t1 = MatProfile.getHotendBaseTemp() printer.heatUp(HeaterEx1, t1, wait=t1-5) raw_input("Press return to stop heating...") if not args.noCoolDown: printer.coolDown(HeaterEx1, wait=150)
def m106_fan_on(self, line, values): # print "m106_fan_on", values fanSpeed = (values["S"] * MatProfile.getFanPercent()) / 100 # "Blip fan" for Cura (S3D supports blip fan) if fanSpeed < 50 and self.ultiGcodeFlavor: # Start fan with full power self.planner.addSynchronizedCommand(CmdSyncFanSpeed, p1=packedvalue.uint8_t(255)) # Dwell 0.25s self.planner.addSynchronizedCommand(CmdDwellMS, p1=packedvalue.uint16_t(250)) self.planner.addSynchronizedCommand(CmdSyncFanSpeed, p1=packedvalue.uint8_t(fanSpeed))
def layerChange(self, layer): if layer == 2: self.partNumber -= 1 if self.partNumber: return # Reduce bedtemp bedTemp = MatProfile.getBedTempReduced() self.gui.log("Layer2, reducing bedtemp to: ", bedTemp) self.addSynchronizedCommand( CmdSyncTargetTemp, p1 = packedvalue.uint8_t(HeaterBed), p2 = packedvalue.uint16_t(bedTemp))
def preParse(self, fn): # Copy file to prevet problems with overwritten files # while reading. tmpfname = ("/tmp/%d_" % id(fn)) + os.path.basename(fn) shutil.copyfile(fn, tmpfname) f = open(tmpfname) print "Unlinking temp. copy of gcode input: ", tmpfname os.unlink(tmpfname) self.numParts = 0 print "pre-parsing ", fn, tmpfname for line in f: line = line.strip() if line.startswith(";"): upperLine = line.upper() # Cura: "LAYER:" layerNum = getCuraLayer(line) if layerNum == 1: self.numParts += 1 self.planner.newPart(self.numParts) # layerNum = getSimplifyLayer(line) # if layerNum == 1: # self.numParts += 1 # self.planner.newPart(self.numParts) # Simplify3D: "; skirt " if upperLine.startswith("; SKIRT"): self.numParts += 1 self.planner.newPart(self.numParts) # ;FLAVOR:UltiGCode elif "FLAVOR:ULTIGCODE" in upperLine: self.ultiGcodeFlavor = True # To compute extrude length from volume (see getValues()): # V = A * h, h = V / A, A = pi/4 * diameter² aFilament = MatProfile.getMatArea() self.e_to_filament_length = self.e_to_filament_length / aFilament print "pre-parsing # parts:", self.numParts f.seek(0) # rewind return f
def __init__(self): if UM2GcodeParser.__single: raise RuntimeError('A UM2GcodeParser already exists') UM2GcodeParser.__single = self self.reset() self.commands = { # G0 and G1 are the same "G0": self.g0, "G1": self.g0, "G4": self.g4_dwell, "G10": self.g10_retract, "G11": self.g11_retract_recover, "G21": self.g21_metric_values, "G28": self.g28_home, "G29": self.g29_autolevel, "G90": self.g90_abs_values, "G92": self.g92_set_pos, "M25": self.m25_stop_reading, "M82": self.m82_extruder_abs_values, "M84": self.m84_disable_motors, "M104": self.m104_extruder_temp, "M106": self.m106_fan_on, "M107": self.m107_fan_off, "M109": self.m109_extruder_temp_wait, "M117": self.m117_message, "M140": self.m140_bed_temp, "M190": self.m190_bed_temp_wait, "M907": self.m907_motor_current, "T0": self.t0, "U": self.unknown, # unknown command for testing purposes } # Apply material flow parameter from material profile self.e_to_filament_length = MatProfile.getFlow() / 100.0 self.steps_per_mm = PrinterProfile.getStepsPerMMVector() self.mm_per_step = map(lambda dim: 1.0 / self.steps_per_mm[dim], range(5)) self.maxFeedrateVector = PrinterProfile.getMaxFeedrateVector() self.planner = Planner.get()
def stat(self, move): # Do not count very small moves, the computation of the extrusion rate is inaccurate because of the # discretization in the gcodeparser (map float values to discrete stepper values). if move.distance3 < 0.1: return # Get maximum extrusion rate, take plateau speed into account only # length of max constant speed: reachedEExtrusion = move.topSpeed.speed( ).eSpeed * MatProfile.getMatArea() if reachedEExtrusion > self.maxRate: # print "New max reachedEExtrusion: ", reachedEExtrusion, "mm³/s" self.maxRate = reachedEExtrusion self.move = move self.max10.append(reachedEExtrusion) if len(self.max10) > 10: self.max10 = self.max10[1:]
def stat(self, move): # Do not count very small moves, the computation of the extrusion rate is inaccurate because of the # discretization in the gcodeparser (map float values to discrete stepper values). if move.distance3 < 0.1: return # Get maximum extrusion rate, take plateau speed into account only # length of max constant speed: reachedESpeed = abs( move.getReachedSpeedV()[util.A_AXIS] ) # [mm/s] reachedEExtrusion = reachedESpeed * MatProfile.getMatArea() if reachedEExtrusion > self.maxRate: # print "New max reachedEExtrusion: ", reachedEExtrusion, "mm³/s" self.maxRate = reachedEExtrusion self.move = move self.max10.append(reachedEExtrusion) if len(self.max10) > 10: self.max10 = self.max10[1:]
def retract(args, parser, doCooldown = True): planner = parser.planner printer = planner.printer commonInit(args, parser) t1 = MatProfile.getHotendBaseTemp() printer.heatUp(HeaterEx1, t1, wait=t1 - 5) # hack # parser.retracted = False parser.execute_line("G10") planner.finishMoves() printer.sendCommandParamV(CmdMove, [MoveTypeNormal]) printer.sendCommand(CmdEOT) printer.waitForState(StateIdle) if doCooldown: printer.coolDown(HeaterEx1,wait=150)
def removeFilament(args, parser): planner = parser.planner printer = planner.printer printer.commandInit(args) ddhome.home(parser, args.fakeendstop) printer.sendPrinterInit() # Move to mid-position # MAX_POS = (X_MAX_POS, Y_MAX_POS, Z_MAX_POS) # feedrate = PrinterProfile.getMaxFeedrate(Z_AXIS) # parser.execute_line("G0 F%d Z%f" % (feedrate*60, MAX_POS[Z_AXIS])) feedrate = PrinterProfile.getMaxFeedrate(X_AXIS) parser.execute_line("G0 F%d X%f Y%f" % (feedrate*60, planner.MAX_POS[X_AXIS]/2, planner.MAX_POS[Y_AXIS]/2)) planner.finishMoves() printer.sendCommandParamV(CmdMove, [MoveTypeNormal]) printer.sendCommand(CmdEOT) printer.waitForState(StateIdle) t1 = MatProfile.getHotendBaseTemp() printer.heatUp(HeaterEx1, t1, wait=t1) # Etwas vorwärts um den retract-pfropfen einzuschmelzen manualMove(parser, A_AXIS, PrinterProfile.getRetractLength() + 5, 5) manualMove(parser, A_AXIS, -1.3*FILAMENT_REVERSAL_LENGTH) if not args.noCoolDown: printer.coolDown(HeaterEx1,wait=150)
def m106_fan_on(self, line, values): # print "m106_fan_on", values fanSpeed = (values["S"] * MatProfile.getFanPercent()) / 100 self.planner.addSynchronizedCommand(CmdSyncFanSpeed, p1=packedvalue.uint8_t(fanSpeed))
def main(): argParser = argparse.ArgumentParser(description='%s, Direct Drive USB Print.' % sys.argv[0]) argParser.add_argument("-d", dest="device", action="store", type=str, help="Device to use, default: /dev/ttyACM0.", default="/dev/ttyACM0") argParser.add_argument("-b", dest="baud", action="store", type=int, help="Baudrate, default 115200.", default=115200) # argParser.add_argument("-b", dest="baud", action="store", type=int, help="Baudrate, default 230400.", default=230400) # argParser.add_argument("-b", dest="baud", action="store", type=int, help="Baudrate, default 500000.", default=500000) # argParser.add_argument("-b", dest="baud", action="store", type=int, help="Baudrate, default 1000000.", default=1000000) argParser.add_argument("-t0", dest="t0", action="store", type=int, help="Temp 0 (heated bed), default comes from mat. profile.") argParser.add_argument("-t1", dest="t1", action="store", type=int, help="Temp 1 (hotend 1), default comes from mat. profile.") argParser.add_argument("-mat", dest="mat", action="store", help="Name of generic material profile to use [pla, abs...], default is pla.", default="pla_1.75mm") argParser.add_argument("-smat", dest="smat", action="store", help="Name of specific material profile to use.") argParser.add_argument("-noz", dest="nozzle", action="store", help="Name of nozzle profile to use [nozzle40, nozzle80...], default is nozzle40.", default="nozzle40") argParser.add_argument("-np", dest="noPrime", action="store_const", const=True, help="Debug: don't prime nozzle, to test extrusion-less moves.") # fake endstops as long we have no real ones argParser.add_argument("-F", dest="fakeendstop", action="store", type=bool, help="Debug: fake endstops", default=False) argParser.add_argument("-nc", dest="noCoolDown", action="store", type=bool, help="Debug: don't wait for heater cool down after print.", default=False) argParser.add_argument("-fr", dest="feedrate", action="store", type=float, help="Feedrate for move commands.", default=0) subparsers = argParser.add_subparsers(dest="mode", help='Mode: mon(itor)|print|store|reset|pre(process).') sp = subparsers.add_parser("autoTune", help=u"Autotune hotend PID values.") sp = subparsers.add_parser("binmon", help=u"Monitor serial printer interface (binary responses).") sp = subparsers.add_parser("changenozzle", help=u"Heat hotend and change nozzle.") sp = subparsers.add_parser("mon", help=u"Monitor serial printer interface (asci).") sp = subparsers.add_parser("print", help=u"Download and print file at once.") sp.add_argument("gfile", help="Input GCode file.") # sp = subparsers.add_parser("store", help=u"Store file as USB.G on sd-card.") # sp.add_argument("gfile", help="Input GCode file.") sp = subparsers.add_parser("writeEepromFloat", help=u"Store float value into eeprom.") sp.add_argument("name", help="Valuename.") sp.add_argument("value", action="store", type=float, help="value (float).") # sp = subparsers.add_parser("reset", help=u"Try to stop/reset printer.") sp = subparsers.add_parser("pre", help=u"Preprocess gcode, for debugging purpose.") sp.add_argument("gfile", help="Input GCode file.") sp = subparsers.add_parser("dumpeeprom", help=u"dump eeprom settings.") sp = subparsers.add_parser("factoryReset", help=u"FactoryReset of eeprom settings, new bed leveling needed.") sp = subparsers.add_parser("test", help=u"Debug: tests for debugging purpose.") sp = subparsers.add_parser("disableSteppers", help=u"Disable stepper current (this dis-homes the printer).") sp = subparsers.add_parser("home", help=u"Home the printer.") sp = subparsers.add_parser("measureTempFlowrateCurve", help=u"Determine temperature/flowrate characteristic.") sp = subparsers.add_parser("moverel", help=u"Debug: Move axis manually, relative coords.") sp.add_argument("axis", help="Axis (XYZAB).", type=str) sp.add_argument("distance", action="store", help="Move-distance (+/-) in mm.", type=float) sp = subparsers.add_parser("moveabs", help=u"Debug: Move axis manually, absolute coords.") sp.add_argument("axis", help="Axis (XYZAB).", type=str) sp.add_argument("distance", action="store", help="Move-distance (+/-) in mm.", type=float) sp = subparsers.add_parser("insertFilament", help=u"Insert filament (heatup, forward filament).") sp = subparsers.add_parser("removeFilament", help=u"Remove filament (heatup, retract filament).") sp = subparsers.add_parser("bedLeveling", help=u"Do bed leveling sequence.") sp = subparsers.add_parser("bedLevelAdjust", help=u"Adjust bedleveling offset - dangerous.") sp.add_argument("distance", action="store", help="Adjust-distance (+/-) in mm.", type=float) sp = subparsers.add_parser("heatHotend", help=u"Heat up hotend (to clean it, etc).") sp = subparsers.add_parser("genTempTable", help=u"Generate extrusion rate limit table.") sp = subparsers.add_parser("getEndstops", help=u"Get current endstop state.") sp = subparsers.add_parser("getFilSensor", help=u"Get current filament position.") sp = subparsers.add_parser("getpos", help=u"Get current printer and virtual position.") sp = subparsers.add_parser("getTemps", help=u"Get current temperatures (Bed, Extruder1, [Extruder2]).") sp = subparsers.add_parser("getTempTable", help=u"Output temperature-speed table.") sp = subparsers.add_parser("getStatus", help=u"Get current printer status.") sp = subparsers.add_parser("zRepeatability", help=u"Debug: Move Z to 10 random positions to test repeatability.") sp = subparsers.add_parser("stop", help=u"Stop print, cooldown, home, disable steppers.") sp = subparsers.add_parser("stepResponse", help=u"Measure and plot stepResponse of hotend PID.") sp = subparsers.add_parser("retract", help=u"Debug: Do the end-of-print retract manually after heating up.") sp = subparsers.add_parser("fanspeed", help=u"Set fan speed manually.") sp.add_argument("speed", help="Fanspeed 0 - 255.", type=int) sp = subparsers.add_parser("testFilSensor", help=u"Debug: move filament manually, output filament sensor measurement.") sp.add_argument("distance", action="store", help="Move-distance (+/-) in mm.", type=float) sp = subparsers.add_parser("calibrateFilSensor", help=u"Debug: helper to determine the ratio of stepper to flowrate sensor.") # sp.add_argument("distance", action="store", help="Move-distance (+/-) in mm.", type=float) args = argParser.parse_args() # print "args: ", args (parser, planner, printer) = initParser(args, mode=args.mode) steps_per_mm = PrinterProfile.getStepsPerMMVector() if args.mode == 'autoTune': util.zieglerNichols(args, parser) elif args.mode == 'changenozzle': util.changeNozzle(args, parser) elif args.mode == "binmon": printer.initSerial(args.device, args.baud) while True: try: (cmd, payload) = printer.readResponse() except RxTimeout: pass else: print "Response cmd :", cmd print "Response payload:", payload.encode("hex") printer.checkErrorResponse(cmd, payload, False) elif args.mode == 'print': util.commonInit(args, parser) t0 = MatProfile.getBedTemp() t1 = MatProfile.getHotendBaseTemp() # Send heat up command print "\nPre-Heating bed...\n" printer.heatUp(HeaterBed, t0) print "\nPre-Heating extruder...\n" printer.heatUp(HeaterEx1, 150) # Send printing moves # f = open(args.gfile) f = parser.preParse(args.gfile) # Send priming moves if not args.noPrime: util.prime(parser) lineNr = 0 printStarted = False for line in f: parser.execute_line(line) # # Send more than one 512 byte block for dlprint # if lineNr > 1000 and (lineNr % 250) == 0: # check temp and start print if not printStarted: print "\nHeating bed (t0: %d)...\n" % t0 printer.heatUp(HeaterBed, t0, t0) print "\nHeating extruder (t1: %d)...\n" % t1 printer.heatUp(HeaterEx1, t1, wait=0.95 * t1) # Send print command printer.sendCommandParamV(CmdMove, [MoveTypeNormal]) printStarted = True else: # Stop sending moves on error status = printer.getStatus() pprint.pprint(status) if not printer.stateMoving(status): break lineNr += 1 print "Parsed %d gcode lines." % lineNr # # Add a move to lift the nozzle from the print if not ultigcode flavor # if not parser.ultiGcodeFlavor: util.endOfPrintLift(parser) planner.finishMoves() printer.sendCommand(CmdEOT) # XXX start print if less than 1000 lines or temp not yet reached: if not printStarted: print "\nHeating bed (t0: %d)...\n" % t0 printer.heatUp(HeaterBed, t0, t0) print "\nHeating extruder (t1: %d)...\n" % t1 printer.heatUp(HeaterEx1, t1, wait=0.95 * t1) # Send print command printer.sendCommandParamV(CmdMove, [MoveTypeNormal]) printer.waitForState(StateIdle) printer.coolDown(HeaterEx1) printer.coolDown(HeaterBed) ddhome.home(parser, args.fakeendstop) printer.sendCommand(CmdDisableSteppers) if not args.noCoolDown: printer.coolDown(HeaterEx1, wait=150) printer.coolDown(HeaterBed, wait=55) printer.readMore() ### Simulator/profiling ### printer.sendCommand(CmdExit) elif args.mode == "pre": # Virtuelle position des druckkopfes falls 'gehomed' homePosMM = util.MyPoint( X = planner.X_HOME_POS, Y = planner.Y_HOME_POS, Z = planner.Z_HOME_POS, # - 20, ) parser.set_position(homePosMM) f = parser.preParse(args.gfile) lineNr = 0 for line in f: parser.execute_line(line) lineNr += 1 print "Parsed %d gcode lines." % lineNr planner.finishMoves() elif args.mode == "mon": printer.initSerial(args.device, args.baud) while True: printer.readMore() elif args.mode == 'dumpeeprom': printer.commandInit(args) resp = printer.query(CmdGetEepromVersion) if util.handleGenericResponse(resp): print "Eepromversion: ", util.getResponseString(resp[1], 1) settingsDict = printer.getEepromSettings() print "eepromSettings: ", pprint.pprint(settingsDict) elif args.mode == 'factoryReset': printer.commandInit(args) printer.sendCommand(CmdEepromFactory) elif args.mode == 'disableSteppers': printer.commandInit(args) printer.sendCommand(CmdDisableSteppers) elif args.mode == 'measureTempFlowrateCurve': util.measureTempFlowrateCurve(args, parser) elif args.mode == 'moverel': assert(args.axis.upper() in "XYZAB") printer.commandInit(args) axis = util.dimIndex[args.axis.upper()] util.manualMove(parser, axis, args.distance, args.feedrate) elif args.mode == 'moveabs': assert(args.axis.upper() in "XYZAB") printer.commandInit(args) axis = util.dimIndex[args.axis.upper()] util.manualMove(parser, axis, args.distance, args.feedrate, True) elif args.mode == 'insertFilament': util.insertFilament(args, parser) elif args.mode == 'removeFilament': util.removeFilament(args, parser) elif args.mode == 'bedLeveling': util.bedLeveling(args, parser) elif args.mode == 'bedLevelAdjust': util.bedLevelAdjust(args, parser) elif args.mode == 'heatHotend': util.heatHotend(args, parser) elif args.mode == 'genTempTable': util.genTempTable(printer) elif args.mode == 'getEndstops': printer.commandInit(args) res = printer.getEndstops() print "Endstop state: ", res elif args.mode == 'getFilSensor': printer.commandInit(args) print "Filament pos:", printer.getFilSensor() elif args.mode == 'getpos': printer.commandInit(args) res = printer.getPos() curPosMM = util.MyPoint( X = res[0] / float(steps_per_mm[0]), Y = res[1] / float(steps_per_mm[1]), Z = res[2] / float(steps_per_mm[2]), A = res[3] / float(steps_per_mm[3]), # B = res[4] / float(steps_per_mm[4]), ) (homePosMM, homePosStepped) = planner.getHomePos() print "Printer pos [steps]:", res print "Printer pos [mm]:", curPosMM print "Virtual home pos [mm]: ", homePosMM elif args.mode == 'getTemps': printer.commandInit(args) printer.getTemps() elif args.mode == 'getTempTable': printer.commandInit(args) (baseTemp, tempTable) = printer.getTempTable() print "tempTable: ", pprint.pprint(tempTable) util.printTempTable(printer, baseTemp, tempTable) elif args.mode == 'getStatus': printer.commandInit(args) status = printer.getStatus() print "Status: " pprint.pprint(status) elif args.mode == 'home': printer.commandInit(args) ddhome.home(parser, args.fakeendstop) elif args.mode == 'zRepeatability': util.zRepeatability(parser) elif args.mode == 'stepResponse': util.stepResponse(args, parser) elif args.mode == 'retract': util.retract(args, parser) elif args.mode == 'stop': printer.commandInit(args) util.stopMove(args, parser) elif args.mode == 'fanspeed': printer.commandInit(args) printer.sendCommandParamV(CmdFanSpeed, [packedvalue.uint8_t(args.speed)]) elif args.mode == 'testFilSensor': ddtest.testFilSensor(args, parser) elif args.mode == 'calibrateFilSensor': ddtest.calibrateFilSensor(args, parser) elif args.mode == 'test': printer.commandInit(args) util.downloadTempTable(printer) printer.readMore() elif args.mode == "writeEepromFloat": util.writeEEpromFloat(args, parser) else: print "Unknown command: ", args.mode assert(0)
def addMove(self, move): # print "addmove ...", move.comment if debugMoves: print "***** Start addMove() *****" move.moveNumber = self.pathData.incCount() if not self.pathData.path: # First move of this path, startspeed is jerkspeed # jerkSpeed = move.vVector().constrain(self.jerk) or move.vVector() # move.setNominalStartFr(jerkSpeed) move.setNominalJerkStartSpeed(self.jerk) # self.prepareMoveEnd(move) self.pathData.path.append(move) if UseExtrusionAutoTemp: self.pathData.time = 0 # Reset path time self.pathData.extrusionAmount = 0 self.pathData.lastTemp = MatProfile.getHotendBaseTemp() # # Zum end-speed können wir nichts sagen, da der nächste move noch nicht # bekannt ist. # if debugMoves: print "***** End addMove() *****" return lastMove = self.pathData.path[-1] lastMove.nextMove = move move.lastMove = lastMove util.joinSpeed(lastMove, move, self.jerk, self.min_speeds) self.pathData.path.append(move) if len(self.pathData.path) < 3: # Wir brauchen mind. 3 moves um einen 'PathBlock' zu bilden if debugMoves: print "***** End addMove() *****" return if self.isIsolationMove(lastMove): l = len(self.pathData.path) pathBlock = self.pathData.path[:l-2] if debugMoves: print "Move #:", lastMove.moveNumber, " is a isolation move." print "Streaming block of moves, len: %d/%d" % (len(pathBlock), l), ", blocks: ", pathBlock[0].moveNumber, " - ", pathBlock[-1].moveNumber self.streamMoves(pathBlock) del self.pathData.path[:l-2] assert(len(self.pathData.path) == 2) if debugMoves: print "***** End addMove() *****"
def streamMoves(self, moves, finish = False): if debugMoves: print "Streaming %d moves..." % len(moves) if debugPlot and not self.plotfile: self.plottime = 0 self.plotfile=open("/tmp/accel_%d.plt" % moves[0].moveNumber, "w") self.plotfile.write("set grid\n") self.plotfile.write("set label 2 at graph 0.01, graph 0.95 'Note: Trapez top not included, e-only moves green.'\n") self.plotfile.write('plot "-" using 1:2:3 with linespoints lc variable\n') ################################################################################# # Backwards move planning self.joinMovesBwd(moves) ################################################################################# for move in moves: # move.pprint("sanicheck") move.sanityCheck(self.jerk) self.planAcceleration(move) self.planSteps(move) # # Collect some statistics # if move.isHeadMove(): self.pathData.maxExtrusionRate.stat(move) # # Collect moves if AutoTemp # if UseExtrusionAutoTemp: if move.isExtrudingMove(util.A_AXIS): # Collect moves and sum up path time self.pathData.time += move.getTime() # Sum extrusion volume self.pathData.extrusionAmount += move.getAdjustedExtrusionVolume(util.A_AXIS, NozzleProfile, MatProfile) self.pathData.atMoves.append(move) else: self.streamMove(move) move.streamed = True # Help garbage collection move.lastMove = errorMove move.nextMove = errorMove if UseExtrusionAutoTemp: if self.pathData.time >= ATInterval or finish: if self.pathData.time > 0: # Compute temperature for this segment and add tempcommand into the stream # Average speed: avgSpeed = self.pathData.extrusionAmount / self.pathData.time # UseAutoTemp: Adjust temp between Tbase and HotendMaxTemp, if speed is greater than 20 mm/s # UseExtrusionAutoTemp: Adjust temp between Tbase and HotendMaxTemp, if speed is greater than 5 mm³/s newTemp = MatProfile.getHotendBaseTemp() # Extruder 1 temp # extrusionLow = self.ExtrusionAmountLow * pow(NozzleProfile.getSize(), 2) if avgSpeed > self.ExtrusionAmountLow: f = MatProfile.getAutoTempFactor() # newTemp += min((avgSpeed - self.ExtrusionAmountLow * pow(NozzleProfile.getSize(), 2)) * f, ATMaxTempIncrease) newTemp += (avgSpeed - self.ExtrusionAmountLow) * f # newTemp *= 1.15 # xxx sync withtemp-speed-adjust newTemp = min(newTemp, MatProfile.getHotendMaxTemp()) if debugAutoTemp: print "AutoTemp: collected %d moves with %.2f s duration." % (len(self.pathData.atMoves), self.pathData.time) print "AutoTemp: amount: %.2f, avg extrusion rate: %.2f mm³/s." % (self.pathData.extrusionAmount, avgSpeed) print "AutoTemp: new temp: %.2f." % (newTemp) self.pathData.maxExtrusionRate.avgStat(avgSpeed) if newTemp != self.pathData.lastTemp and self.args.mode != "pre": # Schedule target temp command self.printer.sendCommandParamV( CmdSyncTargetTemp, [packedvalue.uint8_t(HeaterEx1), packedvalue.uint16_t(newTemp)]) self.pathData.lastTemp = newTemp for move in self.pathData.atMoves: self.streamMove(move) self.pathData.atMoves = [] self.pathData.time = self.pathData.extrusionAmount = 0 # Reset path time
def measureTempFlowrateCurve(args, parser): def writeDataSet(f, dataSet): for dataStr in dataSet: f.write(dataStr) f.write("\n") f.write("E\n") fssteps_per_mm = 265.0 # xxx hardcoded, get from profile or printer... planner = parser.planner printer = planner.printer printer.commandInit(args) ddhome.home(parser, args.fakeendstop) # Disable flowrate limit printer.sendCommandParamV(CmdEnableFRLimit, [packedvalue.uint8_t(0)]) # Move to mid-position printer.sendPrinterInit() feedrate = PrinterProfile.getMaxFeedrate(X_AXIS) parser.execute_line("G0 F%d X%f Y%f" % (feedrate*60, planner.MAX_POS[X_AXIS]/2, planner.MAX_POS[Y_AXIS]/2)) planner.finishMoves() printer.sendCommandParamV(CmdMove, [MoveTypeNormal]) printer.sendCommand(CmdEOT) printer.waitForState(StateIdle) current_position = parser.getRealPos() apos = current_position[A_AXIS] t1 = MatProfile.getHotendBaseTemp() # start temperature area04 = pow(0.4, 2)*math.pi/4 flowrate = MatProfile.getBaseExtrusionRate() * (NozzleProfile.getArea() / area04) aFilament = MatProfile.getMatArea() print "t1: ", t1 print "flowrate: ", flowrate print "aFilament: ", aFilament print "feedrate: ", flowrate / aFilament # xxx todo if using small nozzles assert(flowrate > 2) f = open("temp-flowrate-curve.gnuplot", "w") f.write(""" set grid set yrange [0:35] # Startwert steigung a=0.5 # Startwert y-achse b=5 f(x)=b+a*(x-%d) fit f(x) "-" using 1:3 noerror via a,b\n""" % t1) dataSet = [] printer.sendCommandParamV(CmdFanSpeed, [packedvalue.uint8_t(100)]) retracted = False while t1 <= MatProfile.getHotendMaxTemp(): print "Heating:", t1 printer.heatUp(HeaterEx1, t1, wait=t1) # time.sleep(10) # temp settle wait = 5 while wait: time.sleep(1) temps = printer.getTemps() if abs(t1 - int(temps[HeaterEx1])) <= 1: wait -= 1 else: wait = 5 print "temp wait: ", wait flowrate -= 1 ratio = 1.0 while ratio >= 0.9: feedrate = flowrate / aFilament # distance = 5 * feedrate # xxx distance = 50 apos += distance print "Feedrate for flowrate:", feedrate, flowrate printer.sendPrinterInit() if retracted: parser.execute_line("G11") parser.execute_line("G0 F%d %s%f" % (feedrate*60, dimNames[A_AXIS], apos)) parser.execute_line("G10") planner.finishMoves() printer.sendCommand(CmdEOT) printer.sendCommandParamV(CmdMove, [MoveTypeNormal]) printer.waitForState(StateIdle) time.sleep(0.25) fssteps = printer.getFilSensor() fsdist = fssteps / fssteps_per_mm ratio = fsdist / distance actualFlowrate = flowrate * ratio print "t1, flowrate, fsdist, distance, ratio:", t1, flowrate, fsdist, distance, ratio flowrate += 1 retracted = True print "Feeder grip:", t1, flowrate-1, ratio dataStr = "%f %f %.2f %.3f" % (t1, flowrate - 1, actualFlowrate, ratio) f.write(dataStr + "\n") f.flush() dataSet.append(dataStr) t1 += 2 # next temp f.write("E\n") f.write(""" plot "-" using 1:2 with linespoints title "Target Flowrate", \\ "-" using 1:3 with linespoints title "Actual Flowrate", \\ "-" using 1:3 with linespoints smooth bezier title "Actual Flowrate smooth", \\ f(x) title sprintf("y=B+A*x, A=%.2f, B=%.1f, TempFactor 1/A: %.2f", a, b, 1/a)\n""") writeDataSet(f, dataSet) writeDataSet(f, dataSet) writeDataSet(f, dataSet) f.close() printer.coolDown(HeaterEx1) # Enable flowrate limit printer.sendCommandParamV(CmdEnableFRLimit, [packedvalue.uint8_t(1)])
def insertFilament(args, parser): planner = parser.planner printer = planner.printer def manualMoveE(): current_position = parser.getRealPos() aofs = current_position[A_AXIS] print "cura: ", aofs kbd = GetChar("Enter (f)orward (b)ackwards (F)orward 10mm (B)ackwards 10mm (q)uit") ch = " " while ch not in "q\n": ch = kbd.getc() print "ch: ", ch if ch == "f": # filament forward, 'small' step aofs += 1 elif ch == "F": # filament forward, 'big' step aofs += 10 elif ch == "b": # filament backwards, 'small' step aofs -= 1 elif ch == "B": # filament backwards, 'big' step aofs -= 10 printer.sendPrinterInit() # XXX hardcoded feedrate parser.execute_line("G0 F%d A%f" % (5*60, aofs)) planner.finishMoves() printer.sendCommandParamV(CmdMove, [MoveTypeNormal]) printer.sendCommand(CmdEOT) printer.waitForState(StateIdle, wait=0.1) commonInit(args, parser) # Move to mid-position feedrate = PrinterProfile.getMaxFeedrate(X_AXIS) parser.execute_line("G0 F%d X%f Y%f" % (feedrate*60, planner.MAX_POS[X_AXIS]/2, planner.MAX_POS[Y_AXIS]/2)) planner.finishMoves() printer.sendCommandParamV(CmdMove, [MoveTypeNormal]) printer.sendCommand(CmdEOT) printer.waitForState(StateIdle) t1 = MatProfile.getHotendBaseTemp() printer.heatUp(HeaterEx1, t1, wait=t1 - 5) print "\nInsert filament.\n" manualMoveE() print "\nForwarding filament.\n" manualMove(parser, A_AXIS, FILAMENT_REVERSAL_LENGTH * 0.85) print "\nExtrude filament.\n" manualMoveE() # # Retract # printer.sendPrinterInit() parser.execute_line("G10") planner.finishMoves() printer.sendCommandParamV(CmdMove, [MoveTypeNormal]) printer.sendCommand(CmdEOT) printer.waitForState(StateIdle) if not args.noCoolDown: printer.coolDown(HeaterEx1, wait=150)
def printWorker(self): parser = argparse.ArgumentParser(description='%s, Direct Drive USB Print.' % sys.argv[0]) parser.add_argument("-d", dest="device", action="store", type=str, help="Device to use, default: /dev/ttyACM0.", default="/dev/ttyACM0") parser.add_argument("-b", dest="baud", action="store", type=int, help="Baudrate, default 115200.", default=115200) parser.add_argument("-f", dest="file", action="store", type=str, help="Gcode to print") parser.add_argument("-F", dest="fakeendstop", action="store", type=bool, help="fake endstops", default=False) parser.add_argument("-nc", dest="noCoolDown", action="store", type=bool, help="Debug: don't wait for heater cool down after print.", default=False) parser.add_argument("-t0", dest="t0", action="store", type=int, help="Temp 0 (heated bed), default comes from mat. profile.") parser.add_argument("-t1", dest="t1", action="store", type=int, help="Temp 1 (hotend 1), default comes from mat. profile.") parser.add_argument("-mat", dest="mat", action="store", help="Name of material profile to use [pla, abs...], default is pla.", default="pla_1.75mm") parser.add_argument("-smat", dest="smat", action="store", help="Name of specific material profile to use.") parser.add_argument("-noz", dest="nozzle", action="store", help="Name of nozzle profile to use [nozzle40, nozzle80...], default is nozzle40.", default="nozzle40") self.args = parser.parse_args() self.args.mode = "dlprint" # print "args: ", self.args (self.parser, self.planner, self.printer) = ddprint.initParser(self.args, gui=self) # util.commonInit(self.args, self.parser) try: self.printer.commandInit(self.args) except SerialException: msg = "Can't open serial device '%s' (baudrate: %d)!\n\nPress OK to exit." % (self.args.device, self.args.baud) self.guiQueue.put(SyncCall(self.quit, msg)) return self.mat_t0 = MatProfile.getBedTemp() self.mat_t1 = MatProfile.getHotendBaseTemp() # self.fn.set_value(self.args.file) self.guiQueue.put(SyncCall(self.fn.set_value, self.args.file)) while True: try: while True: # self.guiQueue.put("hi") # self.guiQueue.put(SyncCall(self.appLog.buffer, ["juhu"])) workDone = False while not self.cmdQueue.empty(): obj = self.cmdQueue.get() obj.call() workDone = True if time.time() - self.lastUpdate > 2.5: # status = self.printer.getStatus() # self.guiQueue.put(SyncCall(self.updateStatus, status)) self.printer.getStatus() workDone = True self.lastUpdate = time.time() if not workDone: time.sleep(0.1) except stoppableThread.StopThread: self.printThread.incStopCount() self.log("caught StopThread, continue....")
def main(): argParser = argparse.ArgumentParser(description='%s, Direct Drive USB Print.' % sys.argv[0]) argParser.add_argument("-d", dest="device", action="store", type=str, help="Device to use, default: /dev/ttyACM0.", default="/dev/ttyACM0") argParser.add_argument("-b", dest="baud", action="store", type=int, help="Baudrate, default 500000.", default=500000) argParser.add_argument("-t0", dest="t0", action="store", type=int, help="Temp 0 (heated bed), default comes from mat. profile.") argParser.add_argument("-t1", dest="t1", action="store", type=int, help="Temp 1 (hotend 1), default comes from mat. profile.") argParser.add_argument("-kAdvance", dest="kAdvance", action="store", type=float, help="K-Advance factor, default comes from mat. profile.") argParser.add_argument("-startAdvance", dest="startAdvance", action="store", type=float, help="Gradual advance: advance startvalue.") argParser.add_argument("-advIncrease", dest="advIncrease", action="store", type=float, help="Gradual advance: increase kAdvance by advIncrease after each step.") argParser.add_argument("-advStepHeight", dest="advStepHeight", action="store", type=int, help="Gradual advance: height of each step (number of layers).") argParser.add_argument("-mat", dest="mat", action="store", help="Name of generic material profile to use [pla, abs...], default is pla.", default="pla_1.75mm") argParser.add_argument("-smat", dest="smat", action="store", help="Name of specific material profile to use.") argParser.add_argument("-noz", dest="nozzle", action="store", help="Name of nozzle profile to use [nozzle40, nozzle80...], default is nozzle40.", default="nozzle40") argParser.add_argument("-np", dest="noPrime", action="store_const", const=True, help="Debug: don't prime nozzle, to test extrusion-less moves.") # fake endstops as long we have no real ones argParser.add_argument("-F", dest="fakeendstop", action="store", type=bool, help="Debug: fake endstops", default=False) argParser.add_argument("-nc", dest="noCoolDown", action="store", type=bool, help="Debug: don't wait for heater cool down after print.", default=False) argParser.add_argument("-fr", dest="feedrate", action="store", type=float, help="Feedrate for move commands.", default=0) argParser.add_argument("-rl", dest="retractLength", action="store", type=float, help="Retraction length, default comes from printer profile.", default=0) subparsers = argParser.add_subparsers(dest="mode", help='Mode: mon(itor)|print|store|reset|pre(process).') sp = subparsers.add_parser("autoTune", help=u"Autotune hotend PID values.") sp = subparsers.add_parser("binmon", help=u"Monitor serial printer interface (binary responses).") sp = subparsers.add_parser("changenozzle", help=u"Heat hotend and change nozzle.") sp = subparsers.add_parser("mon", help=u"Monitor serial printer interface (asci).") sp = subparsers.add_parser("print", help=u"Download and print file at once.") sp.add_argument("gfile", help="Input GCode file.") sp = subparsers.add_parser("writeEepromFloat", help=u"Store float value into eeprom.") sp.add_argument("name", help="Valuename.") sp.add_argument("value", action="store", type=float, help="value (float).") # sp = subparsers.add_parser("reset", help=u"Try to stop/reset printer.") sp = subparsers.add_parser("pre", help=u"Preprocess gcode, for debugging purpose.") sp.add_argument("gfile", help="Input GCode file.") sp = subparsers.add_parser("dumpeeprom", help=u"dump eeprom settings.") sp = subparsers.add_parser("factoryReset", help=u"FactoryReset of eeprom settings, new bed leveling needed.") sp = subparsers.add_parser("test", help=u"Debug: tests for debugging purpose.") sp = subparsers.add_parser("disableSteppers", help=u"Disable stepper current (this dis-homes the printer).") sp = subparsers.add_parser("home", help=u"Home the printer.") sp = subparsers.add_parser("measureTempFlowrateCurve", help=u"Determine temperature/flowrate properties of filament.") sp.add_argument("tstart", action="store", type=int, help="Start temperature.") sp.add_argument("tend", action="store", type=int, help="End temperature.") sp.add_argument("-tstep", action="store", type=int, help="Temperature step width.", default=2) sp = subparsers.add_parser("moverel", help=u"Debug: Move axis manually, relative coords.") sp.add_argument("axis", help="Axis (XYZAB).", type=str) sp.add_argument("distance", action="store", help="Move-distance (+/-) in mm.", type=float) sp = subparsers.add_parser("moveabs", help=u"Debug: Move axis manually, absolute coords.") sp.add_argument("axis", help="Axis (XYZAB).", type=str) sp.add_argument("distance", action="store", help="Move-distance (+/-) in mm.", type=float) sp = subparsers.add_parser("insertFilament", help=u"Insert filament (heatup, forward filament).") sp = subparsers.add_parser("removeFilament", help=u"Remove filament (heatup, retract filament).") sp = subparsers.add_parser("bedLeveling", help=u"Do bed leveling sequence.") sp = subparsers.add_parser("bedLevelAdjust", help=u"Adjust bedleveling offset - dangerous.") sp.add_argument("distance", action="store", help="Adjust-distance (+/-) in mm.", type=float) sp = subparsers.add_parser("heatHotend", help=u"Heat up hotend (to clean it, etc).") sp = subparsers.add_parser("genTempTable", help=u"Generate extrusion rate limit table.") sp = subparsers.add_parser("getEndstops", help=u"Get current endstop state.") sp = subparsers.add_parser("getFilSensor", help=u"Get current filament position.") sp = subparsers.add_parser("getpos", help=u"Get current printer and virtual position.") sp = subparsers.add_parser("getTemps", help=u"Get current temperatures (Bed, Extruder1, [Extruder2]).") sp = subparsers.add_parser("getTempTable", help=u"Get temperature-speed table from printer, print it to stdout and to /tmp/temptable_printer.txt.") sp = subparsers.add_parser("getStatus", help=u"Get current printer status.") sp = subparsers.add_parser("zRepeatability", help=u"Debug: Move Z to 10 random positions to test repeatability.") sp = subparsers.add_parser("stop", help=u"Stop print, cooldown, home, disable steppers.") sp = subparsers.add_parser("stepResponse", help=u"Measure and plot stepResponse of hotend PID.") sp = subparsers.add_parser("retract", help=u"Debug: Do the end-of-print retract manually after heating up.") sp = subparsers.add_parser("fanspeed", help=u"Set fan speed manually.") sp.add_argument("speed", help="Fanspeed 0 - 255.", type=int) sp = subparsers.add_parser("testFilSensor", help=u"Debug: move filament manually, output filament sensor measurement.") sp.add_argument("distance", action="store", help="Move-distance (+/-) in mm.", type=float) sp = subparsers.add_parser("calibrateFilSensor", help=u"Debug: helper to determine the ratio of stepper to flowrate sensor.") args = argParser.parse_args() (parser, planner, printer) = initParser(args, mode=args.mode) steps_per_mm = PrinterProfile.getStepsPerMMVector() if args.mode == 'autoTune': util.measureHotendStepResponse(args, parser) elif args.mode == 'changenozzle': util.changeNozzle(args, parser) elif args.mode == "binmon": printer.initSerial(args.device, args.baud) while True: try: (cmd, payload) = printer.readResponse() except RxTimeout: pass else: print "Response cmd :", cmd print "Response payload:", payload.encode("hex") printer.checkErrorResponse(cmd, payload, False) elif args.mode == 'print': util.commonInit(args, parser) t0 = MatProfile.getBedTemp() t1 = MatProfile.getHotendStartTemp() + planner.l0TempIncrease # Send heat up command print "\nPre-Heating bed...\n" printer.heatUp(HeaterBed, t0) print "\nPre-Heating extruder...\n" printer.heatUp(HeaterEx1, t1/2) f = parser.preParse(args.gfile) if not args.noPrime: util.prime(parser) lineNr = 0 printStarted = False for line in f: parser.execute_line(line) # # Send more than one 512 byte block for dlprint # if lineNr > 1000 and (lineNr % 250) == 0: # check temp and start print if not printStarted: print "\nHeating bed (t0: %d)...\n" % t0 printer.heatUp(HeaterBed, t0, t0) print "\nHeating extruder (t1: %d)...\n" % t1 printer.heatUp(HeaterEx1, t1, t1-1) # Send print command printer.sendCommandParamV(CmdMove, [MoveTypeNormal]) printStarted = True else: # Stop sending moves on error status = printer.getStatus() pprint.pprint(status) if not printer.stateMoving(status): break lineNr += 1 print "Parsed %d gcode lines." % lineNr # # Add a move to lift the nozzle end of print # util.endOfPrintLift(parser) planner.finishMoves() printer.sendCommand(CmdEOT) # Start print if less than 1000 lines or temp not yet reached: if not printStarted: print "\nHeating bed (t0: %d)...\n" % t0 printer.heatUp(HeaterBed, t0, t0) print "\nHeating extruder (t1: %d)...\n" % t1 printer.heatUp(HeaterEx1, t1, t1-1) # Send print command printer.sendCommandParamV(CmdMove, [MoveTypeNormal]) printer.waitForState(StateIdle) printer.coolDown(HeaterEx1) printer.coolDown(HeaterBed) ddhome.home(parser, args.fakeendstop) printer.sendCommand(CmdDisableSteppers) if not args.noCoolDown: printer.coolDown(HeaterEx1, wait=150) printer.coolDown(HeaterBed, wait=55) printer.readMore() # Exit simulator for profiling # printer.sendCommand(CmdExit) elif args.mode == "pre": # Virtuelle position des druckkopfes falls 'gehomed' homePosMM = util.MyPoint( X = planner.X_HOME_POS, Y = planner.Y_HOME_POS, Z = planner.Z_HOME_POS, # - 20, ) parser.setPos(homePosMM) f = parser.preParse(args.gfile) lineNr = 0 for line in f: parser.execute_line(line) lineNr += 1 print "Parsed %d gcode lines." % lineNr planner.finishMoves() elif args.mode == "mon": printer.initSerial(args.device, args.baud) while True: printer.readMore() elif args.mode == 'dumpeeprom': printer.commandInit(args) resp = printer.query(CmdGetEepromVersion) if util.handleGenericResponse(resp): print "Eepromversion: ", util.getResponseString(resp[1], 1) settingsDict = printer.getEepromSettings() print "eepromSettings: ", pprint.pprint(settingsDict) elif args.mode == 'factoryReset': printer.commandInit(args) printer.sendCommand(CmdEepromFactory) elif args.mode == 'disableSteppers': printer.commandInit(args) printer.sendCommand(CmdDisableSteppers) elif args.mode == 'measureTempFlowrateCurve': util.measureTempFlowrateCurve(args, parser) elif args.mode == 'moverel': assert(args.axis.upper() in "XYZAB") printer.commandInit(args) axis = util.dimIndex[args.axis.upper()] util.manualMove(parser, axis, args.distance, args.feedrate) elif args.mode == 'moveabs': assert(args.axis.upper() in "XYZAB") printer.commandInit(args) axis = util.dimIndex[args.axis.upper()] util.manualMove(parser, axis, args.distance, args.feedrate, True) elif args.mode == 'insertFilament': util.insertFilament(args, parser, args.feedrate) elif args.mode == 'removeFilament': util.removeFilament(args, parser, args.feedrate) elif args.mode == 'bedLeveling': util.bedLeveling(args, parser) elif args.mode == 'bedLevelAdjust': util.bedLevelAdjust(args, parser) elif args.mode == 'heatHotend': util.heatHotend(args, parser) elif args.mode == 'genTempTable': util.genTempTable(planner) elif args.mode == 'getEndstops': printer.commandInit(args) res = printer.getEndstops() print "Endstop state: ", res elif args.mode == 'getFilSensor': printer.commandInit(args) print "Filament pos:", printer.getFilSensor() elif args.mode == 'getpos': printer.commandInit(args) res = printer.getPos() curPosMM = util.MyPoint( X = res[0] / float(steps_per_mm[0]), Y = res[1] / float(steps_per_mm[1]), Z = res[2] / float(steps_per_mm[2]), A = res[3] / float(steps_per_mm[3]), # B = res[4] / float(steps_per_mm[4]), ) (homePosMM, homePosStepped) = planner.getHomePos() print "Printer pos [steps]:", res print "Printer pos [mm]:", curPosMM print "Virtual home pos [mm]: ", homePosMM elif args.mode == 'getTemps': printer.commandInit(args) printer.getTemps() elif args.mode == 'getTempTable': printer.commandInit(args) (baseTemp, tempTable) = printer.getTempTable() print "tempTable: ", pprint.pprint(tempTable) util.printTempTable(baseTemp, tempTable) elif args.mode == 'getStatus': printer.commandInit(args) status = printer.getStatus() print "Status: " pprint.pprint(status) elif args.mode == 'home': printer.commandInit(args) ddhome.home(parser, args.fakeendstop) elif args.mode == 'zRepeatability': util.zRepeatability(parser) elif args.mode == 'stepResponse': util.stepResponse(args, parser) elif args.mode == 'retract': util.retract(args, parser) elif args.mode == 'stop': printer.commandInit(args) util.stopMove(args, parser) elif args.mode == 'fanspeed': printer.commandInit(args) printer.sendCommandParamV(CmdFanSpeed, [packedvalue.uint8_t(args.speed)]) elif args.mode == 'testFilSensor': ddtest.testFilSensor(args, parser) elif args.mode == 'calibrateFilSensor': ddtest.calibrateFilSensor(args, parser) elif args.mode == 'test': printer.commandInit(args) """ dirbits = printer.getDirBits() print "dirbits:", dirbits # printer.readMore() import time while True: temp = printer.getTemp(doLog=False)[1] print "T1:", temp time.sleep(0.1) """ if args.feedrate == 0: printer.sendCommandParamV(CmdContinuousE, [packedvalue.uint16_t(0)]) else: import time printer.sendCommandParamV(CmdContinuousE, [packedvalue.uint16_t(util.eTimerValue(planner, 0.5))]) for s in range(int(args.feedrate)): time.sleep(1) printer.sendCommandParamV(CmdSetContTimer, [packedvalue.uint16_t(util.eTimerValue(planner, 1+s))]) elif args.mode == "writeEepromFloat": util.writeEEpromFloat(args, parser) else: print "Unknown command: ", args.mode assert(0)
def __init__(self, comment, # stepped_point, displacement_vector, displacement_vector_steps, feedrate, # mm/s ): self.comment=comment self.displacement_vector3=displacement_vector[:3] self.displacement_vector_steps3=displacement_vector_steps[:3] self.extrusion_displacement_raw = displacement_vector[3:] self.extrusion_displacement_steps_raw = displacement_vector_steps[3:] # # Move distance in XYZAB plane # self.distance = displacement_vector.len5() # # Move distance in XYZ plane # self.distance3 = displacement_vector.len3() # self.eOnly = self.displacement_vector3 == 3*[0] self.eOnly = self.distance3 == 0 # # Limit feedrate by maximum extrusion rate # self.feedrateS = feedrate # mm/s # Do not count very small moves, the computation of the extrusion rate is inaccurate because of the # discretization in the gcodeparser (map float values to discrete stepper values). if self.distance3 >= 0.1 and self.isExtrudingMove(A_AXIS) or self.isExtrudingMove(B_AXIS): matArea = MatProfile.getMatArea() assert(not self.eOnly) t = self.distance3 / feedrate extrusionVolume = displacement_vector[A_AXIS] * matArea extrusionRate = extrusionVolume / t # print "extrusionRate:", displacement_vector[A_AXIS], t, extrusionRate if extrusionRate > NozzleProfile.getNetMaxExtrusionRate(): print "Warning, extrusion rate to high: %.1f mm³/s, Move: '%s', len: %.3f., extrusionVolume: %.5f" % (extrusionRate, comment, self.distance3, extrusionVolume) # xxx feedrate adjust disabled ### print "Warning, extrusion rate to high: %.1f mm³/s, reducing to %.1f mm³/s, Move: '%s', len: %.3f., extrusionVolume: %.5f" % (extrusionRate, NozzleProfile.getNetMaxExtrusionRate(), comment, self.distance3, extrusionVolume) ### self.feedrateS = feedrate * (NozzleProfile.getNetMaxExtrusionRate() / extrusionRate) # print "Adjusted feedrate: ", feedrate, self.feedrateS self.trueStartSpeed = self.nominalStartSpeed = None self.trueEndSpeed = self.nominalEndSpeed = None self.accelData = AccelData() self.stepData = StepData() self.lastMove = None self.nextMove = None self.moveNumber = 0 # debug self.state = 0 # 1: joined, 2: accel planned, 3: steps planned self.streamed = False # Time for the three phases of this move self.accelTime = 0 self.linearTime = 0 self.deccelTime = 0
def printWorker(self): parser = argparse.ArgumentParser( description='%s, Direct Drive USB Print.' % sys.argv[0]) parser.add_argument("-d", dest="device", action="store", type=str, help="Device to use, default: /dev/ttyACM0.", default="/dev/ttyACM0") parser.add_argument("-b", dest="baud", action="store", type=int, help="Baudrate, default 500000.", default=500000) parser.add_argument("-f", dest="file", action="store", type=str, help="Gcode to print") parser.add_argument("-F", dest="fakeendstop", action="store", type=bool, help="fake endstops", default=False) parser.add_argument( "-nc", dest="noCoolDown", action="store", type=bool, help="Debug: don't wait for heater cool down after print.", default=False) parser.add_argument( "-t0", dest="t0", action="store", type=int, help="Temp 0 (heated bed), default comes from mat. profile.") parser.add_argument( "-t1", dest="t1", action="store", type=int, help="Temp 1 (hotend 1), default comes from mat. profile.") parser.add_argument( "-kAdvance", dest="kAdvance", action="store", type=float, help="K-Advance factor, default comes from mat. profile.") parser.add_argument( "-mat", dest="mat", action="store", help= "Name of material profile to use [pla, abs...], default is pla.", default="pla_1.75mm") parser.add_argument( "-rl", dest="retractLength", action="store", type=float, help="Retraction length, default comes from printer profile.", default=0) parser.add_argument("-smat", dest="smat", action="store", help="Name of specific material profile to use.") parser.add_argument( "-noz", dest="nozzle", action="store", help= "Name of nozzle profile to use [nozzle40, nozzle80...], default is nozzle40.", default="nozzle40") self.args = parser.parse_args() self.args.mode = "dlprint" # print "args: ", self.args (self.parser, self.planner, self.printer) = ddprint.initParser(self.args, gui=self) # util.commonInit(self.args, self.parser) try: self.printer.commandInit(self.args) except SerialException: msg = "Can't open serial device '%s' (baudrate: %d)!\n\nPress OK to exit." % ( self.args.device, self.args.baud) self.guiQueue.put(SyncCall(self.quit, msg)) return self.mat_t0 = MatProfile.getBedTemp() self.mat_t0_reduced = MatProfile.getBedTempReduced() self.mat_t1 = MatProfile.getHotendStartTemp( ) + self.planner.l0TempIncrease # self.fn.set_value(self.args.file) self.guiQueue.put(SyncCall(self.fn.set_value, self.args.file)) while True: try: while True: # self.guiQueue.put("hi") # self.guiQueue.put(SyncCall(self.appLog.buffer, ["juhu"])) workDone = False while not self.cmdQueue.empty(): obj = self.cmdQueue.get() obj.call() workDone = True if time.time() - self.lastUpdate > 2.5: # status = self.printer.getStatus() # self.guiQueue.put(SyncCall(self.updateStatus, status)) self.printer.getStatus() workDone = True self.lastUpdate = time.time() if not workDone: time.sleep(0.1) except stoppableThread.StopThread: self.printThread.incStopCount() self.log("caught StopThread, continue....")
def __init__(self, args, gui=None): if Planner.__single: raise RuntimeError('A Planner already exists') Planner.__single = self if gui: self.gui = gui else: self.gui = dddumbui.DumbGui() self.args = args self.printer = Printer.get() # self.parser = UM2GcodeParser.get() jerk = [] for dim in dimNames: jerk.append(PrinterProfile.getValues()['axes'][dim]['jerk']) self.jerk = VVector(jerk) self.gui.log("Jerk vector: ", self.jerk) self.zeroPos = util.MyPoint() # Lowest allowed speed in mm/s for every dimension self.min_speeds = 5 * [0] for dim in range(5): # vmin = (fTimer / maxTimerValue) / steps_per_mm if PrinterProfile.getStepsPerMM(dim): self.min_speeds[dim] = float(fTimer) / (maxTimerValue24 * PrinterProfile.getStepsPerMM(dim)) self.gui.log( "min speeds: ", self.min_speeds) # # Constants, xxx todo: query from printer and/or profile # self.HOMING_FEEDRATE = [100, 100, 40] # set the homing speeds (mm/s) self.HOME_RETRACT_MM = 7 # [mm] # ENDSTOP SETTINGS: # Sets direction of endstops when homing; 1=MAX, -1=MIN self.X_HOME_DIR = -1 self.Y_HOME_DIR = 1 self.Z_HOME_DIR = 1 self.HOME_DIR = (self.X_HOME_DIR, self.Y_HOME_DIR, self.Z_HOME_DIR) # XXX defined in profile !!! # Travel limits after homing self.X_MIN_POS = 0 self.X_MAX_POS = 225.0 # 230.0 # X_MIN_POS = 0 self.Y_MAX_POS = 225.0 # 230.0 # Y_MIN_POS = 0 # self.Z_MAX_POS = 229.0 # 230.0 // Dauerdruckplatte hat 5mm im vergleich zur glassplatte 4mm self.Z_MAX_POS = 212.25 # solex nozzle # Z_MIN_POS = 0 self.MAX_POS = (self.X_MAX_POS, self.Y_MAX_POS, self.Z_MAX_POS) # Bed leveling constants self.LEVELING_OFFSET = 0.1 # Assumed thickness of feeler gauge/paper used in leveling (mm) # self.HEAD_HEIGHT = 35.0 # Let enough room for the head, XXX UM2 specific !!! self.HEAD_HEIGHT = 15.0 # Let enough room for the head, XXX UM2 specific !!! # Homing self.X_HOME_POS = self.X_MIN_POS self.Y_HOME_POS = self.Y_MAX_POS self.Z_HOME_POS = self.Z_MAX_POS # XXX + add_homeing_z # # End Constants # self.plotfile = None # Headspeed/extrusionspeed where autotemp increase starts self.ExtrusionAmountLow = 30 # [mm/s] for a 1mm nozzle if UseExtrusionAutoTemp: # self.ExtrusionAmountLow = 7.5 # [mm³/s] for a 1mm nozzle area04 = pow(0.4, 2)*math.pi/4 self.ExtrusionAmountLow = MatProfile.getBaseExtrusionRate() * (NozzleProfile.getArea() / area04) self.reset()