-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathpolybot_coating_experiment.py
230 lines (201 loc) · 7.91 KB
/
polybot_coating_experiment.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# add descriptions for the location of the solvents
# Final goal: create a thin film with polymer_A (that exists in the rack) and a prompt with polymer B that doesn't
import loca # location information
import pandas as pd
import robotics as ro
from robotics import procedure as proc
from robotics.workflow.fields import ( # noqa: F401
Name,
Number,
Speed,
Temperature,
Time,
Volume,
)
# fmt: off
ro.runtime['rack_status'] = {
'vial': pd.DataFrame(
[
# A 6x8 rack, top-left corner is at index [0,0]
# e.g., 'NaCl' is at index [0,1] of the rack
# 'None' means empty, 'False' means do not use (keep empty).
['water_gap', 'NaCl', None, None, None, None, None, None],
[False, None, 'polymer_A', None, None, None, None, None],
[False, None, None, 'carbon_black', None, None, None, None],
[None, None, False, None, None, None, None, None],
[None, None, False, None, None, None, None, None],
[None, None, None, None, None, None, None, None],
]
),
'substrate': pd.DataFrame(
[
# A 12x6 rack, 'new' means new, unused substrate
['new', 'new', 'new', 'new', 'new', 'new'],
['new', 'new', 'new', 'new', 'new', 'new'],
['new', 'new', 'new', 'new', 'new', 'new'],
['new', 'new', 'new', 'new', 'new', 'new'],
['new', 'new', 'new', 'new', 'new', 'new'],
['new', 'new', 'new', 'new', 'new', 'new'],
['new', 'new', 'new', 'new', 'new', 'new'],
['new', 'new', 'new', 'new', 'new', 'new'],
['new', 'new', 'new', 'new', 'new', 'new'],
['new', 'new', 'new', 'new', 'new', 'new'],
['new', 'new', 'new', 'new', 'new', 'new'],
['new', 'new', 'new', 'new', 'new', 'new'],
]
),
}
# fmt: on
# --------------------------------------------------------------
# hardware modules
c9 = ro.system.init('controller') # N9 robot controller
t8 = ro.system.init('temperature') # temperature controller
coater = ro.system.init('coater') # coating station
camera = ro.system.init('camera') # camera at the coating stationo
# The N9 robot arm has one linear motor 'z' for vertial movement
# along the z-axis. It also has two rotational motors
# 'shoulder' and 'elbow', and together they control the x- and y-
# positioning of the arm.
# --------------------------------------------------------------
# initialize the experimemntal workflow
wf = ro.workflow.init(__file__, name="Film Coating Experiment")
# --------------------------------------------------------------
# Functions decorated by @ro.workflow.register are part of the
# experimental workflow. They are executed in order.
# smp means 'sample', it is a Python dictionary-like object.
# smp must be passed as the first argument in every workflow function.
@ro.workflow.register(workflow=wf)
def init_system(smp):
"""Initialize the system"""
ro.reload(loca)
ro.system.reset()
coater.clean_blade(clean_time=3, scratch_time=10)
@ro.workflow.register(workflow=wf)
def prepare_substrate(smp):
"""place a new substrate on the coating station"""
# prepare up a new substrate for coating
c9.tool = 'substrate_tool' # pick up the bernoulli substrate gripper tool
index = proc.find_rack_index(
'substrate', 'new'
) # the next available substrate
c9.position = {
'loc': loca.substrate_rack_seq[index],
'vel': 5000,
'accel': 5000,
} # seq means a sequence of movements
c9.set_output(
'substrate_tool', True
) # turn on the substrate gripper vacuum
ro.runtime['rack_status']['substrate'].iloc[index] = 'last_used'
c9.position = {
'loc': loca.s_coater,
'vel': 5000,
'accel': 5000,
} # move substrate to coating station at a lower speed and acceleration
c9.set_output('coater_stage_vacuum', True)
c9.set_output('substrate_tool', False)
c9.tool = None # drop off the tool in the gripper
# take a picture of the substrate
img_name, img = camera.take_image(
'substrate.jpg',
focus=35,
crop=[0, 900, 600, 1550],
name_only=False,
)
smp['raw_outputs'][camera.outkey][
'substrate'
] = img # add image to the sample dictionary
smp.save() # save data to file
@ro.workflow.register(workflow=wf)
def coating_on_top(
smp,
# fmt: off
sol_label: str = Name(
'Name of the coating solution',
choices=[
'NaCl',
'carbon_black',
'polymer_A',
],
),
V: float = Volume(
'Volume of coating solution (mL)',
constant=True, default=0.003,
),
vel: float = Speed(
'Coating velocity (mm/sec)',
ge=0.5, le=2, step=0.1, default=1,
# ge means great than or equal
# le means less than or equal
# step is the increment
),
T: float = Temperature(
'Coating temperature (Celcius)',
ge=50, le=180, step=10, default=50,
),
# fmt: on
):
"""Film coating"""
# set the coating temperature
t8.set_temp(1, T)
# move solution from the vial rack to the clamp
vial_index = proc.find_rack_index('vial', sol_label)
c9.position = loca.vial_rack[vial_index] # move robot arm to the solution
c9.set_output('gripper', True) # close the robot arm gripper
c9.position = loca.clamp # move robot arm to the clamp
c9.set_output('clamp', True) # close the clamp
c9.set_output('gripper', False) # open the robot arm gripper
# aspirate the solution in the clamp
proc.new_pipette(c9) # get a new pipette
c9.position = loca.clamp
c9.set_output('gripper', True)
c9.uncap(pitch=1.75, revs=3.0, vel=5000, accel=5000) # uncap the vial
uncap_position = c9.position # record the position
c9.position = loca.p_clamp # move pipette to the clamp, inside the vial
c9.aspirate_ml(0, V) # first argument is the pump ID
c9.move_axis(
'z', c9.position[3] - 9000, vel=15000
) # quickly move up by 9 cm
c9.position = uncap_position # move gripper back to the recorded position
c9.cap(pitch=1.75, revs=3.0, torque_thresh=1000, vel=5000, accel=5000)
c9.set_output('gripper', False)
c9.move_axis(
'z', c9.position[3] - 5000, vel=15000
) # quickly move up by 5 cm
# dispense solution
coater.position = 45 # move coater blade to the starting position
c9.position = loca.p_coater # move pipette to the coating station
c9.dispense_ml(0, V) # first argument is the pump ID
c9.move_axis('z', 0) # move robot arm all the way up
coater.velocity = vel # set the coating velocity
coater.position = 75 # move blade all the way to the right
proc.remove_pipette(c9)
# record image data of the film
img_name, img = camera.take_image(
'coated_film.jpg',
focus=35,
crop=[0, 900, 600, 1550],
name_only=False,
)
smp['raw_outputs'][camera.outkey][
'coated_film'
] = img # add image to the sample dictionary
smp.save() # save data to file
# return solution in clamp back to the vial rack
c9.position = loca.clamp # move robot arm to the clamp
c9.set_output('gripper', True) # close the robot arm gripper
c9.set_output('clamp', False) # close the clamp
c9.position = loca.vial_rack[vial_index] # move robot arm to the solution
c9.set_output('gripper', False) # open the robot arm gripper
@ro.workflow.register(workflow=wf)
def store_sample(smp):
"""Return sample to rack, end of experiment"""
c9.tool = 'substrate_tool'
c9.position = loca.s_coater
c9.set_output('substrate_tool', True)
c9.set_output('coater_stage_vacuum', False)
index = proc.find_rack_index('substrate', 'last_used')
c9.position = loca.substrate_rack_seq[index]
c9.set_output('substrate_tool', False)
ro.runtime['rack_status']['substrate'].iloc[index] = 'used'
c9.tool = None