Skip to content

Commit

Permalink
Merge branch 'release/1.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
MiguelJulia committed May 20, 2020
2 parents 46bc491 + 48c0d31 commit fbd16f9
Show file tree
Hide file tree
Showing 80 changed files with 4,377 additions and 5,426 deletions.
30 changes: 30 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## Version 1.4
Documentation:
- Added user manual in spanish and english.
- Added how to ethernet connect your robot.
- Added how to calibrate.
- Added ssh connection guide.

New features:
- Voice messages language optional (spanish and english)
- Added tip count reset option.
- Added calibration scripts checking for all protocols.
- Now beads dilution is optional in protocol 2 station A. #b2b5444
- Only pause for empty trash if samples > 48 in protocol B. #406c79a
- Added json generation with run info in each protocol. This will be used for api connection with openrobots web.
- New labware configuration for ecogen deep well, added to station A and B protocols.

Protocol modifications:
- Now incubation time in protocol B is 7 minutes.
- Reduced height in beads mix in protocol 2 station A, as it was taking some air sometimes. #53789ad
- Increased height in beads mix in protocol 1 station B, as it was too close to the bottom.
- Increased height in aspirates on on the plate above the magdeck, as it was sometimes touching the bottom.
- Protocol now B starts with magdeck off. #6031d94
- Fixed issue where m300 would go too deep and not aspire correctly in elution buffer. #40410be
- Fixed issue where m300 would not aspirate correctly in all wells in supernatant removal, washes an elution when magnet is engaged. Aspiration height is increase to 1.5.

Bug fixes:
- Fixed tip not dropping tip in p300 (protocol C) #9280ae8
- Fixed correct pick up and drop tip for correct tip count for negative control (protocol C) #3483d15
- Fixed correct drop tip for p300 (protocol C) #2e6cca7
- Fixed tip count issue when only one pipette is used. #80b9567
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from opentrons.types import Point
from opentrons import protocol_api
from opentrons.types import Point
from opentrons.drivers.rpi_drivers import gpio
import time
import math
import json
import os
import subprocess
import json

# Metadata
metadata = {
'protocolName': 'S3 Station A Protocol 1 buffer Version 1',
'protocolName': 'Calibration check for S3 Station A Protocol 1 buffer Version 1',
'author': 'Sara <smonzon@isciii.es>, Miguel <mjuliam@isciii.es>',
'source': 'Custom Protocol Request',
'apiLevel': '2.3'
Expand All @@ -23,6 +24,8 @@
DESTINATION_LABWARE = 'opentrons plastic 2ml tubes'
DEST_TUBE = '2ml tubes'
VOLUME_BUFFER = 300
LANGUAGE = 'esp'
RESET_TIPCOUNT = False

# End Parameters to adapt the protocol

Expand Down Expand Up @@ -67,30 +70,70 @@
'2ml tubes': 4
}

LANGUAGE_DICT = {
'esp': 'esp',
'eng': 'eng'
}

if LANGUAGE_DICT[LANGUAGE] == 'eng':
VOICE_FILES_DICT = {
'start': './data/sounds/started_process.mp3',
'finish': './data/sounds/finished_process.mp3',
'close_door': './data/sounds/close_door.mp3',
'replace_tipracks': './data/sounds/replace_tipracks.mp3',
'empty_trash': './data/sounds/empty_trash.mp3'
}
elif LANGUAGE_DICT[LANGUAGE] == 'esp':
VOICE_FILES_DICT = {
'start': './data/sounds/started_process_esp.mp3',
'finish': './data/sounds/finished_process_esp.mp3',
'close_door': './data/sounds/close_door_esp.mp3',
'replace_tipracks': './data/sounds/replace_tipracks_esp.mp3',
'empty_trash': './data/sounds/empty_trash_esp.mp3'
}

# Function definitions
def check_door():
return gpio.read_window_switches()

def confirm_door_is_closed():
#Check if door is opened
if check_door() == False:
#Set light color to red and pause
gpio.set_button_light(1,0,0)
robot.pause(f"Please, close the door")
time.sleep(3)
confirm_door_is_closed()
else:
#Set light color to green
gpio.set_button_light(0,1,1)
if not robot.is_simulating():
#Check if door is opened
if check_door() == False:
#Set light color to red and pause
gpio.set_button_light(1,0,0)
robot.pause()
voice_notification('close_door')
time.sleep(5)
confirm_door_is_closed()
else:
#Set light color to green
gpio.set_button_light(0,1,0)

def finish_run():
voice_notification('finish')
#Set light color to blue
gpio.set_button_light(0,0,1)

def voice_notification(action):
if not robot.is_simulating():
fname = VOICE_FILES_DICT[action]
if os.path.isfile(fname) is True:
subprocess.run(
['mpg123', fname],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
else:
robot.comment(f"Sound file does not exist. Call the technician")

def reset_tipcount():
os.remove('/data/A/tip_log.json', 'w')

def retrieve_tip_info(pip,tipracks,file_path = '/data/A/tip_log.json'):
global tip_log
if not tip_log['count'] or pip not in tip_log['count']:
tip_log['count'][pip] = 0
if not robot.is_simulating():
if os.path.isfile(file_path):
with open(file_path) as json_file:
Expand All @@ -99,12 +142,8 @@ def retrieve_tip_info(pip,tipracks,file_path = '/data/A/tip_log.json'):
tip_log['count'][pip] = data['tips1000']
elif 'P300' in str(pip):
tip_log['count'][pip] = data['tips300']
else:
tip_log['count'][pip] = 0
else:
tip_log['count'][pip] = 0
else:
tip_log['count'][pip] = 0
elif 'P20' in str(pip):
tip_log['count'][pip] = data['tips20']

if "8-Channel" in str(pip):
tip_log['tips'][pip] = [tip for rack in tipracks for tip in rack.rows()[0]]
Expand All @@ -118,12 +157,15 @@ def retrieve_tip_info(pip,tipracks,file_path = '/data/A/tip_log.json'):
def save_tip_info(file_path = '/data/A/tip_log.json'):
data = {}
if not robot.is_simulating():
os.rename(file_path,file_path + ".bak")
if os.path.isfile(file_path):
os.rename(file_path,file_path + ".bak")
for pip in tip_log['count']:
if "P1000" in str(pip):
data['tips1000'] = tip_log['count'][pip]
elif "P300" in str(pip):
data['tips300'] = tip_log['count'][pip]
elif "P20" in str(pip):
data['tips20'] = tip_log['count'][pip]

with open(file_path, 'a+') as outfile:
json.dump(data, outfile)
Expand All @@ -135,21 +177,27 @@ def pick_up(pip,tiprack):
tip_log = {}
tip_log = retrieve_tip_info(pip,tiprack)
if tip_log['count'][pip] == tip_log['max'][pip]:
voice_notification('replace_tipracks')
robot.pause('Replace ' + str(pip.max_volume) + 'µl tipracks before \
resuming.')
confirm_door_is_closed()
pip.reset_tipracks()
tip_log['count'][pip] = 0
pip.pick_up_tip(tip_log['tips'][pip][tip_log['count'][pip]])
tip_log['count'][pip] += 1

def drop(pip):
global switch
side = 1 if switch else -1
drop_loc = robot.loaded_labwares[12].wells()[0].top().move(Point(x=side*20))
pip.drop_tip(drop_loc,home_after=False)
switch = not switch
if "8-Channel" not in str(pip):
side = 1 if switch else -1
drop_loc = robot.loaded_labwares[12].wells()[0].top().move(Point(x=side*20))
pip.drop_tip(drop_loc,home_after=False)
switch = not switch
else:
drop_loc = robot.loaded_labwares[12].wells()[0].top().move(Point(x=20))
pip.drop_tip(drop_loc,home_after=False)

def transfer_buffer(bf_tube, dests, volume, pip,tiprack):
def transfer_buffer(bf_tube, dests, pip,tiprack):
max_trans_per_asp = 3 # 1000/VOLUME_BUFFER = 3
split_ind = [ind for ind in range(0, len(dests), max_trans_per_asp)]
dest_sets = [dests[split_ind[i]:split_ind[i+1]]
Expand All @@ -167,16 +215,17 @@ def transfer_buffer(bf_tube, dests, volume, pip,tiprack):
def run(ctx: protocol_api.ProtocolContext):
global robot
robot = ctx
# confirm door is close
if not ctx.is_simulating():
confirm_door_is_closed()

# check if tipcount is being reset
if RESET_TIPCOUNT:
reset_tipcount()

# define tips
tips1000 = [ctx.load_labware('opentrons_96_filtertiprack_1000ul',
tips1000 = [robot.load_labware('opentrons_96_filtertiprack_1000ul',
3, '1000µl tiprack')]

# define pipettes
p1000 = ctx.load_instrument('p1000_single_gen2', 'left', tip_racks=tips1000)
p1000 = robot.load_instrument('p1000_single_gen2', 'left', tip_racks=tips1000)


# check buffer labware type
Expand All @@ -185,7 +234,7 @@ def run(ctx: protocol_api.ProtocolContext):
following:\nopentrons plastic 50ml tubes')

# load mastermix labware
buffer_rack = ctx.load_labware(
buffer_rack = robot.load_labware(
BUFFER_LW_DICT[BUFFER_LABWARE], '10',
BUFFER_LABWARE)

Expand All @@ -196,30 +245,36 @@ def run(ctx: protocol_api.ProtocolContext):

# load elution labware
dest_racks = [
ctx.load_labware(DESTINATION_LW_DICT[DESTINATION_LABWARE], slot,
robot.load_labware(DESTINATION_LW_DICT[DESTINATION_LABWARE], slot,
'Destination tubes labware ' + str(i+1))
for i, slot in enumerate(['4', '1', '5', '2'])
]

# setup sample sources and destinations
bf_tubes = buffer_rack.wells()[:4]
number_racks = math.ceil(NUM_SAMPLES/len(dest_racks[0].wells()))
dests = [
tube
for rack in dest_racks
for tube in rack.wells()
]

# dest_sets is a list of lists. Each list is the destination well for each rack
# example: [[tube1,tube2,...tube24](first rack),[tube1,tube2(second rack),...]
dest_sets = [
[tube
for rack in dest_racks
for tube in rack.wells()
][:NUM_SAMPLES][i*len(dest_racks[0].wells()):(i+1)*len(dest_racks[0].wells())]
for i in range(number_racks)
]
# check top-left and bottom-right well of each labware with each pipette which uses them
pick_up(p1000, tips1000)
for position in [bf_tubes[0], bf_tubes[-1]]:
p1000.move_to(position.top())
robot.pause(f"Is it at the top of the well?")
p1000.aspirate(800, position.bottom(2))
p1000.move_to(position.top())
robot.pause(f"Did it aspirate correctly?")
p1000.dispense(800, position.top(-20))
p1000.move_to(position.top())
robot.pause(f"Did it dispense all the liquid?")
for position in [dests[0], dests[23], dests[24], dests[47], dests[48], dests[71], dests[72], dests[-1]]:
p1000.move_to(position.top())
robot.pause(f"Is it at the top of the well?")
drop(p1000)

# transfer buffer to tubes
for bf_tube,dests in zip(bf_tubes,dest_sets):
transfer_buffer(bf_tube, dests,VOLUME_BUFFER, p1000, tips1000)

# track final used tip
save_tip_info()

finish_run()
Loading

0 comments on commit fbd16f9

Please sign in to comment.