Example #1
0
def commonInit(args, parser):

    planner = parser.planner
    printer = planner.printer

    printer.commandInit(args)

    ddhome.home(parser, args.fakeendstop)
    downloadTempTable(printer)
    printer.sendPrinterInit()
Example #2
0
def stopMove(args, parser):

    planner = parser.planner
    printer = planner.printer

    if printer.isHomed():
        parser.reset()
        planner.reset()
        ddhome.home(parser, args.fakeendstop)

    printer.sendCommand(CmdStopMove)
    printer.sendCommand(CmdDisableSteppers)
Example #3
0
def zRepeatability(parser):

    import random

    printer.commandInit(args)

    feedrate = PrinterProfile.getMaxFeedrate(Z_AXIS)

    ddhome.home(parser, args.fakeendstop)

    printer.sendPrinterInit()

    for i in range(10):

        parser.execute_line("G0 F%d X115 Y210 Z10" % (feedrate*60))
        parser.execute_line("G0 F%d Z%f" % (feedrate*60, random.randint(20, 150)))

    planner.finishMoves()
    printer.sendCommandParamV(CmdMove, [MoveTypeNormal])
    printer.sendCommand(CmdEOT)

    printer.waitForState(StateIdle)
Example #4
0
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)
Example #5
0
    def printFile(self):

        try:

            self.parser.reset()
            self.planner.reset()

            ddhome.home(self.parser, self.args.fakeendstop)
            util.downloadTempTable(self.planner)
            self.printer.sendPrinterInit()

            # Send heat up  command
            self.log("\nPre-Heating bed (t0: %d)...\n" % self.mat_t0)
            self.printer.heatUp(HeaterBed, self.mat_t0)

            t = int(self.mat_t1 * 0.5)
            self.log("\nPre-Heating extruder (t1: %d)...\n" % t)
            self.printer.heatUp(HeaterEx1, t)

            # Send printing moves
            f = self.parser.preParse(self.fn.get_value())

            # Send priming moves
            util.prime(self.parser)

            lineNr = 0
            printStarted = False
            lastUpdate = time.time()

            for line in f:
                self.parser.execute_line(line)

                #
                # Send more than one 512 byte block for dlprint
                #
                # if lineNr > 1000 and (lineNr % 250) == 0:
                if time.time() > (lastUpdate + 0.5):

                    # check temp and start print

                    if lineNr > 1000 and not printStarted:

                        self.log("\nHeating bed (t0: %d)...\n" % self.mat_t0)
                        self.printer.heatUp(HeaterBed,
                                            self.mat_t0,
                                            wait=self.mat_t0)
                        self.log("\nHeating extruder (t1: %d)...\n" %
                                 self.mat_t1)
                        self.printer.heatUp(HeaterEx1, self.mat_t1,
                                            self.mat_t1 - 1)

                        # Send print command
                        self.printer.sendCommandParamV(CmdMove,
                                                       [MoveTypeNormal])
                        printStarted = True

                    status = self.printer.getStatus()
                    # self.guiQueue.put(SyncCall(self.updateStatus, status))
                    if printStarted and not self.printer.stateMoving(status):
                        break

                    lastUpdate = time.time()

                lineNr += 1

            print "Parsed %d gcode lines." % lineNr

            #
            # Add a move to lift the nozzle from the print if not ultigcode flavor
            #
            # if not self.parser.ultiGcodeFlavor:
            util.endOfPrintLift(self.parser)

            self.planner.finishMoves()
            self.printer.sendCommand(CmdEOT)

            # XXX start print if less than 1000 lines or temp not yet reached:
            if not printStarted:

                self.log("\nHeating bed (t0: %d)...\n" % self.mat_t0)
                self.printer.heatUp(HeaterBed, self.mat_t0, self.mat_t0)
                self.log("\nHeating extruder (t1: %d)...\n" % self.mat_t1)
                self.printer.heatUp(HeaterEx1, self.mat_t1, self.mat_t1 - 1)

                # Send print command
                self.printer.sendCommandParamV(CmdMove, [MoveTypeNormal])

            status = self.printer.getStatus()
            # self.guiQueue.put(SyncCall(self.updateStatus, status))
            while status['state'] != StateIdle:
                time.sleep(2)
                status = self.printer.getStatus()
                # self.guiQueue.put(SyncCall(self.updateStatus, status))

            self.printer.coolDown(HeaterEx1)
            self.printer.coolDown(HeaterBed)

            ddhome.home(self.parser, self.args.fakeendstop)

            self.printer.sendCommand(CmdDisableSteppers)

        except stoppableThread.StopThread:
            # Stop of current action requested
            self.printThread.incStopCount()
            self.log("printFile(): Caught StopThread, bailing out.")
            return

        except FatalPrinterError, ex:
            self.log("printFile(): Caught FatalPrinterError: ", ex.msg)
            # Reset line numbers in case of a printer restart.
            self.printer.resetLineNumber()
Example #6
0
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)
Example #7
0
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)
Example #8
0
def calibrateFilSensor(args, parser):
    def writeDataSet(f, data):

        for tup in data:
            f.write("%f %f\n" % tup)
        f.write("E\n")

    planner = parser.planner
    printer = planner.printer

    maxFeedrate = args.feedrate or 15

    eAccel = PrinterProfile.getMaxAxisAcceleration()[A_AXIS]

    printer.commandInit(args)

    ddhome.home(parser, args.fakeendstop)

    # Disable flowrate limit
    printer.sendCommandParamV(CmdEnableFRLimit, [packedvalue.uint8_t(0)])

    # Disable temp-flowrate limit
    util.downloadDummyTempTable(printer)

    # XXX todo set filament sensor calibration factor to 1.0:
    assert (
        0
    )  # printer.sendCommandParamV(CmdSetFRCalFactor, [packedvalue.float_t(1.0)])

    feedrate = 0.25
    startPos = parser.getPos()[A_AXIS]

    calFile = open("calibrateFilSensor.json", "w")
    calFile.write('{\n    "filSensorCalibration": [\n')

    calValues = []

    while feedrate <= maxFeedrate:

        tStartup = util.getStartupTime(feedrate)
        tAccel = feedrate / eAccel

        accelDistance = 5 * feedrate
        print "accelDistance: ", accelDistance

        current_position = parser.getPos()
        apos = current_position[A_AXIS]

        printer.sendPrinterInit()

        parser.execute_line(
            "G0 F%d %s%f" %
            (feedrate * 60, util.dimNames[A_AXIS], apos + accelDistance))

        planner.finishMoves()
        printer.sendCommand(CmdEOT)
        printer.sendCommandParamV(CmdMove, [MoveTypeNormal])

        status = printer.getStatus()

        while status["slippage"] > 1.5:
            print "wait for startup..."
            status = printer.getStatus()
            time.sleep(0.1)

        data = []
        t = time.time()
        while status["state"] != StateIdle:

            tMeasure = time.time() - t

            if tMeasure >= tStartup:

                data.append(status["slippage"])

            status = printer.getStatus()
            time.sleep(0.01)

        # Cut the last tAccel:
        cut = int(tAccel / 0.01 + 1)
        del data[-cut:]

        # Average of ratio for this speed
        grip = sum(data) / len(data)

        # Calibration value, targetSpeed/measuredSensorSpeed, this ist the value
        # to multiply the measured sensor speed to get the real speed:
        print "speed:", feedrate, "ratio:", grip

        calValues.append((feedrate, grip))

        feedrate += 0.25

    f = open("calibrateFilSensor.gnuplot", "w")
    f.write("""
set grid
set yrange [0:%f]
plot '-' using 1:2 with linespoints title 'ratio'
""" % max(1.5, feedrate * 2))

    writeDataSet(f, calValues)
    f.write("pause mouse close\n")

    calFile.write(",\n".join(
        map(lambda tup: "        [%f, %f]" % tup, calValues)))
    calFile.write("\n    ]\n")
    calFile.write("}\n")
    calFile.close()

    printer.sendPrinterInit()

    parser.execute_line("G0 F%d %s%f" %
                        (maxFeedrate * 60, util.dimNames[A_AXIS], startPos))

    planner.finishMoves()
    printer.sendCommand(CmdEOT)
    printer.sendCommandParamV(CmdMove, [MoveTypeNormal])

    printer.waitForState(StateIdle)

    # Enable flowrate limit
    printer.sendCommandParamV(CmdEnableFRLimit, [packedvalue.uint8_t(1)])
Example #9
0
    def printFile(self):

        try:

            self.parser.reset()
            self.planner.reset()

            ddhome.home(self.parser, self.args.fakeendstop)
            util.downloadTempTable(self.printer)
            self.printer.sendPrinterInit()

            # Send heat up  command
            self.log( "\nPre-Heating bed (t0: %d)...\n" % self.mat_t0)
            self.printer.heatUp(HeaterBed, self.mat_t0)

            t = int(self.mat_t1 * 0.5)
            self.log( "\nPre-Heating extruder (t1: %d)...\n" % t)
            self.printer.heatUp(HeaterEx1, t)

            # Send printing moves
            f = self.parser.preParse(self.fn.get_value())

            # Send priming moves
            util.prime(self.parser)

            lineNr = 0
            printStarted = False
            lastUpdate = time.time()

            for line in f:
                self.parser.execute_line(line)

                #
                # Send more than one 512 byte block for dlprint
                #
                # if lineNr > 1000 and (lineNr % 250) == 0:
                if time.time() > (lastUpdate + 0.5):

                    # check temp and start print

                    if lineNr > 1000 and not printStarted:

                        self.log( "\nHeating bed (t0: %d)...\n" % self.mat_t0 )
                        self.printer.heatUp(HeaterBed, self.mat_t0, wait=self.mat_t0)
                        self.log( "\nHeating extruder (t1: %d)...\n" % self.mat_t1 )
                        self.printer.heatUp(HeaterEx1, self.mat_t1, wait=self.mat_t1 - 10)

                        # Send print command
                        self.printer.sendCommandParamV(CmdMove, [MoveTypeNormal])
                        printStarted = True

                    status = self.printer.getStatus()
                    # self.guiQueue.put(SyncCall(self.updateStatus, status))
                    if printStarted and not self.printer.stateMoving(status):
                        break

                    lastUpdate = time.time()

                lineNr += 1

            print "Parsed %d gcode lines." % lineNr

            # 
            # Add a move to lift the nozzle from the print if not ultigcode flavor
            # 
            if not self.parser.ultiGcodeFlavor:
                util.endOfPrintLift(self.parser)

            self.planner.finishMoves()
            self.printer.sendCommand(CmdEOT)

            # XXX start print if less than 1000 lines or temp not yet reached:
            if not printStarted:

                self.log( "\nHeating bed (t0: %d)...\n" % self.mat_t0 )
                self.printer.heatUp(HeaterBed, self.mat_t0, self.mat_t0)
                self.log( "\nHeating extruder (t1: %d)...\n" % self.mat_t1 )
                self.printer.heatUp(HeaterEx1, self.mat_t1, wait=self.mat_t1 - 10)

                # Send print command
                self.printer.sendCommandParamV(CmdMove, [MoveTypeNormal])

            status = self.printer.getStatus()
            # self.guiQueue.put(SyncCall(self.updateStatus, status))
            while status['state'] != StateIdle:
                time.sleep(2)
                status = self.printer.getStatus()
                # self.guiQueue.put(SyncCall(self.updateStatus, status))

            self.printer.coolDown(HeaterEx1)
            self.printer.coolDown(HeaterBed)

            ddhome.home(self.parser, self.args.fakeendstop)

            self.printer.sendCommand(CmdDisableSteppers)

        except stoppableThread.StopThread:
            # Stop of current action requested
            self.printThread.incStopCount()
            self.log("printFile(): Caught StopThread, bailing out.")
            return

        except FatalPrinterError, ex:
            self.log("printFile(): Caught FatalPrinterError", ex.msg)
            # Reset line numbers in case of a printer restart.
            self.printer.resetLineNumber()
Example #10
0
def bedLeveling(args, parser):

    planner = parser.planner
    printer = planner.printer

    printer.commandInit(args)

    # Reset bedlevel offset in printer eeprom
    payload = struct.pack("<%dpf" % (len("add_homeing_z")+1), "add_homeing_z", 0)
    printer.sendCommand(CmdWriteEepromFloat, binPayload=payload)

    ddhome.home(parser, args.fakeendstop, True)

    zFeedrate = PrinterProfile.getMaxFeedrate(Z_AXIS)
    kbd = GetChar("Enter (u)p (d)own (U)p 1mm (D)own 1mm (2-5) Up Xmm (q)uit")

    def manualMoveZ():

        current_position = parser.getRealPos()
        zofs = current_position[Z_AXIS]
        print "curz: ", zofs

        ch = " "
        while ch not in "q\n":
            ch = kbd.getc()

            print "ch: ", ch
            if ch == "u":       # head down, 'small' step
                zofs -= 0.05
            elif ch == "U":     # head down, 'big' step
                zofs -= 1
            elif ch == "d":     # head up, 'small' step
                zofs += 0.05
            elif ch == "D":     # head up, 'big' step
                zofs += 1
            else:
                try:
                    o = int(ch) # up x mmm
                except ValueError:
                    continue
                if o < 2 or o > 5:
                    continue
                zofs -= o

            printer.sendPrinterInit()

            parser.execute_line("G0 F%d Z%f" % (zFeedrate*60, zofs))

            planner.finishMoves()
            printer.sendCommandParamV(CmdMove, [MoveTypeNormal])
            printer.sendCommand(CmdEOT)

            printer.waitForState(StateIdle, wait=0.1)


    feedrate = PrinterProfile.getMaxFeedrate(X_AXIS)

    #######################################################################################################
    print "Level point 1/3"

    printer.sendPrinterInit()
    parser.execute_line("G0 F%d X%f Y%f Z%f" % (feedrate*60, planner.X_MAX_POS/2, planner.Y_MAX_POS - 10, planner.HEAD_HEIGHT))

    planner.finishMoves()
    printer.sendCommandParamV(CmdMove, [MoveTypeNormal])
    printer.sendCommand(CmdEOT)

    printer.waitForState(StateIdle, wait=0.1)

    manualMoveZ()

    current_position = parser.getRealPos()
    print "curz: ", current_position[Z_AXIS]

    add_homeing_z = -1 * current_position[Z_AXIS];
    print "\nZ-Offset: ", add_homeing_z, "\n"

    # Store into printer eeprom:
    payload = struct.pack("<%dpf" % (len("add_homeing_z")+1), "add_homeing_z", add_homeing_z)
    printer.sendCommand(CmdWriteEepromFloat, binPayload=payload)

    # Finally we know the zero z position
    # current_position[Z_AXIS] = 0
    current_position[Z_AXIS] = planner.LEVELING_OFFSET;

    # Adjust the virtual position
    parser.set_position(current_position)

    # Adjust the printer position
    posStepped = vectorMul(current_position, parser.steps_per_mm)
    payload = struct.pack("<iiiii", *posStepped)
    printer.sendCommand(CmdSetHomePos, binPayload=payload)

    #######################################################################################################
    print "Level point 2/3", current_position

    printer.sendPrinterInit()
    parser.execute_line("G0 F%d Z5" % (zFeedrate*60))
    parser.execute_line("G0 F%d X35 Y20" % (feedrate*60))
    parser.execute_line("G0 F%d Z0.1" % (zFeedrate*60))

    planner.finishMoves()
    printer.sendCommandParamV(CmdMove, [MoveTypeNormal])
    printer.sendCommand(CmdEOT)

    printer.waitForState(StateIdle, wait=0.1)

    raw_input("\nAdjust left front buildplate screw and press <Return>\n")

    #######################################################################################################
    print "Level point 3/3", current_position

    printer.sendPrinterInit()
    parser.execute_line("G0 F%d Z5" % (zFeedrate*60))
    parser.execute_line("G0 F%d X%f" % (feedrate*60, planner.X_MAX_POS-10))
    parser.execute_line("G0 F%d Z0.1" % (zFeedrate*60))

    planner.finishMoves()
    printer.sendCommandParamV(CmdMove, [MoveTypeNormal])
    printer.sendCommand(CmdEOT)

    printer.waitForState(StateIdle, wait=0.1)

    raw_input("\nAdjust right fron buildplate screw and press <Return>\n")

    ddhome.home(parser, args.fakeendstop)
Example #11
0
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)])