Exemplo n.º 1
0
class Interface(object):
    def __init__(self):
        self.i2cbus = SMBus(1)
        self.oled = ssd1306(self.i2cbus)
        self.font = ImageFont.truetype('/home/pi/Code/FreeSans.ttf', 10)
        self.font2 = ImageFont.truetype('/home/pi/Code/FreeSans.ttf', 11)
        self.font3 = ImageFont.truetype('/home/pi/Code/FreeSans.ttf', 18)
        self.font4 = ImageFont.truetype('/home/pi/Code/FreeSans.ttf', 36)
        self.disp = self.oled.canvas
        self.padding = 1
        self.top = self.padding
        self.bottom = self.oled.height - self.padding
        self.left = self.padding
        self.right = self.oled.width - self.padding
        self.line1 = 17
        self.line2 = 29
        self.line3 = 41
        self.line4 = 53
        self.lines = [self.line1, self.line2, self.line3, self.line4]
        self.column1 = self.left + 2
        self.column2 = self.left + 64
        self.column3 = self.right - 44
        self.selector = 0
        self.interfaces = []
        self.currentMenu = None
        self.b = None
        self.busy = False
        self.exit = False
        self.lock = Lock()
        self.stepsPerDeg = 1
        self.stepsPerUnit = 1
        self.motorStepTime = 0.01
        self.sequenceStartTime = 0
        self.timeStamp = 0
        self.lastRun = 0
        self.xEvent = threading.Event()
        self.rEvent = threading.Event()
        return

    #Define pin inputs and outputs
    def setControls(self, enter, go, LED, up, down):
        self.enterButt = enter
        self.goButt = go
        self.buttLED = LED
        #Button Indicator Settings
        self.buttLEDfreq = 1
        self.buttDuty = 25

        #Pin assignments
        GPIO.setup(self.buttLED, GPIO.OUT)
        GPIO.setup(self.goButt, GPIO.IN, pull_up_down=GPIO.PUD_UP)
        GPIO.setup(self.enterButt, GPIO.IN, pull_up_down=GPIO.PUD_UP)

        GPIO.add_event_detect(self.goButt,
                              GPIO.FALLING,
                              callback=self.goSTART,
                              bouncetime=500)
        GPIO.add_event_detect(self.enterButt,
                              GPIO.FALLING,
                              callback=self.selectButt,
                              bouncetime=500)
        self.encoder = RotaryEncoder(up, down, self.decode)
        self.buttON(True)
        time.sleep(0.125)
        self.buttON(False)
        time.sleep(0.125)
        self.buttON(True)
        time.sleep(0.125)
        self.buttON(False)
        return

    #Calibrate the Motors
    def homeMotors(self):
        self.fan(True)
        self.xMotor.calibrate()
        #self.rMotor.calibrate()
        self.fan(True)
        return

    #Define the fan pins
    def setFan(self, pin):
        self.blower = Fan(pin, 100, 0.25, 120)
        return

    #Define Camera Trigger Pins
    def setCamTrigger(self, half, full):
        self.halfPress = half
        self.fullPress = full
        GPIO.setup(self.halfPress, GPIO.OUT)
        GPIO.setup(self.fullPress, GPIO.OUT)
        GPIO.output(self.halfPress, True)
        GPIO.output(self.fullPress, True)
        return

    #Turn the button LED on or off (Button)
    def buttON(self, val):
        GPIO.output(self.buttLED, val)
        return

    #Create menu items
    def populate(self):
        self.main = Menu('Main Menu')

        self.ready = Go('Capture')
        self.preview = Go('Preview')
        self.movement = Menu('Movement')
        self.displacement = Menu('Displacement')
        self.time = Menu('Time')
        self.drive = Menu('Drive')

        self.translation = Menu('Translation')
        self.rotation = Menu('Rotation')
        self.initPos = Menu('Initial Positions')
        self.travDir = Menu('Travel Directions')

        self.camera = Menu('Camera')

        self.calibrate = Menu('Calibrate')
        self.manualControl = Menu('Manual Control')

        self.freeMove = Action('User Control X')
        self.freeRotate = Action('User Control R')

        self.totalDisp = Option('Total Displace')
        self.incDisp = Option('Increment')

        self.totalRot = Option('Total Rotation')
        self.incRot = Option('Increment')

        self.initX = Option('Initial X-Position')
        self.initR = Option('Initial R-Position')

        self.travX = Option('Initial X-Direction')
        self.travR = Option('Initial R-Direction')

        self.tVal = Camera('Time Value')  # Shutter speed of camera
        self.nomages = Option('Images')  # Number of images to capture

        self.inter = Option('Interval')  # Interval between shots in seconds
        self.totalTime = Option(
            'Total Time')  # Total time of sequence in minutes

        self.calTrans = Action('Translation')
        self.calRot = Action('Rotation')

        self.hold = Option('Holding Power')

        self.main.setItems(self.ready, self.movement, self.time, self.drive)
        self.main.pageInfo = 'Today'

        self.movement.setItems(self.displacement, self.initPos, self.travDir,
                               self.main)
        self.displacement.setItems(self.translation, self.rotation,
                                   self.movement)
        self.drive.setItems(self.calibrate, self.manualControl, self.hold,
                            self.main)
        self.time.setItems(self.totalTime, self.inter, self.camera, self.main)
        self.manualControl.setItems(self.freeMove, self.freeRotate, self.drive)
        self.ready.setItems(self.preview, self.main)
        self.ready.setHardware(self.xMotor, self.rMotor)
        self.ready.setSubtitle('Shots')
        self.preview.setItems(self.ready, self.main)
        self.preview.setHardware(self.xMotor, self.rMotor)
        self.preview.setSubtitle('Preview')

        self.translation.setItems(self.totalDisp, self.incDisp, self.movement)
        self.initPos.setItems(self.initX, self.initR, self.movement)
        self.travDir.setItems(self.travX, self.travR, self.movement)
        self.rotation.setItems(self.totalRot, self.incRot, self.movement)
        self.camera.setItems(self.tVal, self.nomages, self.time)

        self.calibrate.setItems(self.calTrans, self.calRot, self.drive)
        self.freeMove.setItems(self.manualControl)
        self.freeMove.setHardware(self.xMotor)
        self.freeRotate.setItems(self.manualControl)
        self.freeRotate.setHardware(self.rMotor)
        self.hold.setItems(self.drive)
        self.hold.hasRange(True)
        self.hold.setRange(0, 2)
        self.hold.hasAlternate(True)
        self.hold.setAlternate('OFF', 'LOW', 'HIGH')
        self.hold.setVal(1)

        self.totalDisp.setItems(self.translation)
        self.totalDisp.canZero(True)
        self.totalDisp.setVal(10000)
        self.totalDisp.setMultiplier(100)
        self.incDisp.setItems(self.translation)
        self.incDisp.canZero(True)
        self.incDisp.setVal(1)

        self.totalRot.setItems(self.rotation)
        self.totalRot.canZero(True)
        self.totalRot.setVal(90)
        self.incRot.setItems(self.rotation)
        self.incRot.canZero(True)
        self.incRot.setVal(1)

        self.totalTime.setItems(self.time)
        self.totalTime.setVal(45)
        self.inter.setItems(self.time)
        self.inter.setVal(2)

        self.tVal.setItems(self.camera)
        self.tVal.setVal(0)
        self.nomages.setItems(self.camera)
        self.nomages.setVal(10)

        self.calTrans.setItems(self.calibrate)
        self.calTrans.setHardware(self.xMotor)
        self.calRot.setItems(self.calibrate)
        self.calRot.setHardware(self.rMotor)

        self.travX.setItems(self.travDir)
        self.travX.hasRange(True)
        self.travX.setRange(0, 1)
        self.travX.hasAlternate(True)
        self.travX.setAlternate('FWD', 'REV')
        self.travR.setItems(self.travDir)
        self.travR.hasRange(True)
        self.travR.setRange(0, 1)
        self.travR.hasAlternate(True)
        self.travR.setAlternate('FWD', 'REV')

        self.initX.setItems(self.initPos)
        self.initX.hasRange(True)
        self.initX.setRange(self.xMotor.Limits[0], self.xMotor.Limits[1])
        self.initX.setMultiplier(100)
        self.initR.setItems(self.initPos)
        self.initR.hasRange(True)
        self.initR.setRange(self.rMotor.Limits[0], self.rMotor.Limits[1])
        self.initR.setMultiplier(100)

        self.currentMenu = self.main
        return

    #Turn the fan on or off (Boolean)
    def fan(self, isOn):
        if self.hold.getVal() == 2:
            self.blower.on()
        elif isOn:
            self.blower.on()
        elif ~isOn:
            self.blower.off()
        return

    #Define pins and create translation motor object
    def setTransMotor(self, pinA1, pinA2, pinB1, pinB2, pinENa, pinENb,
                      endButt, steps):
        self.xMotor = Stepper(pinA1, pinA2, pinB1, pinB2, pinENa, pinENb,
                              endButt)
        self.xMotor.invert()
        self.xMotor.pwmHoldSet(1)
        self.stepsPerUnit = steps
        return

    #Define pins and create rotation motor object
    def setRotMotor(self, pinA1, pinA2, pinB1, pinB2, pinENa, pinENb, endButt,
                    steps):
        self.rMotor = Stepper(pinA1, pinA2, pinB1, pinB2, pinENa, pinENb,
                              endButt)
        self.stepsPerDeg = steps
        return

    #Set hard limits of displacement motor
    def setTransLimits(self, min, max):
        self.xMotor.setLimits(min, max)
        return

    #Set hard limits of rotational motor
    def setRotLimits(self, min, max):
        self.rMotor.setLimits(min, max)
        return

    #Update values of current menu
    def updateInfo(self, val):
        if type(self.currentMenu) is Option or type(
                self.currentMenu) is Camera:
            self.currentMenu.setVal(val)
            self.disp.text((self.column3, self.top),
                           str(self.currentMenu.toString()[2]),
                           font=self.font,
                           fill=0)
            self.disp.text((self.column3, self.top),
                           str(self.currentMenu.toString()[1]),
                           font=self.font,
                           fill=1)
        if type(self.currentMenu) is Action or type(self.currentMenu) is Go:
            self.currentMenu.setVal(val)
        return

    #Draw objects of the current menu
    def draw(self):
        self.disp.text((1, self.top),
                       self.currentMenu.title,
                       font=self.font,
                       fill=1)
        #Populate the interface list with the current menu's items
        try:
            self.interfaces = self.currentMenu.getItems()
        except:
            print('Menu population error')

        if type(self.currentMenu) is Menu:
            self.updateInfo(self.toString())
            for item in self.interfaces:
                if item != None:
                    self.disp.text(
                        (self.column1,
                         self.lines[self.interfaces.index(item)]),
                        self.interfaces[self.interfaces.index(item)].title,
                        font=self.font2,
                        fill=1)
                    if self.interfaces[self.interfaces.index(
                            item)].getVal() != None:
                        self.disp.text(
                            (self.column3,
                             self.lines[self.interfaces.index(item)]),
                            self.interfaces[self.interfaces.index(
                                item)].toString()[2],
                            font=self.font2,
                            fill=0)
                        self.disp.text(
                            (self.column3,
                             self.lines[self.interfaces.index(item)]),
                            self.interfaces[self.interfaces.index(
                                item)].toString()[1],
                            font=self.font2,
                            fill=1)
        #Display scheme for camera shutter speed selection menu
        if type(self.currentMenu) is Option or type(
                self.currentMenu) is Camera:
            #Erase the previous display and write the new display
            self.disp.text((self.column1, self.lines[1]),
                           self.currentMenu.toString()[2],
                           font=self.font4,
                           fill=0)
            self.disp.text((self.column1, self.lines[1]),
                           self.currentMenu.toString()[1],
                           font=self.font4,
                           fill=1)
        #Display scheme for Action menus
        if type(self.currentMenu) is Action:
            #Display info about the current menu functionality
            self.disp.text((self.column1, self.lines[0]),
                           self.currentMenu.getSubtitle(),
                           font=self.font2,
                           fill=1)
            #Erase the previous display and write the new display
            self.disp.text((self.column1, self.lines[2]),
                           self.currentMenu.toString()[2],
                           font=self.font3,
                           fill=0)
            self.disp.text((self.column1, self.lines[2]),
                           self.currentMenu.toString()[1],
                           font=self.font3,
                           fill=1)
            #Display the 'Position' heading
            self.disp.text((self.column2, self.lines[0]),
                           'Position',
                           font=self.font2,
                           fill=1)
            #Erase the previous display and write the new display
            self.disp.text((self.column2, self.lines[2]),
                           str(self.currentMenu.getPosition()[1]),
                           font=self.font3,
                           fill=0)
            self.disp.text((self.column2, self.lines[2]),
                           str(self.currentMenu.getPosition()[0]),
                           font=self.font3,
                           fill=1)
        #Display scheme for Capture menu
        if type(self.currentMenu) is Go:
            #self.updateInfo(self.currentMenu.getVal())
            self.currentMenu.updatePosition()
            #Display 'Shots Remaining' tag
            self.disp.text((self.column1, self.lines[0]),
                           self.currentMenu.getSubtitle(),
                           font=self.font2,
                           fill=1)
            #Display 'Time Remaining'
            self.disp.text((self.column2, self.top),
                           self.currentMenu.getTimeString()[1],
                           font=self.font2,
                           fill=0)
            self.disp.text((self.column2, self.top),
                           self.currentMenu.getTimeString()[0],
                           font=self.font2,
                           fill=1)
            #Erase the previous display and write the new display (Shots Remaining)
            self.disp.text((self.column1, self.lines[2]),
                           self.currentMenu.toString()[2],
                           font=self.font3,
                           fill=0)
            self.disp.text((self.column1, self.lines[2]),
                           self.currentMenu.toString()[1],
                           font=self.font3,
                           fill=1)
            #Display the 'Position' heading
            self.disp.text((self.column2, self.lines[0]),
                           'Position',
                           font=self.font2,
                           fill=1)
            #Erase the previous display and write the new display (xMotor)
            self.disp.text((self.column2, self.lines[1]),
                           'X: ' + str(self.currentMenu.getPosition(0)[1]),
                           font=self.font2,
                           fill=0)
            self.disp.text((self.column2, self.lines[1]),
                           'X: ' + str(self.currentMenu.getPosition(0)[0]),
                           font=self.font2,
                           fill=1)
            #Erase the previous display and write the new display (rMotor)
            self.disp.text((self.column2, self.lines[2]),
                           'R: ' + str(self.currentMenu.getPosition(1)[1]),
                           font=self.font2,
                           fill=0)
            self.disp.text((self.column2, self.lines[2]),
                           'R: ' + str(self.currentMenu.getPosition(1)[0]),
                           font=self.font2,
                           fill=1)
        return

    #Hightlight the menu option indicated by the selector
    def highlight(self):
        if type(self.currentMenu) is Menu:
            try:
                textDim = self.font.getsize(str(
                    self.interfaces[self.selector]))
                self.disp.rectangle(
                    (self.left, self.lines[self.selector] - 1,
                     self.left + textDim[0] + 5,
                     self.lines[self.selector] + textDim[1] + 2),
                    outline=0,
                    fill=1)
                self.disp.text((self.column1, self.lines[self.selector]),
                               self.interfaces[self.selector].toString()[0],
                               font=self.font2,
                               fill=0)
                if self.interfaces[self.selector].getVal() != None:
                    self.disp.text(
                        (self.column3, self.lines[self.selector]),
                        self.interfaces[self.selector].toString()[1],
                        font=self.font2,
                        fill=0)
            except:
                pass
        return

    #Redraw the current menu
    def update(self):
        self.oled.cls()
        self.draw()
        self.highlight()
        self.oled.display()
        return

    #Refresh the display without clearing previous values
    def refresh(self):
        self.draw()
        self.oled.display()
        return

    #Call the update method
    def getMenu(self):
        self.update()
        return

    #Black out the display
    def off(self):
        self.oled.cls()
        self.fan(False)
        self.buttON(False)
        self.xMotor.OFF()
        self.rMotor.OFF()
        return

    #Return object info
    def toString(self):
        return self.currentMenu.toString()

    #Set an object value
    def setVal(self, val):
        self.currentMenu.setVal(val)
        return

    #Get an object value
    def getVal(self):
        return self.currentMenu.getVal()

    #Save option values to file
    def saveDATA(self):
        data = [
            self.totalDisp.getVal(),
            self.incDisp.getVal(),
            self.totalRot.getVal(),
            self.incRot.getVal(),
            self.tVal.getVal(),
            self.nomages.getVal(),
            self.inter.getVal(),
            self.totalTime.getVal(),
            self.xMotor.getPosition(),
            self.rMotor.getPosition()
        ]
        file = open("//home//pi//Control//settings.txt", "w")

        for i in range(0, data.__len__()):
            file.write(str(data[i]))
            file.write(',')

        file.close()
        return

    #Load saved option values from file
    def loadDATA(self):
        try:
            file = open("//home//pi//Control//settings.txt", "r")
            data = file.readlines()
            file.close()

            for line in data:
                vals = line.split(',')
            print(data)

            self.totalDisp.setVal(vals[0])
            self.incDisp.setVal(vals[1])
            self.totalRot.setVal(vals[2])
            self.incRot.setVal(vals[3])
            self.tVal.setVal(vals[4])
            self.nomages.setVal(vals[5])
            self.inter.setVal(vals[6])
            self.totalTime.setVal(vals[7])
            self.xMotor.setPosition(vals[8])
            self.rMotor.setPosition(vals[9])

        except:
            print("Load failed")
        return

    #Select the menu represented by the selector value
    def selectButt(self, channel):
        self.buttON(False)
        self.fan(False)
        try:
            self.currentMenu.isRecent(True)
        except:
            pass
        self.currentMenu = self.interfaces[self.selector]
        if type(self.currentMenu) is Action or type(self.currentMenu) is Go:
            self.buttON(True)
        if type(self.currentMenu) is Action:
            self.fan(True)
        self.selector = 0
        self.calculate()
        self.update()
        self.saveDATA()
        return

    #Increase the menu selector one increment
    def nextButt(self, channel):
        if self.selector < self.interfaces.__len__() - 1:
            self.selector += 1
        else:
            self.selector = 0
        self.update()
        return

    #Decrease the menu selector one increment
    def prevButt(self, channel):
        if self.selector > 0:
            self.selector -= 1
        else:
            self.selector = self.interfaces.__len__() - 1
        self.update()
        return

    #Update all option values to agree with the most recent user setting
    def calculate(self):
        if self.incDisp.isMostRecent() or self.nomages.isMostRecent():
            self.totalDisp.setVal(self.incDisp.getVal() *
                                  self.nomages.getVal())
            self.incDisp.isRecent(False)
            self.nomages.isRecent(False)

        if self.totalDisp.isMostRecent() or self.nomages.isMostRecent():
            self.incDisp.setVal(self.totalDisp.getVal() /
                                self.nomages.getVal())
            self.totalDisp.isRecent(False)
            self.nomages.isRecent(False)

        if self.incRot.isMostRecent() or self.nomages.isMostRecent():
            self.totalRot.setVal(self.incRot.getVal() * self.nomages.getVal())
            self.incRot.isRecent(False)
            self.nomages.isRecent(False)

        if self.totalRot.isMostRecent() or self.nomages.isMostRecent():
            self.incRot.setVal(self.totalRot.getVal() / self.nomages.getVal())
            self.totalRot.isRecent(False)
            self.nomages.isRecent(False)

        if self.totalTime.isMostRecent() or self.inter.isMostRecent():
            self.nomages.setVal(
                (self.totalTime.getVal() * 60) / self.inter.getVal())
            self.totalDisp.setVal(self.nomages.getVal() *
                                  self.incDisp.getVal())
            self.totalRot.setVal(self.nomages.getVal() * self.incRot.getVal())
            self.inter.isRecent(False)
            self.totalTime.isRecent(False)

        if self.inter.isMostRecent() or self.nomages.isMostRecent():
            self.totalTime.setVal(
                (self.inter.getVal() * self.nomages.getVal()) / 60.0)
            self.totalDisp.setVal(self.nomages.getVal() *
                                  self.incDisp.getVal())
            self.totalRot.setVal(self.nomages.getVal() * self.incRot.getVal())
            self.inter.isRecent(False)
            self.nomages.isRecent(False)

        if self.totalTime.isMostRecent() or self.nomages.isMostRecent():
            self.inter.setVal(
                (self.totalTime.getVal() * 60) / self.nomages.getVal())
            self.totalTime.isRecent(False)
            self.nomages.isRecent(False)

        if (self.inter.getVal() - self.tVal.getShutter() - self.motorStepTime *
                self.stepsPerUnit * self.incDisp.getVal()) < -1:
            palm = self.inter.getVal() - self.tVal.getShutter(
            ) - self.motorStepTime * self.stepsPerUnit * self.incDisp.getVal()
            face = self.inter.getVal()
            self.inter.setVal(face - palm)
            self.inter.increment(1)
            print("Interval Updated")

        if (self.inter.getVal() - self.tVal.getShutter() - self.motorStepTime *
                self.stepsPerUnit * self.incDisp.getVal()) < 0:
            self.inter.increment(1)
            print("Interval Updated")

        self.xMotor.pwmHoldSet(self.hold.getVal())
        self.rMotor.pwmHoldSet(self.hold.getVal())
        return

    #Determine what value the encoder should increment
    def decode(self, event):
        with self.lock:
            if type(self.currentMenu) is Menu or type(self.currentMenu) is Go:
                if event == 1:
                    self.nextButt(1)
                elif event == 2:
                    self.prevButt(1)
            elif type(self.currentMenu) is Action or type(
                    self.currentMenu) is Option or type(
                        self.currentMenu) is Camera:
                if event == 1:
                    encoderQueue = 1
                    self.jog(0, encoderQueue)
                elif event == 2:
                    encoderQueue = -1
                    self.jog(0, encoderQueue)
        return

    #Increment some value with the encoder
    def jog(self, channel, val):
        if type(self.currentMenu) is Option or type(
                self.currentMenu) is Camera:
            self.currentMenu.increment(val)
            self.refresh()
        elif type(self.currentMenu) is Action:
            self.currentMenu.jog(val)
            self.refresh()
        return

    #Update the timestamp on the display
    def getTime(self):
        self.timeStamp = time.monotonic()
        hours = int((self.totalTime.getVal() -
                     (self.timeStamp - self.sequenceStartTime) / 60) / 60)
        minutes = int((self.totalTime.getVal() -
                       (self.timeStamp - self.sequenceStartTime) / 60))
        seconds = int((self.totalTime.getVal() * 60 -
                       (self.timeStamp - self.sequenceStartTime)) % 60)
        if hours < 10:
            hourString = '0' + str(hours)
        else:
            hourString = str(hours)
        if minutes < 10:
            minString = '0' + str(minutes)
        else:
            minString = str(minutes)
        if seconds < 10:
            secString = '0' + str(seconds)
        else:
            secString = str(seconds)
        timeString = hourString + ':' + minString + ':' + secString
        self.ready.setTimeString(timeString)
        self.refresh()
        return

    #Trigger what ever action is indicated by the current menu
    def goSTART(self, channel):
        if time.monotonic() - self.lastRun < 2:
            print('DoubleGo')
            return
        if ~self.busy:
            self.exit = False
            self.buttON(False)
            if self.currentMenu == self.preview:
                self.fan(True)
                self.busy = True
                self.xMotor.goTo(self.initX.getVal())
                self.rMotor.goTo(self.initR.getVal())
                self.refresh()
                sleep(1)
                if self.travX.getVal() == 0:
                    self.xThread = stepperThread(1, "Trans-Thread",
                                                 self.xEvent,
                                                 self.totalDisp.getVal(),
                                                 self.incDisp.getVal(),
                                                 self.xMotor, True)
                elif self.travX.getVal() == 1:
                    self.xThread = stepperThread(1, "Trans-Thread",
                                                 self.xEvent,
                                                 -self.totalDisp.getVal(),
                                                 self.incDisp.getVal(),
                                                 self.xMotor, True)
                if self.travR.getVal() == 0:
                    self.rThread = stepperThread(2, "Rot-Thread", self.rEvent,
                                                 self.totalRot.getVal(),
                                                 self.incRot.getVal(),
                                                 self.rMotor, True)
                elif self.travR.getVal() == 1:
                    self.rThread = stepperThread(2, "Rot-Thread", self.rEvent,
                                                 -self.totalRot.getVal(),
                                                 self.incRot.getVal(),
                                                 self.rMotor, True)
                self.xThread.start()
                self.rThread.start()
                while self.xThread.is_alive() or self.rThread.is_alive():
                    self.refresh()
                    sleep(0.01)
                self.buttON(True)
                self.fan(True)
                self.currentMenu.setVal(self.nomages.getVal())
                self.refresh()
                self.busy = False
                self.xMotor.goTo(self.initX.getVal())
                self.rMotor.goTo(self.initR.getVal())
                self.lastRun = time.monotonic()

            elif self.currentMenu == self.ready:
                self.fan(True)
                self.busy = True
                self.xMotor.goTo(self.initX.getVal())
                self.rMotor.goTo(self.initR.getVal())
                self.refresh()
                GPIO.output(self.halfPress, False)
                sleep(1)
                if self.travX.getVal() == 0:
                    self.xThread = stepperThread(1, "Trans-Thread",
                                                 self.xEvent,
                                                 self.totalDisp.getVal(),
                                                 self.incDisp.getVal(),
                                                 self.xMotor, False)
                elif self.travX.getVal() == 1:
                    self.xThread = stepperThread(1, "Trans-Thread",
                                                 self.xEvent,
                                                 -self.totalDisp.getVal(),
                                                 self.incDisp.getVal(),
                                                 self.xMotor, False)
                if self.travR.getVal() == 0:
                    self.rThread = stepperThread(2, "Rot-Thread", self.rEvent,
                                                 self.totalRot.getVal(),
                                                 self.incRot.getVal(),
                                                 self.rMotor, False)
                elif self.travR.getVal() == 1:
                    self.rThread = stepperThread(2, "Rot-Thread", self.rEvent,
                                                 -self.totalRot.getVal(),
                                                 self.incRot.getVal(),
                                                 self.rMotor, False)
                self.sequenceStartTime = time.monotonic()
                self.xThread.start()
                self.rThread.start()
                n = 0  #Shot counter for UI display
                while self.xThread.is_alive() or self.rThread.is_alive():
                    t1 = time.monotonic()
                    n += 1
                    self.captureSequence(n)
                    self.xEvent.set()
                    self.rEvent.set()
                    self.refresh()
                    self.timeStamp = time.monotonic()
                    self.monotomiTimer(t1, self.inter.getVal())
                self.buttON(True)
                self.fan(False)
                self.currentMenu.setVal(self.nomages.getVal())
                self.refresh()
                self.busy = False
                self.xMotor.goTo(self.initX.getVal())
                self.rMotor.goTo(self.initR.getVal())
                self.lastRun = time.monotonic()

            elif self.currentMenu == self.calTrans:
                self.fan(True)
                self.buttON(False)
                self.xMotor.calibrate()
                self.buttON(True)
                self.update()
                self.fan(False)

            elif self.currentMenu == self.calRot:
                self.fan(True)
                self.buttON(False)
                self.rMotor.calibrate()
                self.buttON(True)
                self.update()
                self.fan(False)

            elif self.currentMenu == self.freeMove:
                self.buttON(False)
                self.xMotor.goTo(self.currentMenu.getVal())
                self.buttON(True)
                self.update()

            elif self.currentMenu == self.freeRotate:
                self.buttON(False)
                self.rMotor.goTo(self.currentMenu.getVal())
                self.buttON(True)
                self.update()

            else:
                try:
                    self.currentMenu.isRecent(True)
                except:
                    pass
                self.currentMenu = self.ready
                self.buttON(True)
                self.fan(False)
                self.selector = 0
                self.calculate()
                self.update()
                self.saveDATA()
        else:
            self.exit = True
        return

    #Execute camera capture and update
    def captureSequence(self, shotNumber):
        self.buttON(True)
        self.capture(self.tVal.getShutter())
        self.buttON(False)
        self.updateInfo(self.nomages.getVal() - shotNumber)
        self.refresh()
        return

    #Trigger the camera
    def capture(self, time):
        GPIO.output(self.fullPress, False)
        sleep(time)
        GPIO.output(self.fullPress, True)
        GPIO.output(self.halfPress, True)
        return

    #Time for capture sequence
    def monotomiTimer(self, t1, delay):
        while time.monotonic() - t1 < delay:
            if time.monotonic() - t1 > self.inter.getVal() - 1:
                GPIO.output(self.halfPress, False)
            self.getTime()
            sleep(0.001)
        return