def test_build_config(): built_config = robot_configs.build_config(dummy_cal, dummy_settings) assert built_config.gantry_calibration == dummy_cal for key in [k for k in dummy_settings.keys() if k != 'tip_probe']: assert getattr(built_config, key) == dummy_settings[key] for key in [k for k in dummy_settings['tip_probe'].keys() if k != 'z_clearance']: assert getattr(built_config.tip_probe, key)\ == dummy_settings['tip_probe'][key] for key in [k for k in dummy_settings['tip_probe']['z_clearance'].keys()]: assert getattr(built_config.tip_probe.z_clearance, key)\ == dummy_settings['tip_probe']['z_clearance'][key] settings = copy.deepcopy(dummy_settings) settings['instrument_offset'].update({'right': {}}) built_config = robot_configs.build_config(dummy_cal, settings) expected = { 'left': { 'single': [1, 2, 3], 'multi': [4, 5, 6] }, 'right': { 'single': [0, 0, 0], 'multi': [0, 0, 0] } } assert built_config.instrument_offset == expected
def test_dictify_roundtrip(): new_settings = copy.deepcopy(dummy_settings) new_settings['tip_probe']['dimensions']\ = robot_configs._default_probe_dimensions() new_settings['tip_probe']['center']\ = robot_configs._default_probe_center() built_config = robot_configs.build_config(dummy_cal, dummy_settings) new_cal, new_config = robot_configs.config_to_save(built_config) assert new_cal == dummy_cal assert new_config == new_settings new_config = robot_configs.build_config(new_cal, new_config) assert new_config == built_config
def config(monkeypatch): default = robot_configs.build_config({}, {})._replace( gantry_calibration=[[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]], # probe top center tip_probe=robot_configs._build_tip_probe({})._replace( center=[5.0, 5.0, 100.0], # Bounding box relative to top center dimensions=[50.0, 50.0, 100.0]), # left relative to right instrument_offset={ 'right': { 'single': [0.0, 0.0, 0.0], 'multi': [0.0, 0.0, 0.0] }, 'left': { 'single': [0.0, 0.0, 0.0], 'multi': [0.0, 0.0, 0.0] } }, tip_length={'Pipette': 50}) def dummy_default(a, b): return default monkeypatch.setattr(robot_configs, 'build_config', dummy_default) return default
def test_persistance(tmpdir): sim = simulator_setup.SimulatorSetup( attached_instruments={ Mount.LEFT: {'max_volume': 300}, Mount.RIGHT: {'id': 'some id'}, }, attached_modules={ 'magdeck': [ simulator_setup.ModuleCall('engage', kwargs={'height': 3}) ], 'tempdeck': [ simulator_setup.ModuleCall('set_temperature', kwargs={'celsius': 23}), simulator_setup.ModuleCall('set_temperature', kwargs={'celsius': 24}) ] }, config=robot_configs.build_config([], {}) ) file = Path(tmpdir) / "sim_setup.json" simulator_setup.save_simulator_setup(sim, file) test_sim = simulator_setup.load_simulator_setup(file) assert test_sim == sim
async def test_clear_config(mock_config, sync_hardware): # Clear should happen automatically after the following import, resetting # the robot config to the default value from robot_configs from opentrons.deck_calibration import dc_main dc_main.clear_configuration_and_reload(sync_hardware) config = sync_hardware.config assert config == robot_configs.build_config({}, {})
def _prepare_for_simulator_setup(key, value): """Convert value to a SimulatorSetup""" if key == 'attached_instruments' and value: return {Mount[mount.upper()]: data for (mount, data) in value.items()} if key == 'config' and value: return robot_configs.build_config([], value) if key == 'attached_modules' and value: return { k: [ModuleCall(**data) for data in v] for (k, v) in value.items() } return value
async def test_correct_hotspots(): config = robot_configs.build_config([], {}) tip_length = 47 switch_clearance = 7.5 x_switch_offset = 2.0 y_switch_offset = 5.0 z_switch_offset = 5.0 deck_clearance = 5.0 z_probe_clearance = 5.0 z_start_clearance = 20.0 size_x, size_y, size_z = config.tip_probe.dimensions rel_x_start = (size_x / 2) + switch_clearance rel_y_start = (size_y / 2) + switch_clearance center = [293.03, 301.27, 74.3] nozzle_safe_z = round((size_z - tip_length) + z_probe_clearance, 3) z_start = max(deck_clearance, nozzle_safe_z) expected = [robot_configs.HotSpot('x', -rel_x_start, x_switch_offset, z_start, size_x), robot_configs.HotSpot('x', rel_x_start, x_switch_offset, z_start, -size_x), robot_configs.HotSpot('y', y_switch_offset, -rel_y_start, z_start, size_y), robot_configs.HotSpot('y', y_switch_offset, rel_y_start, z_start, -size_y), robot_configs.HotSpot('z', 0, z_switch_offset, center[2] + z_start_clearance, -size_z)] actual = robot_configs.calculate_tip_probe_hotspots( tip_length, config.tip_probe) assert expected == actual
async def test_controller_home(loop): c = hc.API.build_hardware_simulator(loop=loop, config=robot_configs.build_config({}, {})) await c.home() assert c._current_position == { Axis.X: 418, Axis.Y: 353, Axis.Z: 218, Axis.A: 218, Axis.B: 19, Axis.C: 19 } c._config = c._config._replace(gantry_calibration=[[1, 0, 0, 10], [0, 1, 0, 20], [0, 0, 1, 30], [0, 0, 0, 1]], mount_offset=[0, 0, 10]) conf = await c.config assert conf.gantry_calibration == [[1, 0, 0, 10], [0, 1, 0, 20], [0, 0, 1, 30], [0, 0, 0, 1]] await c.home() # Check that we correctly apply the inverse gantry calibration assert c._current_position == { Axis.X: 408, Axis.Y: 333, Axis.Z: 188, Axis.A: 188, Axis.B: 19, Axis.C: 19 } # Check that we subsequently apply mount offset assert await c.current_position(types.Mount.RIGHT) == { Axis.X: 408, Axis.Y: 333, Axis.A: 188, Axis.C: 19 } assert await c.current_position(types.Mount.LEFT) == { Axis.X: 408, Axis.Y: 333, Axis.Z: 198, Axis.B: 19 }
def test_update_instrument_config(fixture): from opentrons.trackers.pose_tracker import change_base from numpy import array import json robot = fixture.robot inst = fixture.instrument inst_offset = robot.config.instrument_offset[inst.mount][inst.type] cfg = update_instrument_config(instrument=inst, measured_center=(0.0, 0.0, 105.0)) new_tip_length = cfg.tip_length[inst.name] new_instrument_offset = cfg.instrument_offset[inst.mount][inst.type] assert new_tip_length == 55.0 assert new_instrument_offset == tuple(array(inst_offset) + (5.0, 5.0, 0.0)) assert tuple(change_base( robot.poses, src=inst, dst=inst.instrument_mover)) == (5.0, 5.0, 0), \ "Expected instrument position to update relative to mover in pose tree" filename = CONFIG['robot_settings_file'] _, expected = robot_configs.config_to_save( robot_configs.build_config([[]], {})) expected['instrument_offset']['right']['single'] = [5.0, 5.0, 0.0] expected['tip_length']['Pipette'] = 55.0 with open(filename, 'r') as file: actual = json.load(file) # from pprint import pprint # print('=------> <------=') # print("Expected:") # pprint(expected) # print() # print("Actual:") # pprint(actual) # print() assert actual == expected
deserializer=lambda json_dict: { top_types.Mount[mount_name.upper()]: pipette_info for mount_name, pipette_info in json_dict.items() }), Dict[types.Axis, bool]: SerDes( serializer=lambda axisdict: {ax.name: engaged for ax, engaged in axisdict.items()}, deserializer=lambda namedict: {types.Axis[ax.upper()]: engaged for ax, engaged in namedict.items()}), robot_configs.robot_config: SerDes( serializer=lambda config: list(robot_configs.config_to_save(config)), deserializer=lambda clist: robot_configs.build_config(*clist)), List[types.Axis]: SerDes( serializer=lambda axlist: [ax.name for ax in axlist], deserializer=lambda namelist: [types.Axis[name] for name in namelist]), } def _build_serializable_method(method_name, method): # noqa(C901) """ Build the method to actually server over jsonrpc. To serve over jsonrpc, we need to have an interface that is fully json-serializable. Since serving over jsonrpc is a secondary task of the hardware controller, we don't want to make all the hc methods json serializable because that would take away from the readability of rich typing for the python-python interface. Instead, we'll build adapters here