1
- from opentrons .types import Point
2
1
from opentrons import protocol_api
2
+ from opentrons .types import Point
3
3
from opentrons .drivers .rpi_drivers import gpio
4
4
import time
5
5
import math
6
- import json
7
6
import os
7
+ import subprocess
8
+ import json
8
9
9
10
# Metadata
10
11
metadata = {
11
- 'protocolName' : 'S3 Station A Protocol 1 buffer Version 1' ,
12
+ 'protocolName' : 'Calibration check for S3 Station A Protocol 1 buffer Version 1' ,
12
13
13
14
'source' : 'Custom Protocol Request' ,
14
15
'apiLevel' : '2.3'
23
24
DESTINATION_LABWARE = 'opentrons plastic 2ml tubes'
24
25
DEST_TUBE = '2ml tubes'
25
26
VOLUME_BUFFER = 300
27
+ LANGUAGE = 'esp'
28
+ RESET_TIPCOUNT = False
26
29
27
30
# End Parameters to adapt the protocol
28
31
67
70
'2ml tubes' : 4
68
71
}
69
72
73
+ LANGUAGE_DICT = {
74
+ 'esp' : 'esp' ,
75
+ 'eng' : 'eng'
76
+ }
77
+
78
+ if LANGUAGE_DICT [LANGUAGE ] == 'eng' :
79
+ VOICE_FILES_DICT = {
80
+ 'start' : './data/sounds/started_process.mp3' ,
81
+ 'finish' : './data/sounds/finished_process.mp3' ,
82
+ 'close_door' : './data/sounds/close_door.mp3' ,
83
+ 'replace_tipracks' : './data/sounds/replace_tipracks.mp3' ,
84
+ 'empty_trash' : './data/sounds/empty_trash.mp3'
85
+ }
86
+ elif LANGUAGE_DICT [LANGUAGE ] == 'esp' :
87
+ VOICE_FILES_DICT = {
88
+ 'start' : './data/sounds/started_process_esp.mp3' ,
89
+ 'finish' : './data/sounds/finished_process_esp.mp3' ,
90
+ 'close_door' : './data/sounds/close_door_esp.mp3' ,
91
+ 'replace_tipracks' : './data/sounds/replace_tipracks_esp.mp3' ,
92
+ 'empty_trash' : './data/sounds/empty_trash_esp.mp3'
93
+ }
94
+
70
95
# Function definitions
71
96
def check_door ():
72
97
return gpio .read_window_switches ()
73
98
74
99
def confirm_door_is_closed ():
75
- #Check if door is opened
76
- if check_door () == False :
77
- #Set light color to red and pause
78
- gpio .set_button_light (1 ,0 ,0 )
79
- robot .pause (f"Please, close the door" )
80
- time .sleep (3 )
81
- confirm_door_is_closed ()
82
- else :
83
- #Set light color to green
84
- gpio .set_button_light (0 ,1 ,1 )
100
+ if not robot .is_simulating ():
101
+ #Check if door is opened
102
+ if check_door () == False :
103
+ #Set light color to red and pause
104
+ gpio .set_button_light (1 ,0 ,0 )
105
+ robot .pause ()
106
+ voice_notification ('close_door' )
107
+ time .sleep (5 )
108
+ confirm_door_is_closed ()
109
+ else :
110
+ #Set light color to green
111
+ gpio .set_button_light (0 ,1 ,0 )
85
112
86
113
def finish_run ():
114
+ voice_notification ('finish' )
87
115
#Set light color to blue
88
116
gpio .set_button_light (0 ,0 ,1 )
89
117
118
+ def voice_notification (action ):
119
+ if not robot .is_simulating ():
120
+ fname = VOICE_FILES_DICT [action ]
121
+ if os .path .isfile (fname ) is True :
122
+ subprocess .run (
123
+ ['mpg123' , fname ],
124
+ stdout = subprocess .PIPE ,
125
+ stderr = subprocess .PIPE
126
+ )
127
+ else :
128
+ robot .comment (f"Sound file does not exist. Call the technician" )
129
+
130
+ def reset_tipcount ():
131
+ os .remove ('/data/A/tip_log.json' , 'w' )
90
132
91
133
def retrieve_tip_info (pip ,tipracks ,file_path = '/data/A/tip_log.json' ):
92
134
global tip_log
93
135
if not tip_log ['count' ] or pip not in tip_log ['count' ]:
136
+ tip_log ['count' ][pip ] = 0
94
137
if not robot .is_simulating ():
95
138
if os .path .isfile (file_path ):
96
139
with open (file_path ) as json_file :
@@ -99,12 +142,8 @@ def retrieve_tip_info(pip,tipracks,file_path = '/data/A/tip_log.json'):
99
142
tip_log ['count' ][pip ] = data ['tips1000' ]
100
143
elif 'P300' in str (pip ):
101
144
tip_log ['count' ][pip ] = data ['tips300' ]
102
- else :
103
- tip_log ['count' ][pip ] = 0
104
- else :
105
- tip_log ['count' ][pip ] = 0
106
- else :
107
- tip_log ['count' ][pip ] = 0
145
+ elif 'P20' in str (pip ):
146
+ tip_log ['count' ][pip ] = data ['tips20' ]
108
147
109
148
if "8-Channel" in str (pip ):
110
149
tip_log ['tips' ][pip ] = [tip for rack in tipracks for tip in rack .rows ()[0 ]]
@@ -118,12 +157,15 @@ def retrieve_tip_info(pip,tipracks,file_path = '/data/A/tip_log.json'):
118
157
def save_tip_info (file_path = '/data/A/tip_log.json' ):
119
158
data = {}
120
159
if not robot .is_simulating ():
121
- os .rename (file_path ,file_path + ".bak" )
160
+ if os .path .isfile (file_path ):
161
+ os .rename (file_path ,file_path + ".bak" )
122
162
for pip in tip_log ['count' ]:
123
163
if "P1000" in str (pip ):
124
164
data ['tips1000' ] = tip_log ['count' ][pip ]
125
165
elif "P300" in str (pip ):
126
166
data ['tips300' ] = tip_log ['count' ][pip ]
167
+ elif "P20" in str (pip ):
168
+ data ['tips20' ] = tip_log ['count' ][pip ]
127
169
128
170
with open (file_path , 'a+' ) as outfile :
129
171
json .dump (data , outfile )
@@ -135,21 +177,27 @@ def pick_up(pip,tiprack):
135
177
tip_log = {}
136
178
tip_log = retrieve_tip_info (pip ,tiprack )
137
179
if tip_log ['count' ][pip ] == tip_log ['max' ][pip ]:
180
+ voice_notification ('replace_tipracks' )
138
181
robot .pause ('Replace ' + str (pip .max_volume ) + 'µl tipracks before \
139
182
resuming.' )
183
+ confirm_door_is_closed ()
140
184
pip .reset_tipracks ()
141
185
tip_log ['count' ][pip ] = 0
142
186
pip .pick_up_tip (tip_log ['tips' ][pip ][tip_log ['count' ][pip ]])
143
187
tip_log ['count' ][pip ] += 1
144
188
145
189
def drop (pip ):
146
190
global switch
147
- side = 1 if switch else - 1
148
- drop_loc = robot .loaded_labwares [12 ].wells ()[0 ].top ().move (Point (x = side * 20 ))
149
- pip .drop_tip (drop_loc ,home_after = False )
150
- switch = not switch
191
+ if "8-Channel" not in str (pip ):
192
+ side = 1 if switch else - 1
193
+ drop_loc = robot .loaded_labwares [12 ].wells ()[0 ].top ().move (Point (x = side * 20 ))
194
+ pip .drop_tip (drop_loc ,home_after = False )
195
+ switch = not switch
196
+ else :
197
+ drop_loc = robot .loaded_labwares [12 ].wells ()[0 ].top ().move (Point (x = 20 ))
198
+ pip .drop_tip (drop_loc ,home_after = False )
151
199
152
- def transfer_buffer (bf_tube , dests , volume , pip ,tiprack ):
200
+ def transfer_buffer (bf_tube , dests , pip ,tiprack ):
153
201
max_trans_per_asp = 3 # 1000/VOLUME_BUFFER = 3
154
202
split_ind = [ind for ind in range (0 , len (dests ), max_trans_per_asp )]
155
203
dest_sets = [dests [split_ind [i ]:split_ind [i + 1 ]]
@@ -167,16 +215,17 @@ def transfer_buffer(bf_tube, dests, volume, pip,tiprack):
167
215
def run (ctx : protocol_api .ProtocolContext ):
168
216
global robot
169
217
robot = ctx
170
- # confirm door is close
171
- if not ctx .is_simulating ():
172
- confirm_door_is_closed ()
218
+
219
+ # check if tipcount is being reset
220
+ if RESET_TIPCOUNT :
221
+ reset_tipcount ()
173
222
174
223
# define tips
175
- tips1000 = [ctx .load_labware ('opentrons_96_filtertiprack_1000ul' ,
224
+ tips1000 = [robot .load_labware ('opentrons_96_filtertiprack_1000ul' ,
176
225
3 , '1000µl tiprack' )]
177
226
178
227
# define pipettes
179
- p1000 = ctx .load_instrument ('p1000_single_gen2' , 'left' , tip_racks = tips1000 )
228
+ p1000 = robot .load_instrument ('p1000_single_gen2' , 'left' , tip_racks = tips1000 )
180
229
181
230
182
231
# check buffer labware type
@@ -185,7 +234,7 @@ def run(ctx: protocol_api.ProtocolContext):
185
234
following:\n opentrons plastic 50ml tubes' )
186
235
187
236
# load mastermix labware
188
- buffer_rack = ctx .load_labware (
237
+ buffer_rack = robot .load_labware (
189
238
BUFFER_LW_DICT [BUFFER_LABWARE ], '10' ,
190
239
BUFFER_LABWARE )
191
240
@@ -196,30 +245,36 @@ def run(ctx: protocol_api.ProtocolContext):
196
245
197
246
# load elution labware
198
247
dest_racks = [
199
- ctx .load_labware (DESTINATION_LW_DICT [DESTINATION_LABWARE ], slot ,
248
+ robot .load_labware (DESTINATION_LW_DICT [DESTINATION_LABWARE ], slot ,
200
249
'Destination tubes labware ' + str (i + 1 ))
201
250
for i , slot in enumerate (['4' , '1' , '5' , '2' ])
202
251
]
203
252
204
253
# setup sample sources and destinations
205
254
bf_tubes = buffer_rack .wells ()[:4 ]
206
255
number_racks = math .ceil (NUM_SAMPLES / len (dest_racks [0 ].wells ()))
256
+ dests = [
257
+ tube
258
+ for rack in dest_racks
259
+ for tube in rack .wells ()
260
+ ]
207
261
208
- # dest_sets is a list of lists. Each list is the destination well for each rack
209
- # example: [[tube1,tube2,...tube24](first rack),[tube1,tube2(second rack),...]
210
- dest_sets = [
211
- [tube
212
- for rack in dest_racks
213
- for tube in rack .wells ()
214
- ][:NUM_SAMPLES ][i * len (dest_racks [0 ].wells ()):(i + 1 )* len (dest_racks [0 ].wells ())]
215
- for i in range (number_racks )
216
- ]
262
+ # check top-left and bottom-right well of each labware with each pipette which uses them
263
+ pick_up (p1000 , tips1000 )
264
+ for position in [bf_tubes [0 ], bf_tubes [- 1 ]]:
265
+ p1000 .move_to (position .top ())
266
+ robot .pause (f"Is it at the top of the well?" )
267
+ p1000 .aspirate (800 , position .bottom (2 ))
268
+ p1000 .move_to (position .top ())
269
+ robot .pause (f"Did it aspirate correctly?" )
270
+ p1000 .dispense (800 , position .top (- 20 ))
271
+ p1000 .move_to (position .top ())
272
+ robot .pause (f"Did it dispense all the liquid?" )
273
+ for position in [dests [0 ], dests [23 ], dests [24 ], dests [47 ], dests [48 ], dests [71 ], dests [72 ], dests [- 1 ]]:
274
+ p1000 .move_to (position .top ())
275
+ robot .pause (f"Is it at the top of the well?" )
276
+ drop (p1000 )
217
277
218
- # transfer buffer to tubes
219
- for bf_tube ,dests in zip (bf_tubes ,dest_sets ):
220
- transfer_buffer (bf_tube , dests ,VOLUME_BUFFER , p1000 , tips1000 )
221
278
222
279
# track final used tip
223
280
save_tip_info ()
224
-
225
- finish_run ()
0 commit comments