Ejemplo n.º 1
0
def _test_temperature():
    """Tests the temperature probe"""
    for i in range(5):
        temperature, res = interfaces.read_temperature()
        interfaces.lcd_out("Temperature: {0:0.3f}C".format(temperature), 1)
        interfaces.lcd_out("Res: {0:0.3f} Ohms".format(res), 2)
        interfaces.delay(0.5)
Ejemplo n.º 2
0
    def drive_step_stick(self, cycles, direction):
        """
        cycles and direction are integers
        Communicates with arduino to add HCl through pump
        :param cycles: number of rising edges for the pump
        :param direction: direction of pump
        """
        if cycles == 0:
            return 0

        interfaces.delay(0.01)
        if self.serial.writable():
            self.serial.write(cycles.to_bytes(4, "little"))
            self.serial.write(direction.to_bytes(1, "little"))
            self.serial.flush()
            wait_time = cycles / 1000 + 0.5
            print("wait_time = ", wait_time)
            interfaces.delay(wait_time)
            temp = self.serial.readline()
            if temp == b"DONE\r\n" or temp == b"":
                return 0
            else:
                return int(temp)
        else:
            interfaces.lcd_out("Arduino Unavailable", 4, constants.LCD_CENT_JUST)
Ejemplo n.º 3
0
def degas(seconds):
    interfaces.lcd_clear()
    interfaces.lcd_out("Degassing {0:.0f}".format(seconds), line=1)
    interfaces.lcd_out("seconds", line=2)
    interfaces.stir_speed_fast()
    interfaces.delay(seconds, countdown=True)
    interfaces.stir_speed_slow()
Ejemplo n.º 4
0
    def drive_pump(self, volume, direction):
        """Converts volume to cycles and ensures and checks pump level and values"""
        if direction == 0:
            space_in_pump = self.max_pump_capacity - self.volume_in_pump
            if volume > space_in_pump:
                interfaces.lcd_out("Filling Error", line=4)
            else:
                interfaces.lcd_out("Filling {0:1.2f} ml".format(volume), line=4)
                cycles = analysis.determine_pump_cycles(volume)
                self.drive_step_stick(cycles, direction)
                self.volume_in_pump += volume
        elif direction == 1:
            if volume > self.volume_in_pump:
                interfaces.lcd_out("Pumping Error", line=4)
            else:
                interfaces.lcd_out("Pumping {0:1.2f} ml".format(volume), line=4)
                cycles = analysis.determine_pump_cycles(volume)
                offset = self.drive_step_stick(cycles, direction)
                # offset is what is returned from drive_step_stick which originally is returned from the arduino
                if offset != 0:
                    self.drive_step_stick(offset, 0)
                    self.drive_step_stick(offset, 1)
                self.set_volume_in_pump(self.volume_in_pump - volume)

        interfaces.lcd_out("Pump Vol: {0:1.2f} ml".format(self.volume_in_pump), line=4)
def test_routines_test_mode_pump(monkeypatch, capsys):
    monkeypatch.setattr("sys.stdin", io.StringIO("0\n*\n5\nA\n0\nA\n"))
    routines.test_mode_pump()
    _ = capsys.readouterr()
    interfaces.lcd_out("", 1)
    captured = capsys.readouterr()
    assert captured.out == ("*====================*\n" +
                            "|                    |\n" +
                            "|                    |\n" +
                            "|                    |\n" +
                            "|Pump Vol: 0.50 ml   |\n" +
                            "*====================*\n")
Ejemplo n.º 6
0
    def pump_volume(self, volume, direction):
        """
        Moves volume of solution through pump
        :param volume: amount of volume to move (float)
        :param direction: 0 to pull solution in, 1 to pump out
        """
        volume_to_add = volume

        # pull in solution
        if direction == 0:
            # if volume_to_add is greater than space in the pump
            space_in_pump = self.max_pump_capacity - self.volume_in_pump
            if volume_to_add > space_in_pump:
                volume_to_add = self.max_pump_capacity - self.volume_in_pump
            self.drive_pump(volume_to_add, direction)

        # pump out solution
        elif direction == 1:
            # volume greater than max capacity of pump
            if volume_to_add > self.max_pump_capacity:
                interfaces.lcd_out(
                    "Volume > pumpable", style=constants.LCD_CENT_JUST, line=4
                )

                # pump out all current volume
                next_volume = self.volume_in_pump
                self.drive_pump(next_volume, 1)

                # calculate new volume to add
                volume_to_add = volume_to_add - next_volume

                # keep pumping until full volume_to_add is met
                while volume_to_add > 0:
                    next_volume = min(volume_to_add, self.max_pump_capacity)
                    self.drive_pump(next_volume, 0)
                    self.drive_pump(next_volume, 1)
                    volume_to_add -= next_volume

            # volume greater than volume in pump
            elif volume_to_add > self.volume_in_pump:
                next_volume = self.volume_in_pump
                self.drive_pump(next_volume, 1)

                # calculate remaining volume to add
                volume_to_add -= next_volume

                self.drive_pump(volume_to_add, 0)
                self.drive_pump(volume_to_add, 1)

            else:
                # volume less than volume in pump
                self.drive_pump(volume_to_add, direction)
def test_interfaces_lcd(capsys):
    # flush stdout
    _ = capsys.readouterr()

    interfaces.lcd_out("Test string", 1, constants.LCD_LEFT_JUST)

    captured = capsys.readouterr()
    assert captured.out == ("*====================*\n" +
                            "|Test string         |\n" +
                            "|                    |\n" +
                            "|                    |\n" +
                            "|                    |\n" +
                            "*====================*\n")
Ejemplo n.º 8
0
def prime_pump():
    """
    Primes pump by drawing in and pushing out solution.
    Depends on limit switches installed
    """
    interfaces.lcd_out("How many pumps?", 1)
    selection = interfaces.read_user_input()
    sel = int(selection)
    while sel > 0:
        while sel > 0:
            interfaces.drive_step_stick(10000, 0)
            interfaces.drive_step_stick(10000, 1)
            sel = sel - 1
        interfaces.lcd_out("How many more?", 1)
        selection = interfaces.read_user_input()
        sel = int(selection)
Ejemplo n.º 9
0
    def pump_volume(self, volume, direction):
        volume_to_add = volume

        # pull in solution
        if direction == 0:
            # check if volume to add is greater than space left
            space_in_pump = self.max_pump_capacity - self.volume_in_pump
            if volume_to_add > space_in_pump:
                volume_to_add = self.max_pump_capacity - self.volume_in_pump
            self.drive_pump(volume_to_add, direction)

        # pump out solution
        elif direction == 1:
            # volume greater than max capacity of pump
            if volume_to_add > self.max_pump_capacity:
                interfaces.lcd_out("Volume > pumpable",
                                   style=constants.LCD_CENT_JUST,
                                   line=4)

                # pump out all current volume
                next_volume = self.volume_in_pump
                self.drive_pump(next_volume, 1)

                # calculate new volume to add
                volume_to_add = volume_to_add - next_volume

                # keep pumping until full volume_to_add is met
                while volume_to_add > 0:
                    next_volume = min(volume_to_add, self.max_pump_capacity)
                    self.drive_pump(next_volume, 0)
                    self.drive_pump(next_volume, 1)
                    volume_to_add -= next_volume

            # volume greater than volume in pump
            elif volume_to_add > self.volume_in_pump:
                next_volume = self.volume_in_pump
                self.drive_pump(next_volume, 1)

                # calculate remaining volume to add
                volume_to_add -= next_volume

                self.drive_pump(volume_to_add, 0)
                self.drive_pump(volume_to_add, 1)
            else:
                # volume less than volume in pump
                self.drive_pump(volume_to_add, direction)
Ejemplo n.º 10
0
def test_mode_read_values(numVals=60, timestep=0.5):
    numVals = numVals
    timestep = timestep
    timeVals = np.zeros(numVals)
    tempVals = np.zeros(numVals)
    resVals = np.zeros(numVals)
    pHVals = np.zeros(numVals)
    voltVals = np.zeros(numVals)

    for i in range(numVals):
        temp, res = interfaces.read_temperature()
        pH_reading, pH_volts = interfaces.read_pH()
        interfaces.lcd_out("Temp: {0:>4.3f} C".format(temp), line=1)
        interfaces.lcd_out("Res:  {0:>4.3f} Ohms".format(res), line=2)
        interfaces.lcd_out("pH:   {0:>4.5f} pH".format(pH_reading), line=3)
        interfaces.lcd_out("pH V: {0:>3.4f} mV".format(pH_volts * 1000),
                           line=4)
        interfaces.lcd_out("Reading: {}".format(i), 1, console=True)
        timeVals[i] = timestep * i
        tempVals[i] = temp
        resVals[i] = res
        pHVals[i] = pH_reading
        voltVals[i] = pH_volts
        interfaces.delay(timestep)
Ejemplo n.º 11
0
def test_mode_read_volume():
    interfaces.lcd_clear()
    interfaces.lcd_out("Pump Vol: ", line=1)
    interfaces.lcd_out(
        "{0:1.2f}".format(constants.volume_in_pump),
        style=constants.LCD_CENT_JUST,
        line=2,
    )
    interfaces.lcd_out("Press any to cont.", line=3)
    interfaces.read_user_input()
Ejemplo n.º 12
0
def titration(pH_target,
              solution_increment_amount,
              data,
              total_sol_added,
              degas_time=0):
    """
    Incrementally adds HCl depending on the input parameters, until target pH is reached
    :param pH_target: target pH for the titration
    :param solution_increment_amount: amount of HCl to add to solution. Units of mL
    :param data: list of recorded temperature, pH, and solution volume data so far
    :param total_sol_added: total amount of HCl added to the solution so far
    :param degas_time: optional parameter defining the de-gas time for the solution after the target pH has been reached
    :return: total solution added so far
    """
    interfaces.lcd_out(
        "Titrating to {} pH".format(str(pH_target)),
        style=constants.LCD_CENT_JUST,
        line=4,
    )
    # total HCl added
    total_sol = total_sol_added

    current_pH = wait_pH_stable(total_sol, data)

    while current_pH - pH_target > constants.PH_ACCURACY:
        interfaces.pump_volume(solution_increment_amount, 1)
        if constants.volume_in_pump < 0.05:
            # pump in 1 mL
            interfaces.pump_volume(1.0, 0)
        total_sol += solution_increment_amount

        # TESTING SETTLING
        interfaces.lcd_out("Mixing...", style=constants.LCD_CENT_JUST, line=4)
        interfaces.delay(10)  # allow it to mix before taking measurements

        current_pH = wait_pH_stable(total_sol, data)
        interfaces.temperature_controller.update()

    interfaces.lcd_clear()
    interfaces.lcd_out("pH value {} reached".format(current_pH), line=1)
    interfaces.lcd_out("Degassing " + str(degas_time) + " seconds", line=2)

    interfaces.delay(degas_time, countdown=True)
    return total_sol
Ejemplo n.º 13
0
def wait_pH_stable(total_sol, data):
    """
    Continually polls probes until pH values are stable
    :param total_sol: total amount of HCl added to the solution so far
    :param data: list of recorded temperature, pH, and solution volume data so far
    :return: mean stable pH value of last 10 values
    """
    # keep track of 10 most recent pH values to ensure pH is stable
    pH_values = [0] * 10
    # a counter used for updating values in pH_values
    pH_list_counter = 0
    # flag to ensure at least 10 pH readings have been made before adding solution
    valid_num_values_tested = False

    while True:
        pH_reading, pH_volts = interfaces.read_pH()
        temperature_reading = interfaces.read_temperature()[0]
        interfaces.lcd_out("pH:   {0:>4.5f} pH".format(pH_reading), line=1)
        interfaces.lcd_out("pH V: {0:>3.4f} mV".format(pH_volts * 1000),
                           line=2)
        interfaces.lcd_out("Temp: {0:>4.3f} C".format(temperature_reading),
                           line=3)

        pH_values[pH_list_counter] = pH_reading

        if pH_list_counter == 9:
            valid_num_values_tested = True

        # Check that the temperature of the solution is within bounds
        if (abs(temperature_reading - constants.TARGET_TEMPERATURE) >
                constants.TEMPERATURE_ACCURACY):
            # interfaces.lcd_out("TEMPERATURE OUT OF BOUNDS")
            # TODO output to error log
            pass

        # Record data point (temperature, pH volts, total HCl)
        data.append(
            (temperature_reading, pH_volts, total_sol, None, None, None, None))
        pH_list_counter = 0 if pH_list_counter >= 9 else pH_list_counter + 1

        if (valid_num_values_tested and analysis.std_deviation(pH_values) <
                constants.TARGET_STD_DEVIATION):
            return pH_reading

        interfaces.delay(constants.TITRATION_WAIT_TIME)
Ejemplo n.º 14
0
def test_mode_toggle_test_mode():
    constants.IS_TEST = not constants.IS_TEST
    interfaces.lcd_clear()
    interfaces.lcd_out("Testing: {}".format(constants.IS_TEST), line=1)
    interfaces.lcd_out("Press any to cont.", line=3)
    interfaces.read_user_input()
Ejemplo n.º 15
0
def _calibrate_pH():
    """Routine for calibrating pH sensor."""
    # get first buffer pH
    buffer1_actual_pH = interfaces.read_user_value("Enter buffer pH:")
    interfaces.lcd_out("Put sensor in buffer",
                       style=constants.LCD_CENT_JUST,
                       line=1)
    interfaces.lcd_out("", line=2)
    interfaces.lcd_out("Press 1 to", style=constants.LCD_CENT_JUST, line=3)
    interfaces.lcd_out("record value", style=constants.LCD_CENT_JUST, line=4)
    # Waits for user to press enter
    interfaces.read_user_input()
    buffer1_measured_volts = float(interfaces.read_raw_pH())
    interfaces.lcd_clear()
    interfaces.lcd_out("Recorded pH and volts:", line=1)
    interfaces.lcd_out(
        "{0:>2.5f} pH, {1:>3.4f} V".format(buffer1_actual_pH,
                                           buffer1_measured_volts),
        line=2,
    )
    interfaces.lcd_out("Press any button",
                       style=constants.LCD_CENT_JUST,
                       line=3)
    interfaces.lcd_out("to continue", style=constants.LCD_CENT_JUST, line=4)
    interfaces.read_user_input()

    # set calibration constants
    constants.PH_REF_VOLTAGE = buffer1_measured_volts
    constants.PH_REF_PH = buffer1_actual_pH
Ejemplo n.º 16
0
def run():
    """Main driver for the program. Initializes components and queries the user for next steps"""

    try:
        # initialize components
        initialize_components()
        # output prompt to LCD screen
        routine_selection = "0"

        page = 1
        while routine_selection != "6" or routine_selection != constants.KEY_6:
            if routine_selection is constants.KEY_STAR:
                if page == 1:
                    page = 2
                else:
                    page = 1
            if page == 1:
                interfaces.display_list(constants.ROUTINE_OPTIONS_1)
            else:
                interfaces.display_list(constants.ROUTINE_OPTIONS_2)

            # wait for user input to select which routine (polling should be fine here)
            routine_selection = interfaces.read_user_input()
            routines.run_routine(routine_selection)

        analysis.save_calibration_data()
        interfaces.temperature_controller.deactivate()
        interfaces.lcd_clear()
        interfaces.ui_lcd.lcd_backlight(False)
    except (BaseException, Exception):
        # Deactivate the SSR if any crash occurs
        if interfaces.temperature_controller is not None:
            interfaces.temperature_controller.deactivate()
        print("\n************************\nDeactivated SSR\n************************\n")

        try:
            interfaces.lcd_clear()
        except BaseException:
            pass
        try:
            interfaces.lcd_out("Deactivated SSR", 1)
        except BaseException:
            pass

        # Attempt to save calibration data, this will save syringe position
        # and any recent calibrations
        try:
            analysis.save_calibration_data()
            print(
                "\n************************\nCalibration Saved\n************************\n"
            )
            try:
                interfaces.lcd_out("Calibration Saved", 2)
            except Exception:
                pass
        except Exception:
            print(
                "\n!!!!!!!!!!!!!!!!!!!!!!!!\nUnable to save calibration data\n!!!!!!!!!!!!!!!!!!!!!!!!\n"
            )
            try:
                interfaces.lcd_out("Calibration UNSAVED", 2)
            except Exception:
                pass
        print(sys.exc_info()[0])
        traceback.print_exc()
Ejemplo n.º 17
0
def edit_settings():
    """Resets calibration constants to default"""
    interfaces.lcd_out("Reset calibration", line=1)
    interfaces.lcd_out("settings to default?", line=2)
    interfaces.lcd_out("1: Yes", line=3)
    interfaces.lcd_out("2: No", line=4)
    selection = interfaces.read_user_input()
    if selection != "n" or selection != "N":
        analysis.reset_calibration()
        analysis.save_calibration_data()
        interfaces.lcd_clear()
        interfaces.lcd_out("Default constants restored", 1)
        interfaces.lcd_out("Press any to cont.", 3)
        interfaces.read_user_input()

    interfaces.lcd_out("Set volume in pump? (Y/n)", 1)
    selection = interfaces.read_user_input()
    if selection != "n" or selection != "N":
        vol_in_pump = interfaces.read_user_value("Volume in pump: ")
        constants.volume_in_pump = vol_in_pump
        analysis.save_calibration_data()
        interfaces.lcd_out("Volume in pump set", 1)
        interfaces.lcd_out("Press any to cont.", 3)
        interfaces.read_user_input()
Ejemplo n.º 18
0
def _calibrate_temperature():
    """Routine for calibrating the temperature probe."""
    expected_temperature = interfaces.read_user_value(
        "Ref solution temperature?")
    interfaces.lcd_out("Put probe in sol",
                       style=constants.LCD_CENT_JUST,
                       line=1)
    interfaces.lcd_out("", line=2)
    interfaces.lcd_out("Press 1 to", style=constants.LCD_CENT_JUST, line=3)
    interfaces.lcd_out("record value", style=constants.LCD_CENT_JUST, line=4)
    # Waits for user to press enter
    interfaces.read_user_input()
    expected_resistance = analysis.calculate_expected_resistance(
        expected_temperature)

    actual_temperature, actual_resistance = interfaces.read_temperature()
    interfaces.lcd_clear()
    interfaces.lcd_out(
        "Recorded temperature: {0:0.3f}".format(actual_temperature), line=1)
    diff = expected_resistance - actual_resistance
    new_ref_resistance = (
        constants.TEMPERATURE_REF_RESISTANCE +
        diff * constants.TEMPERATURE_REF_RESISTANCE / expected_resistance)
    constants.TEMPERATURE_REF_RESISTANCE = float(new_ref_resistance)
    # reinitialize sensors with calibrated values
    interfaces.lcd_out("{}".format(new_ref_resistance), line=2)
    interfaces.setup_interfaces()
Ejemplo n.º 19
0
def total_alkalinity_titration():
    """Runs through the full titration routine to find total alkalinity"""
    # pull in 1 ml of solution into pump for use in titration
    if constants.volume_in_pump < 1.0:
        p_volume = 1.0 - constants.volume_in_pump
        interfaces.pump_volume(float(p_volume), 0)
    # data object to hold recorded data
    data = [(
        "temperature",
        "pH V",
        "solution volume",
        "weight",
        "salinity",
        "Buffer pH",
        "Buffer pH V",
    )]

    # query user for initial solution weight
    initial_weight = interfaces.read_user_value("Sol. weight (g):")
    salinity = interfaces.read_user_value("Sol. salinity (ppt):")
    buffer_ph = constants.PH_REF_PH
    buffer_v = constants.PH_REF_VOLTAGE

    interfaces.lcd_clear()
    interfaces.lcd_out("Calibrate pH probe?", line=1)
    interfaces.lcd_out("Yes: 1", line=2)
    interfaces.lcd_out("No (use old): 0", line=3)
    interfaces.lcd_out("{0:>2.3f} pH: {1:>2.4f} V".format(buffer_ph, buffer_v),
                       line=4)
    selection = interfaces.read_user_input()
    if selection == constants.KEY_1:
        _calibrate_pH()

    data.append(
        (None, None, None, initial_weight, salinity, buffer_ph, buffer_v))

    # while not initial_weight.replace('.', '').isdigit():
    # interfaces.lcd_out("Please enter a numeric value.", console=True)
    # initial_weight = interfaces.read_user_input()

    # initial titration (bring solution close to 3.5)
    # todo set stir speed slow
    total_sol = 0
    interfaces.lcd_out("Bring pH to 3.5:", line=1)
    interfaces.lcd_out("Manual: 1", line=2)
    interfaces.lcd_out("Automatic: 2", line=3)
    interfaces.lcd_out("Stir speed: slow", line=4)
    user_choice = interfaces.read_user_input()

    # wait until solution is up to temperature
    interfaces.temperature_controller.activate()
    interfaces.lcd_clear()
    interfaces.lcd_out("Heating to 30 C...", line=1)
    interfaces.lcd_out("Please wait...", style=constants.LCD_CENT_JUST, line=3)
    if user_choice == "1":
        interfaces.lcd_out("MANUAL SELECTED",
                           style=constants.LCD_CENT_JUST,
                           line=4)
    else:
        interfaces.lcd_out("AUTO SELECTED",
                           style=constants.LCD_CENT_JUST,
                           line=4)
    while not interfaces.temperature_controller.at_temperature():
        interfaces.temperature_controller.update()
        temperature = interfaces.temperature_controller.get_last_temperature()
        interfaces.lcd_out(
            "Temp: {0:>4.3f} C".format(temperature),
            style=constants.LCD_CENT_JUST,
            line=2,
        )

    if user_choice == "1":
        # Manual
        while user_choice == "1":
            p_volume = interfaces.read_user_value("Volume: ")
            interfaces.lcd_clear()
            interfaces.lcd_out("Direction (0/1): ", line=1)
            p_direction = interfaces.read_user_input()
            p_volume = float(p_volume)
            p_direction = int(p_direction)
            if p_direction == 1:
                total_sol += p_volume
            if p_direction == 0 or p_direction == 1:
                interfaces.pump_volume(p_volume, p_direction)
            current_pH = wait_pH_stable(total_sol, data)
            interfaces.lcd_out("Current pH: {0:>4.5f}".format(current_pH),
                               line=1)
            interfaces.lcd_out("Continue adding solution?", line=2)
            interfaces.lcd_out("(0 - No, 1 - Yes)", line=3)
            interfaces.lcd_out("", line=4)

            user_choice = interfaces.read_user_input()
    else:
        # Automatic
        total_sol = titration(constants.TARGET_PH_INIT,
                              constants.INCREMENT_AMOUNT_INIT, data, 0, 0)
        total_sol = titration(
            constants.TARGET_PH_MID,
            constants.INCREMENT_AMOUNT_MID,
            data,
            total_sol,
            600,
        )

    # 3.5 -> 3.0
    # todo set stir speed fast
    interfaces.lcd_out("Stir speed: fast", line=4)
    titration(constants.TARGET_PH_FINAL, constants.INCREMENT_AMOUNT_FINAL,
              data, total_sol)
    # save data to csv
    analysis.write_titration_data(data)
    interfaces.temperature_controller.deactivate()