如何实现Opentrons移液高度计算公式遍历数值列表?
解决Opentrons移液体积列表的高度追踪报错问题
问题背景
我定义了计算试管剩余溶液高度的公式,希望让吸头随移液后的剩余量自动下降。单个体积移液时功能正常,但传入数值列表时持续报错。
报错信息
ValueError [line 76]: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
原代码
from opentrons import protocol_api import math import numpy as np # metadata metadata = { 'protocolName': '2.27.23 - Highthroughput synthesis of Cs3Sb2X9', 'apiLevel': '2.13'} def run(protocol: protocol_api.ProtocolContext): #labware right_tiprack= protocol.load_labware('opentrons_96_tiprack_300ul', '1') left_tiprack= protocol.load_labware('opentrons_96_tiprack_20ul','5') left_tiprack_two= protocol.load_labware('opentrons_96_tiprack_20ul','4') tuberack= protocol.load_labware('opentrons_15_tuberack_nest_15ml_conical','8') #plates Cs_OPA_plate= protocol.load_labware('corning_96_wellplate_360ul_flat', '6') final_two_plate = protocol.load_labware('corning_96_wellplate_360ul_flat', '3') temp_mod = protocol.load_module('temperature module', '9') final_one_plate = temp_mod.load_labware('corning_96_wellplate_360ul_flat') temp_mod.set_temperature(70) # Volume to transfer from each well #Depth of tube 117.50 mm #diameter of tube 14.90 mm Sb = tuberack.wells_by_name()['A1'] tol = tuberack.wells_by_name()['B1'] Cs = tuberack.wells_by_name()['C1'] #Change to the amount of solution using in mL volume_of_sb_tube_in_ml: float = 2 volume_of_tol_tube_in_ml:float= 13 Volume_of_Cs_tube_in_ml: float = 1 #pipette right_pipette = protocol.load_instrument('p300_single_gen2', 'right', tip_racks=[right_tiprack]) left_pipette= protocol.load_instrument('p20_multi_gen2','left',tip_racks=[left_tiprack,left_tiprack_two]) # calculation of 15 ml tube intiial heights def calc_initial_15(vol): dh = -(15.9- vol)*1000/(math.pi*(7.45**2))- 8 return dh Sb_intial= calc_initial_15(volume_of_sb_tube_in_ml) Toluene_initial= calc_initial_15(volume_of_tol_tube_in_ml) Cs_initial= calc_initial_15(Volume_of_Cs_tube_in_ml) heights = { 'Sb':Sb_intial, 'tol': Toluene_initial, 'Cs': Cs_initial } #Def for all, mix step for dilution, dilution, lower pipette for mixing, change for distrubute pick up/drop tip, def height_track15_tol(reagent): nonlocal heights dh = [vol/(math.pi*(7.45**2)) for vol in volume_amount] dh=np.array(dh) if heights[reagent] - dh < -116: heights[reagent] = -116 else: heights[reagent] -= dh for well_name_tol in ['B1','C1','D1','E1','F1','G1','H1']: volume_amount= np.array([150,225,263,282,290,295,297]) height_track15_tol('tol') h = heights['tol'] right_pipette.pick_up_tip() right_pipette.transfer([150,225,263,282,290,295,297], tol.top(h), [Cs_OPA_plate.wells_by_name()[well_name_tol]], new_tip='never', touch_tip= True) right_pipette.drop_tip()
问题分析
- 数组真值判断歧义:
height_track15_tol函数中,heights[reagent]是单个浮点数,dh是numpy数组,两者相减得到数组后直接用< -116判断,Python无法确定是要判断数组中所有元素还是任意元素满足条件,因此报错。 - 循环逻辑错误:每次循环都重新定义
volume_amount为完整数组,且处理后heights['tol']会变成数组,而Opentrons的top()方法只接受单个数值作为高度参数,后续移液操作会失效。 - 移液逻辑不匹配:单个吸头一次只能移液一个体积值,传入列表的方式不符合
p300_single_gen2的操作逻辑。
修正方案
调整为逐个处理每个移液体积,确保高度始终是单个浮点数,同时匹配单通道移液器的操作逻辑:
from opentrons import protocol_api import math import numpy as np # metadata metadata = { 'protocolName': '2.27.23 - Highthroughput synthesis of Cs3Sb2X9', 'apiLevel': '2.13'} def run(protocol: protocol_api.ProtocolContext): #labware right_tiprack= protocol.load_labware('opentrons_96_tiprack_300ul', '1') left_tiprack= protocol.load_labware('opentrons_96_tiprack_20ul','5') left_tiprack_two= protocol.load_labware('opentrons_96_tiprack_20ul','4') tuberack= protocol.load_labware('opentrons_15_tuberack_nest_15ml_conical','8') #plates Cs_OPA_plate= protocol.load_labware('corning_96_wellplate_360ul_flat', '6') final_two_plate = protocol.load_labware('corning_96_wellplate_360ul_flat', '3') temp_mod = protocol.load_module('temperature module', '9') final_one_plate = temp_mod.load_labware('corning_96_wellplate_360ul_flat') temp_mod.set_temperature(70) # Volume to transfer from each well #Depth of tube 117.50 mm #diameter of tube 14.90 mm Sb = tuberack.wells_by_name()['A1'] tol = tuberack.wells_by_name()['B1'] Cs = tuberack.wells_by_name()['C1'] #Change to the amount of solution using in mL volume_of_sb_tube_in_ml: float = 2 volume_of_tol_tube_in_ml:float= 13 Volume_of_Cs_tube_in_ml: float = 1 #pipette right_pipette = protocol.load_instrument('p300_single_gen2', 'right', tip_racks=[right_tiprack]) left_pipette= protocol.load_instrument('p20_multi_gen2','left',tip_racks=[left_tiprack,left_tiprack_two]) # calculation of 15 ml tube initial heights def calc_initial_15(vol): # 转换为微升计算,减去底部8mm的死区 dh = -(15.9 - vol)*1000/(math.pi*(7.45**2)) - 8 return dh Sb_intial= calc_initial_15(volume_of_sb_tube_in_ml) Toluene_initial= calc_initial_15(volume_of_tol_tube_in_ml) Cs_initial= calc_initial_15(Volume_of_Cs_tube_in_ml) heights = { 'Sb':Sb_intial, 'tol': Toluene_initial, 'Cs': Cs_initial } # 追踪15ml试管的液面高度,接收单个体积值 def update_height_15ml(reagent, transfer_vol): nonlocal heights # 计算体积对应的高度变化(微升转毫米) dh = transfer_vol/(math.pi*(7.45**2)) # 更新高度,最低到-116mm(避免吸头碰到管底) new_height = heights[reagent] - dh heights[reagent] = max(new_height, -116) # 定义体积列表和对应的孔位 volume_list = [150,225,263,282,290,295,297] well_list = ['B1','C1','D1','E1','F1','G1','H1'] # 逐个处理移液操作 for vol, well_name in zip(volume_list, well_list): update_height_15ml('tol', vol) current_height = heights['tol'] right_pipette.pick_up_tip() right_pipette.transfer(vol, tol.top(current_height), Cs_OPA_plate.wells_by_name()[well_name], new_tip='never', touch_tip=True) right_pipette.drop_tip()
关键修改点
- 将
height_track15_tol改为update_height_15ml,接收单个移液体积,处理单个数值计算,避免数组操作 - 用
zip配对体积列表和孔位列表,逐个执行移液,符合单通道移液器的操作逻辑 - 使用
max(new_height, -116)替代条件判断,简化高度限制逻辑,确保高度始终是单个浮点数 - 移除冗余的数组定义,让代码逻辑更清晰
内容的提问来源于stack exchange,提问作者Sheryl Sanchez
相关产品推荐
相关产品推荐

