Ejemplo n.º 1
0
 def __init__(self):
     gpio.setmode(gpio.BCM)
     self.cfg = Config()
     self.pins = {
         'LED': self.cfg.get('LED'),
         'sensor': self.cfg.get('sensor'),
         'PWMa': self.cfg.get('PWMa'),
         'PWMb': self.cfg.get('PWMb'),
         'coilpin_M11': self.cfg.get('coilpin_M11'),
         'coilpin_M12': self.cfg.get('coilpin_M12'),
         'coilpin_M21': self.cfg.get('coilpin_M21'),
         'coilpin_M22': self.cfg.get('coilpin_M22'),
         'stdby': self.cfg.get('stdby')
     }
     self.led = False
     self.GPIOInit()
Ejemplo n.º 2
0
 def __init__(self, hw=None, cam=None):
     self.hw = hw
     self.cam = cam
     self.cfg = Config()
     self.delay = 60
     self.duration = 7
     self.dir = os.path.expanduser('~')
     self.starttime = 0
     self.endtime = 0
     self.running = False
     self.status = "Stopped"
     self.daytime = "TBD"
     self.quit = False
     self.stop_experiment = False
     self.status_change = threading.Event()
     self.next_status = ''
     self.last_captured = None
     self.nshots = 0
     threading.Thread.__init__(self)
Ejemplo n.º 3
0
    if not shutdown:
        # give the app 10 seconds to shut down, then force it
        shutdown = True
        signal.alarm(10)

    log("Signal " + str(sig) + " caught -- shutting down.")
    webui.stop()
    hw.motorOn(False)
    cam.close()
    hw.cleanup()
    sys.exit()


shutdown = False
cfg = Config()
cam = None
hw = HWControl()
for sig in [
        signal.SIGTERM, signal.SIGINT, signal.SIGQUIT, signal.SIGHUP,
        signal.SIGALRM
]:
    signal.signal(sig, terminate)


# start here.
def main():
    if options.reset:
        print("Clearing all configuration values.")
        try:
            os.remove(os.path.expanduser('~/.config/spiro/spiro.conf'))
Ejemplo n.º 4
0
class HWControl:
    def __init__(self):
        gpio.setmode(gpio.BCM)
        self.cfg = Config()
        self.pins = {
            'LED': self.cfg.get('LED'),
            'sensor': self.cfg.get('sensor'),
            'PWMa': self.cfg.get('PWMa'),
            'PWMb': self.cfg.get('PWMb'),
            'coilpin_M11': self.cfg.get('coilpin_M11'),
            'coilpin_M12': self.cfg.get('coilpin_M12'),
            'coilpin_M21': self.cfg.get('coilpin_M21'),
            'coilpin_M22': self.cfg.get('coilpin_M22'),
            'stdby': self.cfg.get('stdby')
        }
        self.led = False
        self.GPIOInit()

    def GPIOInit(self):
        gpio.setwarnings(False)
        gpio.setup(self.pins['LED'], gpio.OUT)
        gpio.setup(self.pins['sensor'], gpio.IN, pull_up_down=gpio.PUD_DOWN)
        gpio.setup(self.pins['PWMa'], gpio.OUT)
        gpio.setup(self.pins['PWMb'], gpio.OUT)
        gpio.setup(self.pins['coilpin_M11'], gpio.OUT)
        gpio.setup(self.pins['coilpin_M12'], gpio.OUT)
        gpio.setup(self.pins['coilpin_M21'], gpio.OUT)
        gpio.setup(self.pins['coilpin_M22'], gpio.OUT)
        gpio.setup(self.pins['stdby'], gpio.OUT)
        gpio.output(self.pins['PWMa'], True)
        gpio.output(self.pins['PWMb'], True)
        self.LEDControl(False)
        self.motorOn(False)

    def cleanup(self):
        gpio.cleanup()

    def findStart(self, calibration=None):
        """rotates the imaging stage until the positional switch is activated"""
        calibration = calibration or self.cfg.get('calibration')
        timeout = 60
        starttime = time.time()

        # make sure that switch is not depressed when starting
        if gpio.input(self.pins['sensor']):
            while gpio.input(
                    self.pins['sensor']) and time.time() < starttime + timeout:
                self.halfStep(1, 0.03)

        while not gpio.input(
                self.pins['sensor']) and time.time() < starttime + timeout:
            self.halfStep(1, 0.03)

        if time.time() < starttime + timeout:
            self.halfStep(calibration, 0.03)
        else:
            log("Timed out while finding start position! Images will be misaligned."
                )

    # sets the motor pins as element in sequence
    def setStepper(self, M_seq, i):
        gpio.output(self.pins['coilpin_M11'], M_seq[i][0])
        gpio.output(self.pins['coilpin_M12'], M_seq[i][1])
        gpio.output(self.pins['coilpin_M21'], M_seq[i][2])
        gpio.output(self.pins['coilpin_M22'], M_seq[i][3])

    # steps the stepper motor using half steps, "delay" is time between coil change
    # 400 steps is 360 degrees
    def halfStep(self, steps, delay, keep_motor_on=False):
        time.sleep(0.005)  # time for motor to activate
        for i in range(0, steps):
            self.setStepper(self.halfstep_seq, self.seqNumb)
            self.seqNumb += 1
            if (self.seqNumb == 8):
                self.seqNumb = 0
            time.sleep(delay)

    # sets motor standby status
    def motorOn(self, value):
        gpio.output(self.pins['stdby'], value)

    # turns on and off led
    def LEDControl(self, value):
        gpio.output(self.pins['LED'], value)
        self.led = value

    # focuses the ArduCam motorized focus camera
    # code is from ArduCam GitHub repo
    def focusCam(self, val):
        value = (val << 4) & 0x3ff0
        data1 = (value >> 8) & 0x3f
        data2 = value & 0xf0
        if os.path.exists('/dev/i2c-0'):
            os.system("i2cset -y 0 0x0c %d %d" % (data1, data2))
        if os.path.exists('/dev/i2c-1'):
            os.system("i2cset -y 1 0x0c %d %d" % (data1, data2))

    # my copy of the pinout
    pins = {}

    # state of stepper motor sequence
    seqNumb = 0

    # sequence for one coil rotation of stepper motor using half step
    halfstep_seq = [(1, 0, 0, 0), (1, 0, 1, 0), (0, 0, 1, 0), (0, 1, 1, 0),
                    (0, 1, 0, 0), (0, 1, 0, 1), (0, 0, 0, 1), (1, 0, 0, 1)]
Ejemplo n.º 5
0
class Experimenter(threading.Thread):
    def __init__(self, hw=None, cam=None):
        self.hw = hw
        self.cam = cam
        self.cfg = Config()
        self.delay = 60
        self.duration = 7
        self.dir = os.path.expanduser('~')
        self.starttime = 0
        self.endtime = 0
        self.running = False
        self.status = "Stopped"
        self.daytime = "TBD"
        self.quit = False
        self.stop_experiment = False
        self.status_change = threading.Event()
        self.next_status = ''
        self.last_captured = None
        self.nshots = 0
        self.idlepos = 0
        threading.Thread.__init__(self)

    def stop(self):
        self.status = "Stopping"
        self.next_status = ''
        self.stop_experiment = True
        log("Stopping running experiment...")

    def isDaytime(self):
        oldres = self.cam.resolution
        self.cam.resolution = (320, 240)
        self.cam.iso = self.cfg.get('dayiso')
        self.cam.shutter_speed = 1000000 // self.cfg.get('dayshutter')
        output = np.empty((240, 320, 3), dtype=np.uint8)
        self.cam.capture(output, 'rgb')
        self.cam.resolution = oldres
        debug("Daytime estimation mean value: " + str(output.mean()))
        return output.mean() > 10

    def setWB(self):
        debug("Determining white balance.")
        self.cam.awb_mode = "auto"
        time.sleep(2)
        g = self.cam.awb_gains
        self.cam.awb_mode = "off"
        self.cam.awb_gains = g

    def takePicture(self, name):
        filename = ""
        prev_daytime = self.daytime
        self.daytime = self.isDaytime()
        # always turn on led
        self.hw.LEDControl(True)

        if self.daytime:
            time.sleep(0.5)
            self.cam.shutter_speed = 1000000 // self.cfg.get('dayshutter')
            self.cam.iso = self.cfg.get('dayiso')
            self.cam.color_effects = None
            filename = os.path.join(self.dir, name + "-day.png")
        else:
            time.sleep(0.5)
            self.cam.shutter_speed = 1000000 // self.cfg.get('nightshutter')
            self.cam.iso = self.cfg.get('nightiso')
            #self.cam.color_effects = (128, 128)
            filename = os.path.join(self.dir, name + "-night.png")

        if prev_daytime != self.daytime and self.daytime and self.cam.awb_mode != "off":
            # if there is a daytime shift, AND it is daytime, AND white balance was not previously set,
            # set the white balance to a fixed value.
            # thus, white balance will only be fixed for the first occurence of daylight.
            self.setWB()

        debug("Capturing %s." % filename)
        self.cam.exposure_mode = "off"
        self.cam.capture(filename)
        self.last_captured = filename
        self.cam.color_effects = None
        self.cam.shutter_speed = 0
        # we leave the cam in auto exposure mode to improve daytime assessment performance
        self.cam.exposure_mode = "auto"

        # turn off led
        self.hw.LEDControl(False)

    def run(self):
        while not self.quit:
            self.status_change.wait()
            if self.next_status == 'run':
                self.next_status = ''
                self.status_change.clear()
                self.runExperiment()

    def go(self):
        self.next_status = 'run'
        self.status_change.set()

    def runExperiment(self):
        if self.running:
            raise RuntimeError('An experiment is already running.')

        try:
            debug("Starting experiment.")
            self.running = True
            self.status = "Initiating"
            self.starttime = time.time()
            self.endtime = time.time() + 60 * 60 * 24 * self.duration
            self.last_captured = None
            self.delay = self.delay or 0.001
            self.nshots = self.duration * 24 * 60 // self.delay
            self.cam.exposure_mode = "auto"
            self.cam.shutter_speed = 0
            self.hw.LEDControl(False)

            for i in range(4):
                platedir = "plate" + str(i + 1)
                os.makedirs(os.path.join(self.dir, platedir), exist_ok=True)

            while time.time() < self.endtime and not self.stop_experiment:
                loopstart = time.time()
                nextloop = time.time() + 60 * self.delay
                if nextloop > self.endtime:
                    nextloop = self.endtime

                for i in range(4):
                    # rotate stage to starting position
                    if i == 0:
                        self.hw.motorOn(True)
                        self.status = "Finding start position"
                        debug("Finding initial position.")
                        self.hw.findStart(
                            calibration=self.cfg.get('calibration'))
                        debug("Found initial position.")
                    else:
                        self.status = "Imaging"
                        # rotate cube 90 degrees
                        debug("Rotating stage.")
                        self.hw.halfStep(100, 0.03)

                    # wait for the cube to stabilize
                    time.sleep(0.5)

                    now = time.strftime("%Y%m%d-%H%M%S", time.localtime())
                    name = os.path.join("plate" + str(i + 1),
                                        "plate" + str(i + 1) + "-" + now)
                    self.takePicture(name)

                self.nshots -= 1
                self.hw.motorOn(False)
                self.status = "Waiting"

                if self.idlepos > 0:
                    # alternate between resting positions during idle, stepping 45 degrees per image
                    self.hw.motorOn(True)
                    self.hw.halfStep(50 * self.idlepos, 0.03)
                    self.hw.motorOn(False)

                self.idlepos += 1
                if self.idlepos > 7:
                    self.idlepos = 0

                while time.time() < nextloop and not self.stop_experiment:
                    # keep rotating while waiting, similar light conditions for each plate
                    self.hw.motorOn(True)
                    self.hw.halfStep(21, 0.03)
                    self.hw.motorOn(False)
                    time.sleep(60)

        finally:
            log("Experiment stopped.")
            self.cam.color_effects = None
            self.status = "Stopped"
            self.stop_experiment = False
            self.running = False
            self.cam.exposure_mode = "auto"
            self.cam.meter_mode = 'spot'
Ejemplo n.º 6
0
class Experimenter(threading.Thread):
    def __init__(self, hw=None, cam=None):
        self.hw = hw
        self.cam = cam
        self.cfg = Config()
        self.delay = 60
        self.duration = 7
        self.dir = os.path.expanduser('~')
        self.starttime = 0
        self.endtime = 0
        self.running = False
        self.status = "Stopped"
        self.daytime = "TBD"
        self.quit = False
        self.stop_experiment = False
        self.status_change = threading.Event()
        self.next_status = ''
        self.last_captured = None
        self.nshots = 0
        threading.Thread.__init__(self)

    def stop(self):
        self.status = "Stopping"
        self.next_status = ''
        self.stop_experiment = True
        log("Stopping running experiment...")

    def isDaytime(self):
        # determine if it's day or not.

        # we need to set a bogus shutter speed before switching to auto exposure mode
        # otherwise the camera can get stuck for some reason
        self.cam.shutter_speed = 10000

        self.cam.exposure_mode = "auto"
        self.cam.shutter_speed = 0
        self.cam.iso = 100
        self.cam.meter_mode = 'matrix'

        # to determine day/night we use a rotating list of the last 5 exposure readings
        # exposure may take a very long time to settle, so we use some heuristics to determine whether it is day or night
        itsday = 'TBD'
        exps = deque([-1, 100, -1, 100, -1])
        stuck = 0

        while itsday == 'TBD':
            time.sleep(1)
            exps.popleft()
            # round the exposure to nearest 1000
            exps.append(self.cam.exposure_speed // 1000)

            if exps[4] < exps[3] < exps[2] < exps[1] < exps[0]:
                if mean(exps) < 33:
                    # decreasing exposure, value below 33000
                    itsday = True
            elif exps[4] > exps[3] > exps[2] > exps[1] > exps[0]:
                if mean(exps) > 33:
                    # increasing exposure time, value above 33999
                    itsday = False
            elif exps[4] == exps[3] == exps[2] == exps[1] == exps[0]:
                if mean(exps) < 33:
                    # stable exposure, value below 33000
                    itsday = True
                elif mean(exps) > 33:
                    # stable exposure, value above 33999
                    itsday = False
                else:
                    # we are stuck at around 1/30 for some reason
                    stuck = stuck + 1

            if stuck > 20:
                # we have been stuck for over 20 seconds, just call it night so we can move on
                itsday = False

        debug("[isDaytime] Daytime: " + str(itsday) + ". Exposure values: " +
              str(exps))
        return itsday

    def setWB(self):
        debug("Determining white balance.")
        self.cam.awb_mode = "auto"
        time.sleep(2)
        g = self.cam.awb_gains
        self.cam.awb_mode = "off"
        self.cam.awb_gains = g

    def takePicture(self, name):
        filename = ""
        prev_daytime = self.daytime
        self.daytime = self.isDaytime()

        if self.daytime:
            time.sleep(0.5)
            self.cam.shutter_speed = 1000000 // self.cfg.get('dayshutter')
            self.cam.iso = self.cfg.get('dayiso')
            self.cam.color_effects = None
            filename = os.path.join(self.dir, name + "-day.jpg")
        else:
            # turn on led
            self.hw.LEDControl(True)
            time.sleep(0.5)
            self.cam.shutter_speed = 1000000 // self.cfg.get('nightshutter')
            self.cam.iso = self.cfg.get('nightiso')
            self.cam.color_effects = (128, 128)
            filename = os.path.join(self.dir, name + "-night.jpg")

        if prev_daytime != self.daytime and self.daytime and self.cam.awb_mode != "off":
            # if there is a daytime shift, AND it is daytime, AND white balance was not previously set,
            # set the white balance to a fixed value.
            # thus, white balance will only be fixed for the first occurence of daylight.
            self.setWB()

        debug("Capturing %s." % filename)
        self.cam.exposure_mode = "off"
        self.cam.capture(filename)
        self.last_captured = filename
        self.cam.color_effects = None
        self.cam.shutter_speed = 0
        # we leave the cam in auto exposure mode to improve daytime assessment performance
        self.cam.exposure_mode = "auto"

        if not self.daytime:
            # turn off led
            self.hw.LEDControl(False)

    def run(self):
        while not self.quit:
            self.status_change.wait()
            if self.next_status == 'run':
                self.next_status = ''
                self.status_change.clear()
                self.runExperiment()

    def go(self):
        self.next_status = 'run'
        self.status_change.set()

    def runExperiment(self):
        if self.running:
            raise RuntimeError('An experiment is already running.')

        try:
            debug("Starting experiment.")
            self.running = True
            self.status = "Initiating"
            self.starttime = time.time()
            self.endtime = time.time() + 60 * 60 * 24 * self.duration
            self.last_captured = None
            self.delay = self.delay or 0.001
            self.nshots = self.duration * 24 * 60 // self.delay
            self.cam.exposure_mode = "auto"
            self.cam.shutter_speed = 0
            self.hw.LEDControl(False)

            for i in range(4):
                platedir = "plate" + str(i + 1)
                os.makedirs(os.path.join(self.dir, platedir), exist_ok=True)

            while time.time() < self.endtime and not self.stop_experiment:
                loopstart = time.time()
                nextloop = time.time() + 60 * self.delay
                if nextloop > self.endtime:
                    nextloop = self.endtime

                for i in range(4):
                    # rotate stage to starting position
                    if i == 0:
                        self.hw.motorOn(True)
                        self.status = "Finding start position"
                        debug("Finding initial position.")
                        self.hw.findStart(
                            calibration=self.cfg.get('calibration'))
                        debug("Found initial position.")
                    else:
                        self.status = "Imaging"
                        # rotate cube 90 degrees
                        debug("Rotating stage.")
                        self.hw.halfStep(100, 0.03)

                    # wait for the cube to stabilize
                    time.sleep(0.5)

                    now = time.strftime("%Y%m%d-%H%M%S", time.localtime())
                    name = os.path.join("plate" + str(i + 1),
                                        "plate" + str(i + 1) + "-" + now)
                    self.takePicture(name)

                self.nshots -= 1
                self.hw.motorOn(False)

                # this part is "active waiting", rotating the cube slowly over the period of options.delay
                # this ensures consistent lighting for all plates.
                # account for the time spent capturing images.
                self.status = "Waiting"
                secs = 0
                while time.time() < nextloop and not self.stop_experiment:
                    time.sleep(1)
                    secs += 1
                    if self.delay > 15 and secs == int(self.delay / 7.5):
                        # don't bother if delay is very short (<= 15 min)
                        secs = 0
                        self.hw.motorOn(True)
                        self.hw.halfStep(50, 0.03)
                        self.hw.motorOn(False)

        finally:
            log("Experiment stopped.")
            self.cam.color_effects = None
            self.status = "Stopped"
            self.stop_experiment = False
            self.running = False
            self.cam.exposure_mode = "auto"
            self.cam.meter_mode = 'spot'