Beispiel #1
0
class SerialFactory():
    
    def __init__(self):
        self.serial   = SerialUtils(debug=False)
        self.reply    = None
        self.command  = None
        self.response = {}
    
    def get_eeprom(self):
        self.response = self.serial.eeprom()
        self.output()
        
    def restore_eeprom(self):
        self.send('M502', False)
        self.send('M500', False)
        self.output()
    
    def send(self, codes, output = True):
        codes = codes.split('-')
        replies = []
        for code in codes:
            self.serial.sendGCode(code)
            replies.append(self.serial.getReply())
            time.sleep(0.2)
        self.command = codes
        self.reply   = replies
        if(output):
            self.output()
        
    def output(self):
        object = {
            'response' : self.response,
            'command'  : self.command,
            'reply'    : self.reply
        }
        
        print json.dumps(object)
Beispiel #2
0
class SerialFactory():
    def __init__(self):
        self.serial = SerialUtils(debug=False)
        self.reply = None
        self.command = None
        self.response = {}

    def get_eeprom(self):
        self.response = self.serial.eeprom()
        self.output()

    def restore_eeprom(self):
        self.send('M502', False)
        self.send('M500', False)
        self.output()

    def send(self, codes, output=True):
        codes = codes.split('-')
        replies = []
        for code in codes:
            self.serial.sendGCode(code)
            replies.append(self.serial.getReply())
            time.sleep(0.2)
        self.command = codes
        self.reply = replies
        if (output):
            self.output()

    def output(self):
        object = {
            'response': self.response,
            'command': self.command,
            'reply': self.reply
        }

        print json.dumps(object)
Beispiel #3
0
if (settings['hardware']['head']['type'] in HEAD_VERSION_CMDS):
    HEAD_VERSION_CMDS[settings['hardware']['head']['type']](su, settings)
else:
    hybridHead(su, settings)
""" exec hardware revisions """
if (settings['settings_type'] == 'custom'):
    customHardware(su, settings, config.get('printer', 'settings_file'))
elif hw_version in HW_VERSION_CMDS:
    HW_VERSION_CMDS[hw_version](su, settings,
                                config.get('printer', 'settings_file'))
else:
    settings['feeder']['show'] = True
    saveSettings(settings, config.get('printer', 'settings_file'))

if (save_settings):
    eeprom = su.eeprom()
    settings['e'] = eeprom['steps_per_unit']['e']
    saveSettings(settings, config.get('printer', 'settings_file'))
#### save all to EEPROM
commands.append('M500')
### alive machine
commands.append('M728')
### set ambient lights ###
commands.append('M701 S{0}'.format(settings['color']['r']))
commands.append('M702 S{0}'.format(settings['color']['g']))
commands.append('M703 S{0}'.format(settings['color']['b']))
su.sendGCode(commands)
su.close()
if os.path.isfile(config.get('task', 'lock_file')):
    os.remove(config.get('task', 'lock_file'))
Beispiel #4
0
def main():
    
    parser = argparse.ArgumentParser()

    parser.add_argument("-t", "--trace",    help="log travce file",        default=config.get('macro', 'trace_file'))
    parser.add_argument("-r", "--response", help="log response file",      default=config.get('macro', 'response_file'))
    parser.add_argument("-l", "--heigth",   help="height",                 default=38, type=int)
    parser.add_argument("-n", "--probes",   help="Number of probes",       default=1,  type=int)
    parser.add_argument("-s", "--skip",     help="Skip homing",            action="store_true")
    parser.add_argument("-d", "--debug",    help="Debug: print console",   action="store_true")
    args = parser.parse_args()
    #write LOCK FILE    
    open(config.get('task', 'lock_file'), 'w').close()
    
    """ ### init  ### """
    log_trace     = args.trace
    logfile       = args.response
    response_file = args.response
    num_probes    = args.probes
    skip_homing   = args.skip
    debug         = args.debug
    
    cycle=True
    s_warning=s_error=s_skipped=0
    probe_height=50.0
    milling_offset=0.0
    probe_offset_security=15
    
    screw_turns=["" for x in range(4)]
    screw_height=["" for x in range(4)]
    screw_degrees=["" for x in range(4)]
    
    #points to probe
    probed_points=np.array([[5+17,5+61.5,0],[5+17,148.5+61.5,0],[178+17,148.5+61.5,0],[178+17,5+61.5,0]])
    #first screw offset (lower left corner)
    screw_offset=[8.726,10.579,0]
    
    ''' #### START #### '''
    su = SerialUtils(debug = debug)
    su.trace('Manual Bed Calibration Wizard Initiated')
    eeprom = su.eeprom();
    probe_height = (abs(float(eeprom['probe_length'])) + 1 ) + probe_offset_security
    
    settings_file = open(config.get('printer', 'settings_file'))
    settings = json.load(settings_file)
    
    if 'settings_type' in settings and settings['settings_type'] == 'custom':
        settings_file = open(config.get('printer', 'custom_settings_file'))
        settings = json.load(settings_file)
    settings_file.close()
    
    try:
        safety_door = int (settings['safety']['door']) == 1
        milling_offset = float(settings['milling']['layer-offset'])
    except KeyError:
        safety_door = False
        milling_offset = 0
    
    
    if(safety_door):
        su.doMacro('M741', 'TRIGGERED', -1, 'Front panel door control', verbose=False)
    
    su.doMacro('M744', 'TRIGGERED', -1, 'Milling bed side up', warning=True, verbose=False)
    #su.trace("Milling sacrificial layer thickness: "+str(milling_offset))
    su.doMacro('M402', 'ok', 1, 'Retracting Probe (safety)', verbose=False)
    su.doMacro('G90', 'ok', -1, 'Setting absolute mode', verbose=False)
    
    if(skip_homing == False):
        su.doMacro('G27', 'ok', -1, 'Homing Z - Fast', verbose=False)
        su.doMacro('G92 Z241.2', 'ok', -1, 'Setting correct Z', verbose=False)
        su.doMacro('M402', 'ok', 1, 'Retracting Probe (safety)', verbose=False)
    
    su.doMacro("G0 Z"+str(probe_height)+" F15000", 'ok', -1, 'Moving to start Z height', verbose=False)#mandatory!
    
    for (p,point) in enumerate(probed_points):
    
        #real carriage position
        x=point[0]-17
        y=point[1]-61.5
        
        su.doMacro("G0 X"+str(x)+" Y"+str(y)+" Z"+str(probe_height)+" F15000", 'ok', -1, 'Moving to Pos', verbose=False)
        msg="Measuring point " +str(p+1)+ " of "+ str(len(probed_points)) + " (" +str(num_probes) + " times)"
        su.trace(msg)
        #Touches 4 times the bed in the same position
        probes=num_probes #temp
        for i in range(0,num_probes):
            su.sendGCode('M401')
            z = su.g30()
            probed_points[p,2]+=float(z) # store Z
            #G0 Z40 F5000
            #macro("G0 Z40 F5000","ok",10,"Rising Bed",0.1, warning=True, verbose=False)
            su.doMacro("G0 Z"+str(probe_height)+" F15000", 'ok', -1, 'Rising Bed', verbose=False)
            
        #mean of the num of measurements
        probed_points[p,0]=probed_points[p,0]
        probed_points[p,1]=probed_points[p,1]
        probed_points[p,2]=probed_points[p,2]/probes; #mean of the Z value on point "p"
        
        #trace("Mean ="+ str(probed_points[p,2]))
        
        #msg="Point " +str(p+1)+ "/"+ str(len(probed_points)) + " , Z= " +str(probed_points[p,2])
        #trace(msg)
        su.sendGCode('M402')
        #su.doMacro("M402", 'ok', -1, 'Raising Probe', verbose=False)
        #macro("M402","ok",2,"Raising Probe",0.1, warning=True, verbose=False)    
        
        #G0 Z40 F5000
        #macro("G0 Z40 F5000","ok",2,"Rising Bed",0.1, warning=True, verbose=False)
        su.doMacro("G0 Z"+str(probe_height)+" F15000", 'ok', -1, 'Rising Bed', verbose=False)
        #macro("G0 Z"+str(probe_height)+" F5000","ok",2,"Rising Bed",0.5, warning=True, verbose=False)
        
    su.doMacro("G0 X5 Y5 Z"+str(probe_height)+" F15000", 'ok', -1, 'Idle Position', verbose=False)
    su.doMacro("M18", 'ok', -1, 'Motors off', verbose=False)
    su.trace("Completed")
    
    probed_points=np.add(probed_points,screw_offset)
    
    Fit = str(fitplane(probed_points))
    
    Fit = fitplane(probed_points)
    coeff = Fit[0:3]
    d = Fit[3]
    
    eeprom = su.eeprom();
    z_probe = float(eeprom['probe_length'])
    
    d_ovr=d
    
    cal_point=np.array([[0-8.726,0-10.579,0],[0-8.726,257.5-10.579,0],[223-8.726,257.5-10.579,0],[223-8.726,0-10.579,0]])
    
    idx=0
    for (p,point) in enumerate(cal_point):
        #cal_point[p][0][1]  => point[1]  #Y coordinate of point 0
    
        z=(-coeff[0]*point[0] - coeff[1]*point[1] +d)/coeff[2]
            
        #difference from titled plane to straight plane
        #distance=P2-P1
        diff=abs(-d_ovr)-abs(z)
        
        #msg= "d :"+str(d)+", P :"+str(p)+" , Z:" +str(z) +" Diff: "+str(diff) +" d_ovr: "+str(d_ovr) 
        #msg= str(d_ovr)+ "-"+str(abs(z))+" = " + str(diff)
        #trace(msg)
        
        #number of screw turns, pitch 0.5mm
        turns=round(diff/0.5, 2) #
        degrees= turns*360
        degrees=int(5 * round(float(degrees)/5))  #lets round to upper 5
        
        screw_turns[idx]=turns
        screw_height[idx]=diff
        screw_degrees[idx]=degrees
        
        idx+=1
        print "Calculated=" + str(z) + " Difference " + str(diff) +" Turns: "+ str(turns) + " deg: " + str(degrees)
    
    #save everything
    bed_calibration = {
     "t1": screw_turns[0],
     "t2": screw_turns[1],
     "t3": screw_turns[2],
     "t4": screw_turns[3],
     "s1": screw_height[0],
     "s2": screw_height[1],
     "s3": screw_height[2],
     "s4": screw_height[3],
     "d1": screw_degrees[0],
     "d2": screw_degrees[1],
     "d3": screw_degrees[2],
     "d4": screw_degrees[3]
    }
    
    result = {
     "bed_calibration" : bed_calibration
    }
    
    with open(logfile, 'w') as outfile:
        json.dump(result, outfile)
    outfile.close()
    
    if os.path.isfile(config.get('task', 'lock_file')):
        os.remove(config.get('task', 'lock_file'))
Beispiel #5
0
import serial, os
import argparse
import json
from serial_utils import SerialUtils

parser = argparse.ArgumentParser()

parser.add_argument("o", help="output type",  default='json', nargs='?',)
args = parser.parse_args()

output = args.o
su = SerialUtils()
eeprom = su.eeprom()

if output == 'json':
    print json.dumps(eeprom)
Beispiel #6
0
class BedLeveling():

    PROBE_POINTS = [
        [5 + 17, 5 + 61.5, 0.0],  #point 1
        [5 + 17, 158.5 + 61.5, 0.0],  #point 2
        [178 + 17, 158.5 + 61.5, 0.0],  #point 3
        [178 + 17, 5 + 61.5, 0.0],  #point 4
    ]
    SCREW_OFFSET = [8.726, 10.579, 0]
    SCREW_PITCH = 0.5  # mm/deg
    CARRIAGE_POSITION = [17, 61.5]
    XY_FEEDRATE = 10000
    Z_FEEDRATE = 10000
    PROBE_OFFSET_SECURITY = 15
    MAX_NUM_PROBES = 4

    def __init__(self,
                 trace_file,
                 response_file,
                 settings,
                 num_probes=1,
                 skip_homing=False):
        print "init"
        self.serial = SerialUtils(debug=True)
        self.trace_file = trace_file
        self.response_file = response_file
        self.num_probes = num_probes
        self.skip_homing = skip_homing
        self.hardware_settings = settings
        self.probe_height = 50
        self.milling_offset = 0
        self.safety_door = False
        self.eeprom = None
        self.screw_turns = ["" for x in range(4)]
        self.screw_height = ["" for x in range(4)]
        self.screw_degrees = ["" for x in range(4)]
        if (self.num_probes > self.MAX_NUM_PROBES):
            self.num_probes = self.MAX_NUM_PROBES

    def prepareTask(self):
        self.eeprom = self.serial.eeprom()
        self.probe_height = (abs(float(self.eeprom['probe_length'])) +
                             1) + self.PROBE_OFFSET_SECURITY
        self.safety_door = int(self.hardware_settings['safety']['door']) == 1
        #print self.probe_height
        #print self.safety_door
        self.serial.doMacro('G21',
                            'ok',
                            1,
                            "Set units millimeters",
                            verbose=False)
        if (self.safety_door):
            self.serial.doMacro('M741',
                                'TRIGGERED',
                                -1,
                                'Front panel door control',
                                verbose=False)
        self.serial.doMacro('M744',
                            'TRIGGERED',
                            1,
                            'Milling bed side up',
                            verbose=False,
                            errorMessage="Please flip platform")
        self.serial.doMacro('M402',
                            'ok',
                            -1,
                            'Retracting Probe (safety)',
                            verbose=False)
        self.serial.doMacro('G90',
                            'ok',
                            -1,
                            'Setting absolute mode',
                            verbose=False)
        if (self.skip_homing == False):
            self.serial.doMacro('G27',
                                'ok',
                                -1,
                                'Homing Z - Fast',
                                verbose=False)
            self.serial.doMacro('G92 Z241.2',
                                'ok',
                                -1,
                                'Setting correct Z',
                                verbose=False)
            #self.serial.doMacro('M402', 'ok', 1, 'Retracting Probe (safety)', verbose=False)
        self.serial.doMacro("G0 Z" + str(self.probe_height) + " F15000",
                            'ok',
                            -1,
                            'Moving to start Z height Z{0}'.format(
                                self.probe_height),
                            verbose=False)  #mandatory!
        if os.path.isfile(config.get('task', 'lock_file')) == False:
            open(config.get('task', 'lock_file'), 'w').close()

    def fitplane(self, XYZ):
        [npts, rows] = XYZ.shape

        if not rows == 3:
            #print XYZ.shape
            raise ('data is not 3D')
            return None

        if npts < 3:
            raise ('too few points to fit plane')
            return None

        # Set up constraint equations of the form  AB = 0,

        # where B is a column vector of the plane coefficients
        # in the form   b(1)*X + b(2)*Y +b(3)*Z + b(4) = 0.
        t = XYZ
        p = (np.ones((npts, 1)))
        A = np.hstack([t, p])

        if npts == 3:  # Pad A with zeros
            A = [A, np.zeros(1, 4)]

        [u, d, v] = np.linalg.svd(A)  # Singular value decomposition.
        #print v[3,:]
        B = v[3, :]
        # Solution is last column of v.
        nn = np.linalg.norm(B[0:3])
        B = B / nn
        #plane = Plane(Point(B[0],B[1],B[2]),D=B[3])
        #return plane
        return B[:]

    def probe(self, x, y, open):
        print "probe point %s %s " % (x, y)
        # move to position
        self.serial.doMacro('G90',
                            'ok',
                            -1,
                            'Setting absolute mode',
                            verbose=False)
        self.serial.doMacro('G0 X{0} Y{1} F{2}'.format(x, y, self.XY_FEEDRATE),
                            'ok',
                            -1,
                            'Moving to Pos',
                            verbose=False)
        # open probe
        if (open == True):
            self.serial.doMacro('M401', 'ok', -1, 'Open probe', verbose=False)
        # rise bed
        z_touched = self.serial.g30()
        #self.serial.sendGCode('G0 Z{0} F{1}'.format(self.probe_height, self.Z_FEEDRATE))
        #self.serial.doMacro('G0 Z{0} F{1}'.format(self.probe_height, self.Z_FEEDRATE), 'ok', -1, 'Safety Z height', verbose=True)
        #self.serial.doMacro('M402', 'ok', -1, 'Retracting Probe (safety)', verbose=False)
        return z_touched

    def idlePosition(self, x=5, y=5):
        # move to idle position
        self.serial.doMacro('G90',
                            'ok',
                            -1,
                            'Setting absolute mode',
                            verbose=False)
        self.serial.doMacro('G0 X{0} Y{1} Z{2} F{3}'.format(
            x, y, self.probe_height, self.XY_FEEDRATE),
                            'ok',
                            -1,
                            'Idle Position',
                            verbose=False)

    def outuput(self):
        output = {
            "bed_calibration": {
                "t1": self.screw_turns[0],
                "t2": self.screw_turns[1],
                "t3": self.screw_turns[2],
                "t4": self.screw_turns[3],
                "s1": self.screw_height[0],
                "s2": self.screw_height[1],
                "s3": self.screw_height[2],
                "s4": self.screw_height[3],
                "d1": self.screw_degrees[0],
                "d2": self.screw_degrees[1],
                "d3": self.screw_degrees[2],
                "d4": self.screw_degrees[3]
            }
        }
        print output
        with open(self.response_file, 'w') as response:
            json.dump(output, response)
        response.close()

    def run(self):
        self.serial.trace('Bed leveling procedure')
        self.prepareTask()
        probed_points = np.array(self.PROBE_POINTS)
        openProbe = True
        for (p, point) in enumerate(self.PROBE_POINTS):
            self.serial.trace('Measuring point {0} of {1} ({2} times)'.format(
                p + 1, len(probed_points), self.num_probes))
            # Real carriage position
            x = point[0] - self.CARRIAGE_POSITION[0]
            y = point[1] - self.CARRIAGE_POSITION[1]
            #self.serial.doMacro('M401', 'ok', -1, 'Open Probe (safety)', verbose=False)
            for i in range(0, self.num_probes):
                z = self.probe(x, y, openProbe)
                if (openProbe == True):
                    openProbe = False
                probed_points[p, 2] += float(z)  # store Z

            probed_points[p, 0] = probed_points[p, 0]
            probed_points[p, 1] = probed_points[p, 1]
            probed_points[p, 2] = probed_points[p, 2] / self.num_probes
            #self.serial.doMacro('M402', 'ok', -1, 'Retracting Probe (safety)', verbose=False)
        #move to idle position
        self.serial.doMacro('M402',
                            'ok',
                            -1,
                            'Retracting Probe (safety)',
                            verbose=False)
        self.idlePosition()
        self.serial.doMacro("M18", 'ok', -1, 'Motors off', verbose=False)
        self.serial.trace('Processing points..')

        probed_points = np.add(probed_points, self.SCREW_OFFSET)
        Fit = self.fitplane(probed_points)
        coeff = Fit[0:3]
        d = Fit[3]

        d_ovr = d
        cal_point = np.array([[0.0 - 8.726, 0.0 - 10.579, 0.0],
                              [0.0 - 8.726, 257.5 - 10.579, 0.0],
                              [223 - 8.726, 257.5 - 10.579, 0.0],
                              [223 - 8.726, 0.0 - 10.579, 0.0]])

        idx = 0
        for (p, point) in enumerate(cal_point):
            z = (-coeff[0] * point[0] - coeff[1] * point[1] + d) / coeff[2]
            #difference from titled plane to straight plane
            #distance=P2-P1
            diff = abs(-d_ovr) - abs(z)
            #number of screw turns, pitch 0.5mm
            turns = round(diff / 0.5, 2)  #
            degrees = turns * 360
            degrees = int(5 *
                          round(float(degrees) / 5))  #lets round to upper 5

            self.screw_turns[idx] = turns
            self.screw_height[idx] = diff
            self.screw_degrees[idx] = degrees
            idx += 1
            print "Calculated=" + str(z) + " Difference " + str(
                diff) + " Turns: " + str(turns) + " deg: " + str(degrees)
        self.outuput()
Beispiel #7
0
class BedLeveling():
    
    PROBE_POINTS = [
                        [5+17,      5+61.5,     0.0], #point 1
                        [5+17,      158.5+61.5, 0.0], #point 2
                        [178+17,    158.5+61.5, 0.0], #point 3
                        [178+17,    5+61.5,     0.0], #point 4
                   ]
    SCREW_OFFSET = [8.726, 10.579, 0]
    SCREW_PITCH  = 0.5 # mm/deg
    CARRIAGE_POSITION   = [17, 61.5]
    XY_FEEDRATE = 10000
    Z_FEEDRATE  = 10000
    PROBE_OFFSET_SECURITY = 15
    MAX_NUM_PROBES = 4
    
    def __init__(self, trace_file, response_file, settings, num_probes = 1, skip_homing = False):
        print "init"
        self.serial = SerialUtils(debug=True)
        self.trace_file            = trace_file
        self.response_file         = response_file
        self.num_probes            = num_probes
        self.skip_homing           = skip_homing
        self.hardware_settings     = settings
        self.probe_height          = 50
        self.milling_offset        = 0
        self.safety_door           = False
        self.eeprom                = None
        self.screw_turns           = ["" for x in range(4)]
        self.screw_height          = ["" for x in range(4)]
        self.screw_degrees         = ["" for x in range(4)]
        if(self.num_probes > self.MAX_NUM_PROBES):
            self.num_probes = self.MAX_NUM_PROBES
        
    def prepareTask(self):
        self.eeprom = self.serial.eeprom()
        self.probe_height = (abs(float(self.eeprom['probe_length'])) + 1 ) + self.PROBE_OFFSET_SECURITY
        self.safety_door = int (self.hardware_settings['safety']['door']) == 1
        #print self.probe_height
        #print self.safety_door
        self.serial.doMacro('G21', 'ok', 1, "Set units millimeters", verbose=False)
        if(self.safety_door):
            self.serial.doMacro('M741', 'TRIGGERED', -1, 'Front panel door control', verbose=False)
        self.serial.doMacro('M744', 'TRIGGERED', 1, 'Milling bed side up', verbose=False, errorMessage="Please flip platform")
        self.serial.doMacro('M402', 'ok', -1, 'Retracting Probe (safety)', verbose=False)
        self.serial.doMacro('G90', 'ok', -1, 'Setting absolute mode', verbose=False)
        if(self.skip_homing == False):
            self.serial.doMacro('G27', 'ok', -1, 'Homing Z - Fast', verbose=False)
            self.serial.doMacro('G92 Z241.2', 'ok', -1, 'Setting correct Z', verbose=False)
            #self.serial.doMacro('M402', 'ok', 1, 'Retracting Probe (safety)', verbose=False)
        self.serial.doMacro("G0 Z"+str(self.probe_height)+" F15000", 'ok', -1, 'Moving to start Z height Z{0}'.format(self.probe_height), verbose=False)#mandatory!
        if os.path.isfile(config.get('task', 'lock_file')) == False:
            open(config.get('task', 'lock_file'), 'w').close()
        
    def fitplane(self, XYZ):
        [npts,rows] = XYZ.shape

        if not rows == 3:
            #print XYZ.shape
            raise ('data is not 3D')
            return None

        if npts < 3:
            raise ('too few points to fit plane')
            return None

        # Set up constraint equations of the form  AB = 0,
        
        # where B is a column vector of the plane coefficients
        # in the form   b(1)*X + b(2)*Y +b(3)*Z + b(4) = 0.
        t = XYZ
        p = (np.ones((npts,1)))
        A = np.hstack([t,p])

        if npts == 3:                       # Pad A with zeros
            A = [A, np.zeros(1,4)]

        [u, d, v] = np.linalg.svd(A)        # Singular value decomposition.
        #print v[3,:]
        B = v[3,:];                         # Solution is last column of v.
        nn = np.linalg.norm(B[0:3])
        B = B / nn
        #plane = Plane(Point(B[0],B[1],B[2]),D=B[3])
        #return plane
        return B[:]
            
    def probe(self, x, y, open):
        print "probe point %s %s " % (x, y)
        # move to position
        self.serial.doMacro('G90', 'ok', -1, 'Setting absolute mode', verbose=False)
        self.serial.doMacro('G0 X{0} Y{1} F{2}'.format(x, y, self.XY_FEEDRATE), 'ok', -1, 'Moving to Pos', verbose=False)
        # open probe
        if(open==True):
            self.serial.doMacro('M401', 'ok', -1, 'Open probe', verbose=False)
        # rise bed
        z_touched = self.serial.g30()
        #self.serial.sendGCode('G0 Z{0} F{1}'.format(self.probe_height, self.Z_FEEDRATE))
        #self.serial.doMacro('G0 Z{0} F{1}'.format(self.probe_height, self.Z_FEEDRATE), 'ok', -1, 'Safety Z height', verbose=True)
        #self.serial.doMacro('M402', 'ok', -1, 'Retracting Probe (safety)', verbose=False)
        return z_touched
      
    def idlePosition(self, x=5, y=5):
        # move to idle position
        self.serial.doMacro('G90', 'ok', -1, 'Setting absolute mode', verbose=False)
        self.serial.doMacro('G0 X{0} Y{1} Z{2} F{3}'.format(x, y, self.probe_height, self.XY_FEEDRATE), 'ok', -1, 'Idle Position', verbose=False)
        
    def outuput(self):
        output = {
            "bed_calibration" : {
                 "t1": self.screw_turns[0],
                 "t2": self.screw_turns[1],
                 "t3": self.screw_turns[2],
                 "t4": self.screw_turns[3],
                 "s1": self.screw_height[0],
                 "s2": self.screw_height[1],
                 "s3": self.screw_height[2],
                 "s4": self.screw_height[3],
                 "d1": self.screw_degrees[0],
                 "d2": self.screw_degrees[1],
                 "d3": self.screw_degrees[2],
                 "d4": self.screw_degrees[3]
            }
        }
        print output
        with open(self.response_file, 'w') as response:
            json.dump(output, response)
        response.close()
        
    def run(self):
        self.serial.trace('Bed leveling procedure')
        self.prepareTask()
        probed_points = np.array(self.PROBE_POINTS)
        openProbe = True
        for (p,point) in enumerate(self.PROBE_POINTS):    
            self.serial.trace('Measuring point {0} of {1} ({2} times)'.format(p+1, len(probed_points), self.num_probes))
            # Real carriage position
            x = point[0] - self.CARRIAGE_POSITION[0]
            y = point[1] - self.CARRIAGE_POSITION[1]
            #self.serial.doMacro('M401', 'ok', -1, 'Open Probe (safety)', verbose=False)
            for i in range(0,self.num_probes):
                z = self.probe(x, y, openProbe)
                if(openProbe == True):
                    openProbe = False
                probed_points[p,2]+=float(z) # store Z
            
            probed_points[p,0]=probed_points[p,0]
            probed_points[p,1]=probed_points[p,1]
            probed_points[p,2]=probed_points[p,2]/self.num_probes;
            #self.serial.doMacro('M402', 'ok', -1, 'Retracting Probe (safety)', verbose=False)
        #move to idle position
        self.serial.doMacro('M402', 'ok', -1, 'Retracting Probe (safety)', verbose=False)
        self.idlePosition()
        self.serial.doMacro("M18", 'ok', -1, 'Motors off', verbose=False)
        self.serial.trace('Processing points..')
        
        probed_points=np.add(probed_points,self.SCREW_OFFSET)
        Fit = self.fitplane(probed_points)
        coeff = Fit[0:3]
        d = Fit[3]
        
        d_ovr=d
        cal_point = np.array([
            [0.0-8.726, 0.0-10.579,     0.0],
            [0.0-8.726, 257.5-10.579,   0.0],
            [223-8.726, 257.5-10.579,   0.0],
            [223-8.726, 0.0-10.579,     0.0]
        ])
        
        idx=0
        for (p,point) in enumerate(cal_point):
            z=(-coeff[0]*point[0] - coeff[1]*point[1] +d)/coeff[2]
            #difference from titled plane to straight plane
            #distance=P2-P1
            diff=abs(-d_ovr)-abs(z)
            #number of screw turns, pitch 0.5mm
            turns=round(diff/0.5, 2) #
            degrees= turns*360
            degrees=int(5 * round(float(degrees)/5))  #lets round to upper 5
            
            self.screw_turns[idx]=turns
            self.screw_height[idx]=diff
            self.screw_degrees[idx]=degrees
            idx+=1
            print "Calculated=" + str(z) + " Difference " + str(diff) +" Turns: "+ str(turns) + " deg: " + str(degrees)
        self.outuput()