예제 #1
0
def initialize(**options):
    """
    Prepare the PyEPL repository and hardware interfaces for use.
    """
    global initialized
    if not initialized:
        initialized = True
        hardware.initialize(**options)
예제 #2
0
    def __init__(self, run_id, start_temp, target_temp, ramp_rate,
                 max_ramp_rate, PID_ref, PID_sample, interval,
                 min_upload_length, stabilization_duration, temp_tolerance):
        """
        Generic init method that initiates the class.

        :type run_id: int
        :param run_id: Run ID from the web server response.
        :type start_temp: float
        :param start_temp: Starting temperature specified by the user on the web interface.
        :type target_temp: float
        :param target_temp: Target temperature specified by the user on the web interface.
        :type ramp_rate: float
        :param ramp_rate: Ramp rate (0 - 1), as fraction of max rate, specified by the user on the web interface.
        :type max_ramp_rate: float
        :param max_ramp_rate: Maximum ramp rate allowed in degrees Celsius per minute,
            specified by the user on the Calibrate web page.
        :type PID_ref: hardware.PID
        :param PID_ref: PID object for the reference heater
        :type PID_sample: hardware.PID
        :param PID_sample: PID object for the sample heater
        :type interval: float
        :param interval: Main event PID calculation refresh interval.
        :type min_upload_length: int
        :param min_upload_length: Minimum number of measurements in batches when uploading data.
        :type stabilization_duration: float
        :param stabilization_duration: Minimum duration, in seconds, that temperature must stabilise before moving on.
        :type temp_tolerance: float
        :param temp_tolerance: Maximum difference between two temperature readings, in degrees Celsius,
            for them to be considered equivalent.
        """
        self.id = run_id
        self.start_temp = start_temp
        self.target_temp = target_temp
        self.ramp_rate = ramp_rate
        self.max_ramp_rate = (
            max_ramp_rate +
            0.434) * 0.02  # degrees per minute -> degrees per cycle

        self.PID_ref = PID_ref
        self.PID_sample = PID_sample

        self.heater_ref, self.heater_sample, self.adc = initialize()
        self.duty_cycle_ref, self.duty_cycle_sample = 0, 0

        self.interval = interval
        self.min_upload_length = min_upload_length
        self.temp_tolerance = temp_tolerance
        self.stabilization_duration = stabilization_duration

        self.stabilized_at_start = False
        self.is_ready = False
        self.is_finished = False

        self.last_time = time.time()
        self.network_queue = NetworkQueue(threshold_time=interval,
                                          threshold_qsize=min_upload_length)
        self.data_points = []
예제 #3
0
def initialize():
    hardware.initialize()
예제 #4
0
async def active(_loop, **calorimeter_data):
    """
    An asynchronous coroutine run periodically during an active calorimetry job.
    Contains logic about the set point, heating to start temp as quickly as possible, and uploading measurements.

    This function is the overarching loop responsible for two main parts of the DSC job.

    #. Firstly measure both temperatures simultaneously.
    #. Instantiate a new :class:`classes.Run` object containing relevant basic info about this DSC run.
       The info comes from the web API JSON response in the form of a dict.
       This dict then constructs the :class:`classes.Run` object using the special classmethod
       :meth:`classes.Run.from_web_resp`.
    #. Switch on LED lights to indicate starting up. Asynchronously, yield control to the
       :func:`main.get_ready` co-routine loop. Coincidentally, when a new :class:`Run` object is
       instantiated, it will automatically set the heaters
    #. When control is given back to this function,
       it suggests that temperature has stabilised at the start temperature.
       Switch on LED lights to indicate heating up, while yielding control to the
       :func:`main.run_calorimetry` co-routine.
    #. When control is again yielded to this function,
       the DSC job in question has finished.
       Clean up the GPIO boards and go back to the
       :func:`main.idle` loop.

    This function will also go back to the :func:`main.idle` loop and cleanup if at any point
    a :exc:`utils.StopHeatingError` is raised.

    :param _loop: The main event loop.
    :param calorimeter_data: JSON representation of the active job from the server API.
    """

    # Read temperatures simultaneously by creating a combined Future object (blocking)
    temp_ref, temp_sample = await asyncio.gather(asyncio.ensure_future(read_temp_ref()),
                                                 asyncio.ensure_future(read_temp_sample()),
                                                 loop=_loop)

    # Get a representation of this DSC run
    run = Run.from_web_resp(calorimeter_data, temp_ref, temp_sample)

    try:
        # Get cells to reach start temperature
        _loop.call_soon(indicate_starting_up)

        if settings.DEBUG:
            print('****************************************'
                  '\nThe main event loop has entered the GET READY LOOP.')

        await get_ready(_loop, run)

        # When control is yielded back from get_ready, start_temp has been reached
        _loop.call_soon(indicate_heating, _loop)

        if settings.DEBUG:
            print('****************************************'
                  '\nThe main event loop has entered the LINEAR RAMP LOOP.')
        await run_calorimetry(_loop, run)

    # when instructed to stop heating, clean up and return to idle function
    except StopHeatingError:
        cleanup(run.heater_sample, run.heater_ref, wipe=True)
        initialize(board_only=True)
        return
예제 #5
0
        # make measurements and upload
        await run.make_measurement(_loop)
        await run.queue_upload(_loop)

        # Sleep for a set amount of time, then rerun the PWM calculations
        await asyncio.sleep(run.interval)


if __name__ == '__main__':
    # For some reason, some imports on the raspberry pi do not work unless the following is included
    ROOT_DIR = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0]))
    if ROOT_DIR not in sys.path:
        sys.path.insert(0, ROOT_DIR)

    # initialize the GPIO boards and set output pins to output mode
    initialize(board_only=True)

    # asynchronous main event loop
    loop = asyncio.get_event_loop()

    # enable verbose mode if in development
    if settings.DEBUG:
        loop.set_debug(enabled=True)

    try:
        # start and run main event loop
        asyncio.ensure_future(idle(loop), loop=loop)
        loop.run_forever()

    finally:
        # When any error occurs or when the main loop ends,
예제 #6
0
 def __init__(self):
     hardware.initialize()