def exit(): # stop any active threads exit_threads.set() # stop detached run thread Robot.get_instance().stop() # stops attached run thread func = request.environ.get('werkzeug.server.shutdown') if func is None: sys.exit() func() return 'Server shutting down...'
def _detached_progress(): robot = Robot.get_instance() while not exit_threads.is_set(): res = robot._driver.smoothie_player.progress(timeout=20) if not res.get('file'): return percentage = '{}%'.format(round(res.get('percentage', 0) * 100, 2)) def _seconds_to_string(sec): hours = int(sec / (60 * 60)) hours = str(hours) if hours > 9 else '0{}'.format(hours) minutes = int(sec / 60) % 60 minutes = str(minutes) if minutes > 9 else '0{}'.format(minutes) seconds = sec % 60 seconds = str(seconds) if seconds > 9 else '0{}'.format(seconds) return (hours, minutes, seconds) h, m, s = _seconds_to_string(res.get('elapsed_time')) progress_data = 'Protocol {} Complete - Elapsed Time {}:{}:{}'.format( percentage, h, m, s) if res.get('estimated_time'): h, m, s = _seconds_to_string(res.get('estimated_time')) progress_data += ' - Estimated Time Left {}:{}:{}'.format(h, m, s) d = { 'caller': 'ui', 'mode': 'live', 'name': 'command-run', 'command_description': progress_data } notify(d)
def _run_commands(should_home_first=True): robot = Robot.get_instance() start_time = time.time() api_response = {'errors': [], 'warnings': []} try: robot.resume() robot.run(caller='ui') if len(robot._commands) == 0: error = \ "This protocol does not contain any commands for the robot." api_response['errors'] = [error] except Exception as e: api_response['errors'] = [str(e)] api_response['warnings'] = robot.get_warnings() or [] api_response['name'] = 'run exited' end_time = time.time() emit_notifications(api_response['warnings'], 'warning') emit_notifications(api_response['errors'], 'danger') seconds = end_time - start_time minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) run_time = "%d:%02d:%02d" % (hours, minutes, seconds) result = "Run complete in {}".format(run_time) emit_notifications([result], 'success') socketio.emit('event', {'name': 'run-finished'})
def _run_detached(): try: robot = Robot.get_instance() p = player.SmoothiePlayer_2_0_0() d = {'caller': 'ui', 'mode': 'live', 'name': 'command-run'} d.update({'command_description': 'Simulating, please wait...'}) notify(d) robot.smoothie_drivers['simulate'].record_start(p) robot.simulate() robot.smoothie_drivers['simulate'].record_stop() d.update( {'command_description': 'Saving file to robot, please wait...'}) notify(d) robot._driver.play(p) d.update({ 'command_description': 'Protocol running, unplug USB at any time.' }) notify(d) d.update( {'command_description': 'To stop, unplug USB and power robot OFF'}) notify(d) _detached_progress() except Exception as e: emit_notifications([str(e)], 'danger') socketio.emit('event', {'name': 'run-finished'})
def _get_all_pipettes(): robot = Robot.get_instance() pipette_list = [] for _, p in robot.get_instruments(): if isinstance(p, instruments.Pipette): pipette_list.append(p) return sorted(pipette_list, key=lambda p: p.name.lower())
def setUp(self): Robot.reset_for_tests() self.robot = Robot.get_instance() self.robot.connect() self.trash = containers.load('point', 'A1', 'trash') self.tiprack = containers.load('tiprack-200ul', 'B2', 'p200-rack') self.trough = containers.load('trough-12row', 'B2', 'trough') self.plate = containers.load('96-flat', 'A2', 'magbead') self.p200 = instruments.Pipette( name="p200", trash_container=self.trash, tip_racks=[self.tiprack], min_volume=10, # These are variable axis="b", channels=1) self.p1000 = instruments.Pipette( name="p1000", trash_container=self.trash, tip_racks=[self.tiprack], min_volume=100, # These are variable axis="a", channels=1)
def test_containers_create(self): import os import json from opentrons import Robot container_name = 'plate_for_testing_containers_create' containers.create(name=container_name, grid=(8, 12), spacing=(9, 9), diameter=4, depth=8, volume=1000) p = containers.load(container_name, 'A1') self.assertEquals(len(p), 96) self.assertEquals(len(p.rows), 12) self.assertEquals(len(p.cols), 8) self.assertEquals(p.get_parent(), Robot.get_instance().deck['A1']) self.assertEquals(p['C3'], p[18]) self.assertEquals(p['C3'].max_volume(), 1000) for i, w in enumerate(p): self.assertEquals(w, p[i]) # remove the file if we only created it for this test should_delete = False with open(environment.get_path('CONTAINERS_FILE')) as f: created_containers = json.load(f) del created_containers['containers'][p.get_name()] if not len(created_containers['containers'].keys()): should_delete = True if should_delete: os.remove(environment.get_path('CONTAINERS_FILE'))
def setUp(self): Robot.reset_for_tests() self.robot = Robot.get_instance() self.robot.connect() self.trash = containers.load('point', 'A1', 'trash') self.tiprack = containers.load('tiprack-200ul', 'B2', 'p200-rack') self.trough = containers.load('trough-12row', 'B2', 'trough') self.plate = containers.load('96-flat', 'A2', 'magbead') self.p200 = instruments.Pipette( name="p200", trash_container=self.trash, tip_racks=[self.tiprack], min_volume=10, # These are variable axis="b", channels=1 ) self.p1000 = instruments.Pipette( name="p1000", trash_container=self.trash, tip_racks=[self.tiprack], min_volume=100, # These are variable axis="a", channels=1 )
def update_step_list(): global current_protocol_step_list robot = Robot.get_instance() if current_protocol_step_list is None: create_step_list() try: for step in current_protocol_step_list: t_axis = str(step['axis']).upper() instrument = robot._instruments[t_axis] step.update({ 'top': instrument.positions['top'], 'bottom': instrument.positions['bottom'], 'blow_out': instrument.positions['blow_out'], 'drop_tip': instrument.positions['drop_tip'], 'max_volume': instrument.max_volume, 'calibrated': _check_if_instrument_calibrated(instrument) }) for placeable_step in step['placeables']: c = _get_container_from_step(placeable_step) if c: placeable_step.update( {'calibrated': _check_if_calibrated(instrument, c)}) except Exception as e: emit_notifications([str(e)], 'danger') return current_protocol_step_list
def get_unallocated_slot(self): """ :return: str name of a slot without any children (first occurence) """ robot = Robot.get_instance() for slot in robot._deck.get_children_list(): if not slot.has_children(): return slot.get_name() raise JSONProcessorRuntimeError( 'Unable to find any unallocated slots in robot deck')
def get_unallocated_slot(self): """ :return: str name of a slot without any children (first occurence) """ robot = Robot.get_instance() for slot in robot._deck.get_children_list(): if not slot.has_children(): return slot.get_name() raise JSONProcessorRuntimeError( 'Unable to find any unallocated slots in robot deck' )
def _get_all_containers(): """ Returns all containers currently on the deck """ all_containers = list() robot = Robot.get_instance() for slot in robot._deck: if slot.has_children(): all_containers += slot.get_children_list() return _sort_containers(all_containers)
def drop_tip(): robot = Robot.get_instance() try: axis = request.json.get("axis") instrument = robot._instruments[axis.upper()] instrument.return_tip(enqueue=False) except Exception as e: emit_notifications([str(e)], 'danger') return flask.jsonify({'status': 'error', 'data': str(e)}) return flask.jsonify({'status': 'success', 'data': ''})
def disconnectRobot(): status = 'success' data = None robot = Robot.get_instance() try: robot.disconnect() emit_notifications(["Successfully disconnected"], 'info') except Exception as e: status = 'error' data = str(e) emit_notifications([data], 'danger') return flask.jsonify({'status': status, 'data': data})
def test_remove_child(self): robot = Robot.get_instance() robot.reset() slot = 'B1' plate = containers.load('96-flat', slot, 'plate') self.assertEquals(len(robot.containers()), 1) plate.get_parent().remove_child(plate.get_name()) self.assertEquals(len(robot.containers()), 0) plate = containers.load('96-flat', slot, 'plate') self.assertEquals(len(robot.containers()), 1) robot.deck[slot].remove_child(plate.get_name()) self.assertEquals(len(robot.containers()), 0)
def setUp(self): self.robot = Robot.get_instance() # set this to True if testing with a robot connected # testing while connected allows the response handlers # and serial handshakes to be tested self.motor = self.robot._driver options = {"limit_switches": True, "config": {"alpha_steps_per_mm": 80.0, "beat_steps_per_mm": 80.0}} myport = self.robot.VIRTUAL_SMOOTHIE_PORT self.robot.disconnect() success = self.robot.connect(port=myport, options=options) self.assertTrue(success)
def load(container_name, slot, label=None): """ Examples -------- >>> from opentrons import containers >>> containers.load('96-flat', 'A1') <Deck>/<Slot A1>/<Container 96-flat> >>> containers.load('96-flat', 'A2', 'plate') <Deck>/<Slot A2>/<Container plate> >>> containers.load('non-existent-type', 'A2') # doctest: +ELLIPSIS Exception: Container type "non-existent-type" not found in file ... """ from opentrons import Robot if not label: label = container_name protocol = Robot.get_instance() return protocol.add_container(container_name, slot, label)
def jog(): robot = Robot.get_instance() coords = request.json status = 'success' result = '' try: if coords.get("a") or coords.get("b"): result = robot._driver.move_plunger(mode="relative", **coords) else: result = robot.move_head(mode="relative", **coords) except Exception as e: result = str(e) status = 'error' emit_notifications([result], 'danger') return flask.jsonify({'status': status, 'data': result})
def setUp(self): Robot.reset_for_tests() self.robot = Robot.get_instance() self.robot.connect() self.plate = containers.load('96-flat', 'A1', 'plate') self.p200 = instruments.Pipette(name="p200", axis="b") self.p200.delete_calibration_data() well = self.plate[0] pos = well.from_center(x=0, y=0, z=0, reference=self.plate) self.location = (self.plate, pos) well_deck_coordinates = well.center(well.get_deck()) dest = well_deck_coordinates + Vector(1, 2, 3) self.robot.move_head(x=dest['x'], y=dest['y'], z=dest['z']) self.p200.calibrate_position(self.location)
def setUp(self): self.robot = Robot.get_instance() # set this to True if testing with a robot connected # testing while connected allows the response handlers # and serial handshakes to be tested options = { 'firmware': 'edge-1c222d9NOMSD', 'limit_switches': True, 'config': { 'alpha_steps_per_mm': 80.0, 'beta_steps_per_mm': 80.0 } } self.robot.disconnect() self.robot.connect(options=options) self.motor = self.robot._driver
def connectRobot(): port = request.json.get('port') options = request.json.get('options', {'limit_switches': False}) status = 'success' data = None robot = Robot.get_instance() try: robot.connect(port, options=options) except Exception as e: # any robot version incompatibility will be caught here robot.disconnect() status = 'error' data = str(e) if "versions are incompatible" in data: data += ". To upgrade, go to docs.opentrons.com" emit_notifications([data], 'danger') return flask.jsonify({'status': status, 'data': data})
def _calibrate_placeable(container_name, parent_slot, axis_name): robot = Robot.get_instance() deck = robot._deck this_container = deck[parent_slot].get_child_by_name(container_name) axis_name = axis_name.upper() if not this_container: raise ValueError('Container {0} not found in slot {1}'.format( container_name, parent_slot)) if axis_name not in robot._instruments: raise ValueError('Axis {} is not initialized'.format(axis_name)) instrument = robot._instruments[axis_name] well = this_container[0] pos = well.from_center(x=0, y=0, z=-1, reference=this_container) location = (this_container, pos) instrument.calibrate_position(location) return instrument.calibration_data
def move_to_container(): robot = Robot.get_instance() slot = request.json.get("slot") name = request.json.get("label") axis = request.json.get("axis") try: instrument = robot._instruments[axis.upper()] container = robot._deck[slot].get_child_by_name(name) well_x, well_y, well_z = tuple( instrument.calibrator.convert(container[0], container[0].bottom()[1])) _, _, robot_max_z = robot._driver.get_dimensions() # move to max Z to avoid collisions while calibrating robot.move_head(z=robot_max_z) robot.move_head(x=well_x, y=well_y) robot.move_head(z=well_z) except Exception as e: emit_notifications([str(e)], 'danger') return flask.jsonify({'status': 'error', 'data': str(e)}) return flask.jsonify({'status': 'success', 'data': ''})
def move_to_slot(): robot = Robot.get_instance() status = 'success' result = '' try: slot = request.json.get("slot") slot = robot._deck[slot] slot_x, slot_y, _ = slot.from_center(x=-1, y=0, z=0, reference=robot._deck) _, _, robot_max_z = robot._driver.get_dimensions() robot.move_head(z=robot_max_z) robot.move_head(x=slot_x, y=slot_y) except Exception as e: result = str(e) status = 'error' emit_notifications([result], 'danger') return flask.jsonify({'status': status, 'data': result})
def setUp(self): self.robot = Robot.get_instance() # set this to True if testing with a robot connected # testing while connected allows the response handlers # and serial handshakes to be tested self.motor = self.robot._driver options = { 'limit_switches': True, 'config': { 'alpha_steps_per_mm': 80.0, 'beat_steps_per_mm': 80.0 } } myport = self.robot.VIRTUAL_SMOOTHIE_PORT self.robot.disconnect() success = self.robot.connect(port=myport, options=options) self.assertTrue(success)
def upload_jupyter(): global robot, filename, last_modified, current_protocol_step_list robot = Robot.get_instance() try: jupyter_robot = dill.loads(request.data) # These attributes need to be persisted from existing robot jupyter_robot._driver = robot._driver jupyter_robot.smoothie_drivers = robot.smoothie_drivers jupyter_robot.can_pop_command = robot.can_pop_command Singleton._instances[Robot] = jupyter_robot robot = jupyter_robot # Reload instrument calibrations [ instr.load_persisted_data() for _, instr in jupyter_robot.get_instruments() ] [ instr.update_calibrator() for _, instr in jupyter_robot.get_instruments() ] current_protocol_step_list = None calibrations = update_step_list() filename = 'JUPYTER UPLOAD' last_modified = dt.datetime.now().strftime('%a %b %d %Y') upload_data = { 'calibrations': calibrations, 'fileName': 'Jupyter Upload', 'lastModified': last_modified } app.logger.info('Successfully deserialized robot for jupyter upload') socketio.emit('event', {'data': upload_data, 'name': 'jupyter-upload'}) except Exception as e: app.logger.exception('Failed to properly deserialize jupyter upload') print(e) return flask.jsonify({'status': 'success', 'data': None})
def _start_connection_watcher(): robot = Robot.get_instance() connection_state_watcher, watcher_should_run = BACKGROUND_TASKS.get( 'CONNECTION_STATE_WATCHER', (None, None)) if connection_state_watcher and watcher_should_run: watcher_should_run.set() watcher_should_run = threading.Event() def watch_connection_state(should_run): while not should_run.is_set(): socketio.emit('event', { 'type': 'connection_status', 'is_connected': robot.is_connected() }) socketio.sleep(1.5) connection_state_watcher = socketio.start_background_task( watch_connection_state, (watcher_should_run)) BACKGROUND_TASKS['CONNECTION_STATE_WATCHER'] = (connection_state_watcher, watcher_should_run)
def load_python(stream): global robot robot = Robot.get_instance() code = helpers.convert_byte_stream_to_str(stream) api_response = {'errors': [], 'warnings': []} robot.reset() patched_robot, restore_patched_robot = ( helpers.get_upload_proof_robot(robot)) try: try: exec(code, globals()) except Exception as e: tb = e.__traceback__ stack_list = traceback.extract_tb(tb) _, line, name, text = stack_list[-1] if 'exec' in text: text = None raise Exception('Error in protocol file line {} : {}\n{}'.format( line, str(e), text or '')) robot = restore_patched_robot() # robot.simulate() if len(robot._commands) == 0: error = ( "This protocol does not contain any commands for the robot.") api_response['errors'] = [error] except Exception as e: app.logger.error(e) api_response['errors'] = [str(e)] finally: robot = restore_patched_robot() api_response['warnings'] = robot.get_warnings() or [] return api_response
def setUp(self): Robot.reset_for_tests() self.robot = Robot.get_instance()
def get_versions(): robot = Robot.get_instance() return flask.jsonify({'versions': robot.versions()})
def protocol(self): robot = Robot.get_instance() robot.get_serial_ports_list() robot.connect() robot.home() tiprack = containers.load( 'tiprack-200ul', # container type 'A1', # slot 'tiprack' # user-defined name ) plate = containers.load( '96-flat', 'B1', 'plate' ) trash = containers.load( 'point', 'C2', 'trash' ) trough = containers.load( 'trough-12row', 'B2', 'trough' ) p200 = instruments.Pipette( name="p200", trash_container=trash, tip_racks=[tiprack], max_volume=200, min_volume=0.5, axis="b", channels=1 ) calibration_data = """ { "b": { "blowout": 28.0, "bottom": 26.0, "droptip": 32.0, "resting": 0, "theContainers": { "plate": { "rel_x": 181.696, "rel_y": 0.700999999999965, "rel_z": 9.600999999999999, "x": 202.195, "y": 370.304, "z": 125.7 }, "tiprack": { "rel_x": 0.0, "rel_y": 0.0, "rel_z": 0.0, "x": 20.499, "y": 369.603, "z": 116.099 }, "trough": { "rel_x": 0.0, "rel_y": 0.0, "rel_z": 0.0, "x": 20.499, "y": 269.603, "z": 116.099 }, "trash": { "rel_x": 212.701, "rel_y": -200.801, "rel_z": -58.399, "x": 233.2, "y": 171.305, "z": 57.7 } }, "tip_rack_origin": "tiprack", "tip_racks": [ { "container": "tiprack" } ], "top": 13.0, "trash_container": { "container": "trash" }, "volume": 200 } } """ import_calibration_json(calibration_data, robot, True) robot.clear_commands() # distribute p200.pick_up_tip(tiprack[0]) p200.aspirate(96 * 2, trough[0]) for i in range(96): p200.dispense(2, plate[i]).touch_tip() p200.drop_tip(tiprack[0]) p200.pick_up_tip(tiprack[1]) for i in range(96): p200.aspirate(2, plate[95 - i]) p200.dispense(trough[0]) p200.drop_tip(tiprack[1])
import os from opentrons import containers from opentrons.labware import instruments from opentrons import Robot from opentrons.drivers.motor import CNCDriver from helpers.calibration import import_json_calibration robot = Robot.get_instance() robot._driver = CNCDriver() plate = containers.load("96-flat", "A2", "magbead") trash = containers.load("point", "A1", "trash") tiprack = containers.load("tiprack-200ul", "B2", "p200-rack") # tipracks need a Well height equal to the tip length for tip in tiprack: tip.properties["height"] = 80 p200 = instruments.Pipette( name="p200", trash_container=trash, tip_racks=[tiprack], max_volume=200, min_volume=0.1, # These are variable axis="b", channels=1, )
import os from opentrons import containers from opentrons.labware import instruments from opentrons import Robot from opentrons.drivers.motor import SmoothieDriver1 from helpers.calibration import import_json_calibration robot = Robot.get_instance() robot._driver = SmoothieDriver1() plate = containers.load('96-flat', 'A2', 'magbead') trash = containers.load('point', 'A1', 'trash') tiprack = containers.load('tiprack-200ul', 'B2', 'p200-rack') # tipracks need a Well height equal to the tip length for tip in tiprack: tip.properties['height'] = 80 p200 = instruments.Pipette( name="p200", trash_container=trash, tip_racks=[tiprack], max_volume=200, min_volume=0.1, # These are variable axis="b", channels=1) json_file_path = os.path.join(os.path.dirname(__file__),
def get_coordinates(): robot = Robot.get_instance() return flask.jsonify( {'coords': robot._driver.get_position().get("target")})
def setUp(self): Robot.reset_for_tests() self.robot = Robot.get_instance() self.robot.connect() self.protocol = None
def diagnostics(): robot = Robot.get_instance() return flask.jsonify({'diagnostics': robot.diagnostics()})