Esempio n. 1
0
    def cache_instrument_models(self):
        """
        Queries Smoothie for the model and ID strings of attached pipettes, and
        saves them so they can be reported without querying Smoothie again (as
        this could interrupt a command if done during a run or other movement).

        Shape of return dict should be:

        ```
        {
          "left": {
            "model": "<model_string>" or None,
            "id": "<pipette_id_string>" or None
          },
          "right": {
            "model": "<model_string>" or None,
            "id": "<pipette_id_string>" or None
          }
        }
        ```

        :return: a dict with pipette data (shape described above)
        """
        log.debug("Updating instrument model cache")
        for mount in self.model_by_mount.keys():
            model_value = self._driver.read_pipette_model(mount)
            if model_value:
                name_value = pipette_config.name_for_model(model_value)
            else:
                name_value = None
            plunger_axis = 'B' if mount == 'left' else 'C'
            mount_axis = 'Z' if mount == 'left' else 'A'
            if model_value:
                cfg = pipette_config.load(model_value)
                home_pos = cfg.home_position
                max_travel = cfg.max_travel
                steps_mm = cfg.steps_per_mm
            else:
                home_pos = self.config.default_pipette_configs['homePosition']
                max_travel = self.config.default_pipette_configs['maxTravel']
                steps_mm = self.config.default_pipette_configs['stepsPerMM']

            self._driver.update_steps_per_mm({plunger_axis: steps_mm})
            self._driver.update_pipette_config(mount_axis, {'home': home_pos})
            self._driver.update_pipette_config(plunger_axis,
                                               {'max_travel': max_travel})

            if model_value:
                id_response = self._driver.read_pipette_id(mount)
            else:
                id_response = None
            self.model_by_mount[mount] = {
                'model': model_value,
                'id': id_response,
                'name': name_value
            }
            log.debug("{}: {} [{}]".format(mount,
                                           self.model_by_mount[mount]['model'],
                                           self.model_by_mount[mount]['id']))
Esempio n. 2
0
def test_load_instrument(loop):
    ctx = papi.ProtocolContext(loop=loop)
    for model in config_models:
        loaded = ctx.load_instrument(model, Mount.LEFT, replace=True)
        assert loaded.model == model
        instr_name = name_for_model(model)
        loaded = ctx.load_instrument(instr_name, Mount.RIGHT, replace=True)
        assert loaded.name == instr_name
Esempio n. 3
0
 def __init__(self,
              model: str,
              inst_offset_config: Dict[str, Tuple[float, float, float]],
              pipette_id: str = None) -> None:
     self._config = pipette_config.load(model, pipette_id)
     self._name = pipette_config.name_for_model(model)
     self._model = model
     self._model_offset = self._config.model_offset
     self._current_volume = 0.0
     self._working_volume = self._config.max_volume
     self._current_tip_length = 0.0
     self._fallback_tip_length = self._config.tip_length
     self._has_tip = False
     self._pipette_id = pipette_id
     pip_type = 'multi' if self._config.channels > 1 else 'single'
     self._instrument_offset = Point(*inst_offset_config[pip_type])
     self._log = mod_log.getChild(
         self._pipette_id if self._pipette_id else '<unknown>')
     self._log.info("loaded: {}, instr offset {}".format(
         model, self._instrument_offset))
     self.ready_to_aspirate = False
Esempio n. 4
0
async def test_get_cached_pipettes(async_server, async_client, monkeypatch):
    test_model = 'p300_multi_v1'
    test_name = 'p300_multi'
    test_id = '123abc'

    hw = async_server['com.opentrons.hardware']
    hw._backend._attached_instruments = {
        types.Mount.RIGHT: {
            'model': test_model,
            'id': test_id
        },
        types.Mount.LEFT: {
            'model': test_model,
            'id': test_id
        }
    }

    await hw.reset()

    model = pipette_config.load(test_model)
    expected = {
        'left': {
            'model': test_model,
            'name': test_name,
            'tip_length': model.tip_length,
            'mount_axis': 'z',
            'plunger_axis': 'b',
            'id': test_id
        },
        'right': {
            'model': test_model,
            'name': test_name,
            'tip_length': model.tip_length,
            'mount_axis': 'a',
            'plunger_axis': 'c',
            'id': test_id
        }
    }

    resp = await async_client.get('/pipettes')
    text = await resp.text()
    assert resp.status == 200
    assert json.loads(text) == expected

    model1 = 'p10_single_v1.3'
    config1 = pipette_config.load(model1)
    id1 = 'fgh876'
    hw._backend._attached_instruments = {
        types.Mount.RIGHT: {
            'model': model1,
            'id': id1
        },
        types.Mount.LEFT: {
            'model': model1,
            'id': id1
        }
    }

    resp1 = await async_client.get('/pipettes')
    text1 = await resp1.text()
    assert resp1.status == 200
    assert json.loads(text1) == expected

    expected2 = {
        'left': {
            'model': model1,
            'name': pipette_config.name_for_model(model1),
            'tip_length': config1.tip_length,
            'mount_axis': 'z',
            'plunger_axis': 'b',
            'id': id1
        },
        'right': {
            'model': model1,
            'name': pipette_config.name_for_model(model1),
            'tip_length': config1.tip_length,
            'mount_axis': 'a',
            'plunger_axis': 'c',
            'id': id1
        }
    }

    resp2 = await async_client.get('/pipettes?refresh=true')
    text2 = await resp2.text()
    assert resp2.status == 200
    assert json.loads(text2) == expected2
Esempio n. 5
0
    def cache_instrument_models(self):
        """
        Queries Smoothie for the model and ID strings of attached pipettes, and
        saves them so they can be reported without querying Smoothie again (as
        this could interrupt a command if done during a run or other movement).

        Shape of return dict should be:

        ```
        {
          "left": {
            "model": "<model_string>" or None,
            "id": "<pipette_id_string>" or None
          },
          "right": {
            "model": "<model_string>" or None,
            "id": "<pipette_id_string>" or None
          }
        }
        ```

        :return: a dict with pipette data (shape described above)
        """
        log.debug("Updating instrument model cache")
        for mount in self.model_by_mount.keys():
            plunger_axis = 'B' if mount == 'left' else 'C'
            mount_axis = 'Z' if mount == 'left' else 'A'
            model_value = self._driver.read_pipette_model(mount)
            splits = {plunger_axis: None}
            if model_value:
                name_value = pipette_config.name_for_model(model_value)
                pc = pipette_config.load(model_value)
                home_current = pc.plunger_current
                if 'needsUnstick' in pc.quirks:
                    splits[plunger_axis] = MoveSplit(split_distance=1,
                                                     split_current=1.5,
                                                     split_speed=1,
                                                     after_time=1800,
                                                     fullstep=True)
            else:
                name_value = None
                home_current = self.config.high_current[plunger_axis]

            if model_value:
                cfg = pipette_config.load(model_value)
                home_pos = cfg.home_position
                max_travel = cfg.max_travel
                steps_mm = cfg.steps_per_mm
                idle_current = cfg.idle_current
            else:
                home_pos = self.config.default_pipette_configs['homePosition']
                max_travel = self.config.default_pipette_configs['maxTravel']
                steps_mm = self.config.default_pipette_configs['stepsPerMM']
                idle_current = self.config.low_current[plunger_axis]

            self._driver.update_steps_per_mm({plunger_axis: steps_mm})
            self._driver.update_pipette_config(mount_axis, {'home': home_pos})
            self._driver.update_pipette_config(plunger_axis,
                                               {'max_travel': max_travel})
            self._driver.set_dwelling_current({plunger_axis: idle_current})
            self._driver.configure_splits_for(splits)

            if model_value:
                id_response = self._driver.read_pipette_id(mount)
            else:
                id_response = None
            self.model_by_mount[mount] = {
                'model': model_value,
                'id': id_response,
                'name': name_value,
                'home_current': home_current
            }
            log.debug("{}: {} [{}]".format(mount,
                                           self.model_by_mount[mount]['model'],
                                           self.model_by_mount[mount]['id']))