-
Notifications
You must be signed in to change notification settings - Fork 38
Prcxi9320 #204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prcxi9320 #204
Conversation
* Cleanup registry to be easy-understanding (deepmodeling#76) * delete deprecated mock devices * rename categories * combine chromatographic devices * rename rviz simulation nodes * organic virtual devices * parse vessel_id * run registry completion before merge --------- Co-authored-by: Xuwznln <18435084+Xuwznln@users.noreply.github.com> * fix: workstation handlers and vessel_id parsing * fix: working dir error when input config path feat: report publish topic when error * modify default discovery_interval to 15s * feat: add trace log level * feat: 添加ChinWe设备控制类,支持串口通信和电机控制功能 (deepmodeling#79) * fix: drop_tips not using auto resource select * fix: discard_tips error * fix: discard_tips * fix: prcxi_res * add: prcxi res fix: startup slow * feat: workstation example * fix pumps and liquid_handler handle * feat: 优化protocol node节点运行日志 * fix all protocol_compilers and remove deprecated devices * feat: 新增use_remote_resource参数 * fix and remove redundant info * bugfixes on organic protocols * fix filter protocol * fix protocol node * 临时兼容错误的driver写法 * fix: prcxi import error * use call_async in all service to avoid deadlock * fix: figure_resource * Update recipe.yaml * add workstation template and battery example * feat: add sk & ak * update workstation base * Create workstation_architecture.md * refactor: workstation_base 重构为仅含业务逻辑,通信和子设备管理交给 ProtocolNode * refactor: ProtocolNode→WorkstationNode * Add:msgs.action (deepmodeling#83) * update: Workstation dev 将版本号从 0.10.3 更新为 0.10.4 (deepmodeling#84) * Add:msgs.action * update: 将版本号从 0.10.3 更新为 0.10.4 * simplify resource system * uncompleted refactor * example for use WorkstationBase * feat: websocket * feat: websocket test * feat: workstation example * feat: action status * fix: station自己的方法注册错误 * fix: 还原protocol node处理方法 * fix: build * fix: missing job_id key * ws test version 1 * ws test version 2 * ws protocol * 增加物料关系上传日志 * 增加物料关系上传日志 * 修正物料关系上传 * 修复工站的tracker实例追踪失效问题 * 增加handle检测,增加material edge关系上传 * 修复event loop错误 * 修复edge上报错误 * 修复async错误 * 更新schema的title字段 * 主机节点信息等支持自动刷新 * 注册表编辑器 * 修复status密集发送时,消息出错 * 增加addr参数 * fix: addr param * fix: addr param * 取消labid 和 强制config输入 * Add action definitions for LiquidHandlerSetGroup and LiquidHandlerTransferGroup - Created LiquidHandlerSetGroup.action with fields for group name, wells, and volumes. - Created LiquidHandlerTransferGroup.action with fields for source and target group names and unit volume. - Both actions include response fields for return information and success status. * Add LiquidHandlerSetGroup and LiquidHandlerTransferGroup actions to CMakeLists * Add set_group and transfer_group methods to PRCXI9300Handler and update liquid_handler.yaml * result_info改为字典类型 * 新增uat的地址替换 * runze multiple pump support (cherry picked from commit 49354fc) * remove runze multiple software obtainer (cherry picked from commit 8bcc92a) * support multiple backbone (cherry picked from commit 4771ff2) * Update runze pump format * Correct runze multiple backbone * Update runze_multiple_backbone * Correct runze pump multiple receive method. * Correct runze pump multiple receive method. * 对于PRCXI9320的transfer_group,一对多和多对多 * 移除MQTT,更新launch文档,提供注册表示例文件,更新到0.10.5 * fix import error * fix dupe upload registry * refactor ws client * add server timeout * Fix: run-column with correct vessel id (deepmodeling#86) * fix run_column * Update run_column_protocol.py (cherry picked from commit e5aa4d9) * resource_update use resource_add * 新增版位推荐功能 * 重新规定了版位推荐的入参 * update registry with nested obj * fix protocol node log_message, added create_resource return value * fix protocol node log_message, added create_resource return value * try fix add protocol * fix resource_add * 修复移液站错误的aspirate注册表 * Feature/xprbalance-zhida (deepmodeling#80) * feat(devices): add Zhida GC/MS pretreatment automation workstation * feat(devices): add mettler_toledo xpr balance * balance * 重新补全zhida注册表 * PRCXI9320 json * PRCXI9320 json * PRCXI9320 json * fix resource download * remove class for resource * bump version to 0.10.6 * 更新所有注册表 * 修复protocolnode的兼容性 * 修复protocolnode的兼容性 * Update install md * Add Defaultlayout * 更新物料接口 * fix dict to tree/nested-dict converter * coin_cell_station draft * refactor: rename "station_resource" to "deck" * add standardized BIOYOND resources: bottle_carrier, bottle * refactor and add BIOYOND resources tests * add BIOYOND deck assignment and pass all tests * fix: update resource with correct structure; remove deprecated liquid_handler set_group action * feat: 将新威电池测试系统驱动与配置文件并入 workstation_dev_YB2 (deepmodeling#92) * feat: 新威电池测试系统驱动与注册文件 * feat: bring neware driver & battery.json into workstation_dev_YB2 * add bioyond studio draft * bioyond station with communication init and resource sync * fix bioyond station and registry * fix: update resource with correct structure; remove deprecated liquid_handler set_group action * frontend_docs * create/update resources with POST/PUT for big amount/ small amount data * create/update resources with POST/PUT for big amount/ small amount data * refactor: add itemized_carrier instead of carrier consists of ResourceHolder * create warehouse by factory func * update bioyond launch json * add child_size for itemized_carrier * fix bioyond resource io * Workstation templates: Resources and its CRUD, and workstation tasks (deepmodeling#95) * coin_cell_station draft * refactor: rename "station_resource" to "deck" * add standardized BIOYOND resources: bottle_carrier, bottle * refactor and add BIOYOND resources tests * add BIOYOND deck assignment and pass all tests * fix: update resource with correct structure; remove deprecated liquid_handler set_group action * feat: 将新威电池测试系统驱动与配置文件并入 workstation_dev_YB2 (deepmodeling#92) * feat: 新威电池测试系统驱动与注册文件 * feat: bring neware driver & battery.json into workstation_dev_YB2 * add bioyond studio draft * bioyond station with communication init and resource sync * fix bioyond station and registry * create/update resources with POST/PUT for big amount/ small amount data * refactor: add itemized_carrier instead of carrier consists of ResourceHolder * create warehouse by factory func * update bioyond launch json * add child_size for itemized_carrier * fix bioyond resource io --------- Co-authored-by: h840473807 <47357934+h840473807@users.noreply.github.com> Co-authored-by: Xie Qiming <97236197+Andy6M@users.noreply.github.com> * 更新物料接口 * Workstation dev yb2 (deepmodeling#100) * Refactor and extend reaction station action messages * Refactor dispensing station tasks to enhance parameter clarity and add batch processing capabilities - Updated `create_90_10_vial_feeding_task` to include detailed parameters for 90%/10% vial feeding, improving clarity and usability. - Introduced `create_batch_90_10_vial_feeding_task` for batch processing of 90%/10% vial feeding tasks with JSON formatted input. - Added `create_batch_diamine_solution_task` for batch preparation of diamine solution, also utilizing JSON formatted input. - Refined `create_diamine_solution_task` to include additional parameters for better task configuration. - Enhanced schema descriptions and default values for improved user guidance. * 修复to_plr_resources * add update remove * 支持选择器注册表自动生成 支持转运物料 * 修复资源添加 * 修复transfer_resource_to_another生成 * 更新transfer_resource_to_another参数,支持spot入参 * 新增test_resource动作 * fix host_node error * fix host_node test_resource error * fix host_node test_resource error * 过滤本地动作 * 移动内部action以兼容host node * 修复同步任务报错不显示的bug * feat: 允许返回非本节点物料,后面可以通过decoration进行区分,就不进行warning了 * update todo * modify bioyond/plr converter, bioyond resource registry, and tests * pass the tests * update todo * add conda-pack-build.yml * add auto install script for conda-pack-build.yml (cherry picked from commit 172599a) * update conda-pack-build.yml * update conda-pack-build.yml * update conda-pack-build.yml * update conda-pack-build.yml * update conda-pack-build.yml * Add version in __init__.py Update conda-pack-build.yml Add create_zip_archive.py * Update conda-pack-build.yml * Update conda-pack-build.yml (with mamba) * Update conda-pack-build.yml * Fix FileNotFoundError * Try fix 'charmap' codec can't encode characters in position 16-23: character maps to <undefined> * Fix unilabos msgs search error * Fix environment_check.py * Update recipe.yaml * Update registry. Update uuid loop figure method. Update install docs. * Fix nested conda pack * Fix one-key installation path error * Bump version to 0.10.7 * Workshop bj (deepmodeling#99) * Add LaiYu Liquid device integration and tests Introduce LaiYu Liquid device implementation, including backend, controllers, drivers, configuration, and resource files. Add hardware connection, tip pickup, and simplified test scripts, as well as experiment and registry configuration for LaiYu Liquid. Documentation and .gitignore for the device are also included. * feat(LaiYu_Liquid): 重构设备模块结构并添加硬件文档 refactor: 重新组织LaiYu_Liquid模块目录结构 docs: 添加SOPA移液器和步进电机控制指令文档 fix: 修正设备配置中的最大体积默认值 test: 新增工作台配置测试用例 chore: 删除过时的测试脚本和配置文件 * add * 重构: 将 LaiYu_Liquid.py 重命名为 laiyu_liquid_main.py 并更新所有导入引用 - 使用 git mv 将 LaiYu_Liquid.py 重命名为 laiyu_liquid_main.py - 更新所有相关文件中的导入引用 - 保持代码功能不变,仅改善命名一致性 - 测试确认所有导入正常工作 * 修复: 在 core/__init__.py 中添加 LaiYuLiquidBackend 导出 - 添加 LaiYuLiquidBackend 到导入列表 - 添加 LaiYuLiquidBackend 到 __all__ 导出列表 - 确保所有主要类都可以正确导入 * 修复大小写文件夹名字 * 电池装配工站二次开发教程(带目录)上传至dev (deepmodeling#94) * 电池装配工站二次开发教程 * Update intro.md * 物料教程 * 更新物料教程,json格式注释 * Update prcxi driver & fix transfer_liquid mix_times (deepmodeling#90) * Update prcxi driver & fix transfer_liquid mix_times * fix: correct mix_times type * Update liquid_handler registry * test: prcxi.py * Update registry from pr * fix ony-key script not exist * clean files --------- Co-authored-by: Junhan Chang <changjh@dp.tech> Co-authored-by: ZiWei <131428629+ZiWei09@users.noreply.github.com> Co-authored-by: Guangxin Zhang <guangxin.zhang.bio@gmail.com> Co-authored-by: Xie Qiming <97236197+Andy6M@users.noreply.github.com> Co-authored-by: h840473807 <47357934+h840473807@users.noreply.github.com> Co-authored-by: LccLink <1951855008@qq.com> Co-authored-by: lixinyu1011 <61094742+lixinyu1011@users.noreply.github.com> Co-authored-by: shiyubo0410 <shiyubo@dp.tech>
add auto install during one-key installation
…lidation aliases (deepmodeling#104) Co-authored-by: ZiWei <131428629+ZiWei09@users.noreply.github.com>
Install conda-pack before pack command Add conda-pack to base when building one-key installer Fix param error when using mamba run Try fix one-key build on linux
Update registry
* Fix ResourceTreeSet load error * Raise error when using unsupported type to create ResourceTreeSet * Fix children key error * Fix children key error * Fix workstation resource not tracking * Fix workstation deck & children resource dupe * Fix workstation deck & children resource dupe * Fix multiple resource error * Fix resource tree update * Fix resource tree update * Force confirm uuid * Tip more error log * Refactor Bioyond workstation and experiment workflow (deepmodeling#105) Refactored the Bioyond workstation classes to improve parameter handling and workflow management. Updated experiment.py to use BioyondReactionStation with deck and material mappings, and enhanced workflow step parameter mapping and execution logic. Adjusted JSON experiment configs, improved workflow sequence handling, and added UUID assignment to PLR materials. Removed unused station_config and material cache logic, and added detailed docstrings and debug output for workflow methods. * Fix resource get. Fix resource parent not found. Mapping uuid for all resources. * mount parent uuid * Add logging configuration based on BasicConfig in main function * fix workstation node error * fix workstation node error * Update boot example * temp fix for resource get * temp fix for resource get * provide error info when cant find plr type * pack repo info * fix to plr type error * fix to plr type error * Update regular container method * support no size init * fix comprehensive_station.json * fix comprehensive_station.json * fix type conversion * fix state loading for regular container * Update deploy-docs.yml * Update deploy-docs.yml --------- Co-authored-by: ZiWei <131428629+ZiWei09@users.noreply.github.com>
Update doc url.
* cancel upload_registry * Refactor Bioyond workstation and experiment workflow -fix (deepmodeling#111) * refactor(bioyond_studio): 优化材料缓存加载和参数验证逻辑 改进材料缓存加载逻辑以支持多种材料类型和详细材料处理 更新工作流参数验证中的字段名从key/value改为Key/DisplayValue 移除未使用的merge_workflow_with_parameters方法 添加get_station_info方法获取工作站基础信息 清理实验文件中的注释代码和更新导入路径 * fix: 修复资源移除时的父资源检查问题 在BaseROS2DeviceNode中,移除资源前添加对父资源是否为None的检查,避免空指针异常 同时更新Bottle和BottleCarrier类以支持**kwargs参数 修正测试文件中Liquid_feeding_beaker的大小写拼写错误 * correct return message --------- Co-authored-by: ZiWei <131428629+ZiWei09@users.noreply.github.com>
在创建任务后清空工作流序列和参数,防止下次执行时累积重复
add more enumeration in POSE fix converter in resource_tracker
fix(reaction_station): 为步骤参数添加Value字段传个BY后端 fix(bioyond/warehouses): 修正仓库尺寸和物品排列参数 调整仓库的x轴和z轴物品数量以及物品尺寸参数,使其符合4x1x4的规格要求 fix warehouse serialize/deserialize fix bioyond converter fix itemized_carrier.unassign_child_resource allow not-loaded MSG in registry add layout serializer & converter warehouseuse A1-D4; add warehouse layout fix(graphio): 修正bioyond到plr资源转换中的坐标计算错误 Fix resource assignment and type mapping issues Corrects resource assignment in ItemizedCarrier by using the correct spot key from _ordering. Updates graphio to use 'typeName' instead of 'name' for type mapping in resource_bioyond_to_plr. Renames DummyWorkstation to BioyondWorkstation in workstation_http_service for clarity.
Refine descriptions in Bioyond reaction station YAML Updated and clarified field and operation descriptions in the reaction_station_bioyond.yaml file for improved accuracy and consistency. Changes include more precise terminology, clearer parameter explanations, and standardized formatting for operation schemas. refactor(workstation): 更新反应站参数描述并添加分液站配置文件 修正反应站方法参数描述,使其更准确清晰 添加bioyond_dispensing_station.yaml配置文件 add create_workflow script and test add invisible_slots to carriers fix(warehouses): 修正bioyond_warehouse_1x4x4仓库的尺寸参数 调整仓库的num_items_x和num_items_z值以匹配实际布局,并更新物品尺寸参数 save resource get data. allow empty value for layout and cross_section_type More decks&plates support for bioyond (deepmodeling#115) refactor(registry): 重构反应站设备配置,简化并更新操作命令 移除旧的自动操作命令,新增针对具体化学操作的命令配置 更新模块路径和配置结构,优化参数定义和描述 fix(dispensing_station): 修正物料信息查询方法调用 将直接调用material_id_query改为通过hardware_interface调用,以符合接口设计规范
修改prcxi连线 prcxi样例图 Create example_prcxi.json
use ordering to convert identifier to idx convert identifier to site idx correct extra key update extra before transfer fix multiple instance error add resource_tree_transfer func fox itemrized carrier assign child resource support internal device material transfer remove extra key use same callback group support material extra support material extra support update_resource_site in extra
modify workstation_architecture docs bioyond_HR (deepmodeling#133) * feat: Enhance Bioyond synchronization and resource management - Implemented synchronization for all material types (consumables, samples, reagents) from Bioyond, logging detailed information for each type. - Improved error handling and logging during synchronization processes. - Added functionality to save Bioyond material IDs in UniLab resources for future updates. - Enhanced the `sync_to_external` method to handle material movements correctly, including querying and creating materials in Bioyond. - Updated warehouse configurations to support new storage types and improved layout for better resource management. - Introduced new resource types such as reactors and tip boxes, with detailed specifications. - Modified warehouse factory to support column offsets for naming conventions (e.g., A05-D08). - Improved resource tracking by merging extra attributes instead of overwriting them. - Added a new method for updating resources in Bioyond, ensuring better synchronization of resource changes. * feat: 添加TipBox和Reactor的配置到bottles.yaml * fix: 修复液体投料方法中的volume参数处理逻辑 修复solid_feeding_vials方法中的volume参数处理逻辑,优化solvents参数的使用条件 更新液体投料方法,支持通过溶剂信息自动计算体积,添加solvents参数并更新文档描述 Add batch creation methods for vial and solution tasks 添加批量创建90%10%小瓶投料任务和二胺溶液配置任务的功能,更新相关参数和默认值
correct bioyond config prcxi example fix append_resource fix regularcontainer fix cancel error fix resource_get param fix json dumps support name change during materials change enable slave mode change uuid logger to trace level correct remove_resource stats disable slave connect websocket adjust with_children param modify devices to use correct executor (sleep, create_task) support sleep and create_task in node fix run async execution error
update registry
* change 9320 desk row number to 4 * Updated 9320 host address * Updated 9320 host address * Add **kwargs in classes: PRCXI9300Deck and PRCXI9300Container * Removed all sample_id in prcxi_9320.json to avoid KeyError * 9320 machine testing settings * Typo * Rewrite setup logic to clear error code * 初始化 step_mode 属性
* 宜宾奔耀工站deck前端by_Xinyu * 构建物料教程byxinyu * 1114物料手册定义教程
* 修改lh的json启动 * 修改lh的json启动 * 修改backend,做成sim的通用backend * 修改yaml的地址,3D模型适配网页生产环境 * 添加laiyu硬件连接 * 修改移液枪的状态判断方法, 修改移液枪的状态判断方法, 添加三轴的表定点与零点之间的转换 添加三轴真实移动的backend * 修改laiyu移液站 简化移动方法, 取消软件限制位置, 修改当值使用Z轴时也需要重新复位Z轴的问题 * 更新lh以及laiyu workshop 1,现在可以直接通过修改backend,适配其他的移液站,主类依旧使用LiquidHandler,不用重新编写 2,修改枪头判断标准,使用枪头自身判断而不是类的判断, 3,将归零参数用毫米计算,方便手动调整, 4,修改归零方式,上电使用机械归零,确定机械零点,手动归零设置工作区域零点方便计算,二者互不干涉 * 修改枪头动作 * 修改虚拟仿真方法 --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: Junhan Chang <changjh@dp.tech>
* change 9320 desk row number to 4 * Updated 9320 host address * Updated 9320 host address * Add **kwargs in classes: PRCXI9300Deck and PRCXI9300Container * Removed all sample_id in prcxi_9320.json to avoid KeyError * 9320 machine testing settings * Typo * Typo in base_device_node.py * Enhance liquid handling functionality by adding support for multiple transfer modes (one-to-many, one-to-one, many-to-one) and improving parameter validation. Default channel usage is set when not specified. Adjusted mixing logic to ensure it only occurs when valid conditions are met. Updated documentation for clarity.
Resource dict fully change to "pose" key Update oss link Reduce pylabrobot conversion warning & force enable log dump. 更新 logo 图片
print all logs to file fix resource dict dump error
Reviewer's GuideExtends PRCXI 9320/9300 liquid handler capabilities and resource handling by adding heater/shaker/move-plate commands, propagating sample UUIDs through aspiration/dispense and ROS actions, adjusting schemas and coordinate handling, adding axis selection for left/right channels on PRCXI9300, and updating pose/position handling while cleaning up unused Laiyu liquid device code and one bioyond transfer action. Sequence diagram for aspirate/dispense sample tracking and result packagingsequenceDiagram
actor User
participant HostNode
participant BaseDeviceNode
participant LiquidHandlerAbstract
participant LiquidHandlerMiddleware
participant Backend as PRCXIBackend
participant TypeCheck as TypeCheckUtil
User->>HostNode: request liquid_handler aspirate
HostNode->>HostNode: assign_sample_id(action_kwargs)
HostNode->>BaseDeviceNode: send_goal(action_id, goal_msg)
BaseDeviceNode->>BaseDeviceNode: ACTION wrapper resolves resources
BaseDeviceNode->>BaseDeviceNode: query resources from bridge
BaseDeviceNode->>BaseDeviceNode: figure_resource() and copy unilabos_extra.sample_uuid
BaseDeviceNode->>LiquidHandlerAbstract: aspirate(resources, vols, use_channels,...)
LiquidHandlerAbstract->>LiquidHandlerMiddleware: aspirate(resources, vols, use_channels,...)
LiquidHandlerMiddleware->>Backend: aspirate(ops, use_channels,...)
Backend-->>LiquidHandlerMiddleware: low level hardware steps
LiquidHandlerMiddleware->>LiquidHandlerMiddleware: build res_samples and res_volumes
LiquidHandlerMiddleware->>LiquidHandlerMiddleware: pending_liquids_dict[channel] = sample_uuid, volume
LiquidHandlerMiddleware-->>LiquidHandlerAbstract: SimpleReturn(samples, volumes)
LiquidHandlerAbstract-->>BaseDeviceNode: SimpleReturn(samples, volumes)
BaseDeviceNode-->>HostNode: result_value(SimpleReturn)
HostNode-->>User: result_info_str
activate TypeCheck
User->>TypeCheck: get_result_info_str(error, suc, return_value)
TypeCheck->>TypeCheck: if return_value is dict and has samples
TypeCheck->>TypeCheck: samples = return_value.pop(samples)
TypeCheck-->>User: json{error, suc, return_value, samples}
deactivate TypeCheck
User->>HostNode: later dispense call
HostNode->>BaseDeviceNode: send_goal for dispense
BaseDeviceNode->>LiquidHandlerAbstract: dispense(resources, vols, use_channels,...)
LiquidHandlerAbstract->>LiquidHandlerMiddleware: dispense(resources, vols, use_channels,...)
LiquidHandlerMiddleware->>Backend: dispense(ops, use_channels,...)
Backend-->>LiquidHandlerMiddleware: low level dispense steps
LiquidHandlerMiddleware->>LiquidHandlerMiddleware: propagate pending_liquids_dict[channel] to target wells
LiquidHandlerMiddleware-->>LiquidHandlerAbstract: SimpleReturn(samples, volumes)
LiquidHandlerAbstract-->>BaseDeviceNode: SimpleReturn(samples, volumes)
BaseDeviceNode-->>HostNode: result_value(SimpleReturn)
HostNode-->>User: json with samples via get_result_info_str
Class diagram for updated liquid handler middleware, abstract handler, and PRCXI9300 backendclassDiagram
class SimpleReturn {
+list samples
+list volumes
}
class LiquidHandlerBackend {
<<abstract>>
}
class LiquidHandler {
}
class LiquidHandlerMiddleware {
+bool _simulator
+int channel_num
+dict pending_liquids_dict
+LiquidHandlerBackend _backend
+LiquidHandler _simulate_handler
+Deck deck
+__init__(backend: LiquidHandlerBackend, deck: Deck, simulator: bool, channel_num: int, joint_config)
+async drop_tips(tip_spots, use_channels, offsets, allow_nonzero_volume, backend_kwargs)
+async discard_tips(use_channels, allow_nonzero_volume, offsets, backend_kwargs)
+async aspirate(resources, vols, use_channels, offsets, flow_rates, use_anti_droplet, blow_out_air_volume, spread, backend_kwargs) SimpleReturn
+async dispense(resources, vols, use_channels, offsets, flow_rates, use_anti_droplet, blow_out_air_volume, spread, backend_kwargs) SimpleReturn
}
class LiquidHandlerAbstract {
+bool support_pick_up_tip
+bool support_drop_tips
+bool support_touch_tip
+BaseROS2DeviceNode _ros_node
+dict group_info
+__init__(backend: LiquidHandlerBackend|dict, deck: Deck, simulator: bool, channel_num: int, total_height: float)
+post_init(ros_node: BaseROS2DeviceNode)
+set_liquid(wells: list~Well~, liquid_names: list~str~, volumes: list~float~) SimpleReturn
}
class PRCXI9320Device {
+__init__(backend: LiquidHandlerBackend, deck: Deck, simulator: bool, channel_num: int, is_9320: bool)
+post_init(ros_node: BaseROS2DeviceNode)
+set_liquid(wells: list~Well~, liquid_names: list~str~, volumes: list~float~) SimpleReturn
+async move_to(well: Well, dis_to_top: float, channel: int)
+async shaker_action(time: int, module_no: int, amplitude: int, is_wait: bool)
+async heater_action(temperature: float, time: int)
+async move_plate(plate: Plate, to: Resource, intermediate_locations: list~Coordinate~, pickup_offset: Coordinate, destination_offset: Coordinate, drop_direction: GripDirection, pickup_direction: GripDirection, pickup_distance_from_top: float, backend_kwargs)
}
class PRCXI9300Backend {
+bool debug
+int _num_channels
+object _execute_setup
+str axis
+list steps_todo_list
+__init__(deck: Deck, simulation: bool, setup, port: str, channel_num: int, debug: bool)
+async shaker_action(time: int, module_no: int, amplitude: int, is_wait: bool)
+async pick_up_resource(pickup: ResourcePickup, backend_kwargs)
+async drop_resource(drop: ResourceDrop, backend_kwargs)
+async heater_action(temperature: float, time: int)
+run_protocol() bool
+async setup()
+async stop()
+async pick_up_tips(ops: list~Pickup~, use_channels: list~int~)
+async drop_tips(ops: list~Drop~, use_channels: list~int~)
+async mix(targets, vols, mix_liquid_height, mix_times, mix_vol, mix_rate, mix_stage, none_keys)
+async aspirate(ops: list~SingleChannelAspiration~, use_channels: list~int~)
+async dispense(ops: list~SingleChannelDispense~, use_channels: list~int~)
+async move_picked_up_resource(move: ResourceMove)
}
class PRCXI9300ApiClient {
+start() bool
+wait_for_finish() bool
+Load(dosage: int, plate_no: int, is_whole_plate: bool, hole_col: int, hole_row: int, balance_height: int, plate_or_hole_num: str, assist_fun1: str, assist_fun2: str, assist_fun3: str, assist_fun4: str, assist_fun5: str, liquid_method: str, axis: str) dict
+Imbibing(dosage: int, plate_no: int, is_whole_plate: bool, hole_col: int, hole_row: int, balance_height: int, plate_or_hole_num: str, assist_fun1: str, assist_fun2: str, assist_fun3: str, assist_fun4: str, assist_fun5: str, liquid_method: str, axis: str) dict
+Tapping(dosage: int, plate_no: int, is_whole_plate: bool, hole_col: int, hole_row: int, balance_height: int, plate_or_hole_num: str, assist_fun1: str, assist_fun2: str, assist_fun3: str, assist_fun4: str, assist_fun5: str, liquid_method: str, axis: str) dict
+Blending(dosage: int, plate_no: int, is_whole_plate: bool, hole_col: int, hole_row: int, balance_height: int, plate_or_hole_num: str, assist_fun1: str, assist_fun2: str, assist_fun3: str, assist_fun4: str, assist_fun5: str, liquid_method: str, axis: str) dict
+UnLoad(dosage: int, plate_no: int, is_whole_plate: bool, hole_col: int, hole_row: int, balance_height: int, plate_or_hole_num: str, assist_fun1: str, assist_fun2: str, assist_fun3: str, assist_fun4: str, assist_fun5: str, liquid_method: str, axis: str) dict
+clamp_jaw_pick_up(plate_no: int, is_whole_plate: bool, balance_height: int) dict
+clamp_jaw_drop(plate_no: int, is_whole_plate: bool, balance_height: int) dict
+shaker_action(time: int, module_no: int, amplitude: int, is_wait: bool) dict
}
LiquidHandlerMiddleware --|> LiquidHandler
LiquidHandlerAbstract --|> LiquidHandlerMiddleware
PRCXI9320Device --|> LiquidHandlerAbstract
PRCXI9300Backend ..|> LiquidHandlerBackend
PRCXI9300Backend o--> PRCXI9300ApiClient : api_client
SimpleReturn <.. LiquidHandlerMiddleware : returns
SimpleReturn <.. LiquidHandlerAbstract : returns
SimpleReturn <.. PRCXI9320Device : returns
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - I've found 5 issues, and left some high level feedback:
- In
_handle_future_exception(base_device_node.py), theelsebranch usesparent_resource(r)butris only defined inside theif isinstance(rs, list)block; this should likely beparent_resource(rs)to avoid a NameError. - The new
PRCXI9300Backend.heater_actioncurrently just prints and returns without appending a step or calling the API client (the real call is commented out), which means heater actions will be silently ignored; consider implementing it consistently withshaker_action. - In
ResourceTracker.get_resource_instance_from_dict, constructingpose['size']readscontent['config']without ensuring theconfigkey exists or is a dict, which can raise a KeyError or AttributeError for minimal resource dicts; adding a safe default or guard aroundcontent['config']would make this more robust.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `_handle_future_exception` (base_device_node.py), the `else` branch uses `parent_resource(r)` but `r` is only defined inside the `if isinstance(rs, list)` block; this should likely be `parent_resource(rs)` to avoid a NameError.
- The new `PRCXI9300Backend.heater_action` currently just prints and returns without appending a step or calling the API client (the real call is commented out), which means heater actions will be silently ignored; consider implementing it consistently with `shaker_action`.
- In `ResourceTracker.get_resource_instance_from_dict`, constructing `pose['size']` reads `content['config']` without ensuring the `config` key exists or is a dict, which can raise a KeyError or AttributeError for minimal resource dicts; adding a safe default or guard around `content['config']` would make this more robust.
## Individual Comments
### Comment 1
<location> `unilabos/devices/liquid_handling/prcxi/prcxi.py:441-450` </location>
<code_context>
+ async def shaker_action(self, time: int, module_no: int, amplitude: int, is_wait: bool):
+ return await self._unilabos_backend.shaker_action(time, module_no, amplitude, is_wait)
+
+ async def heater_action(self, temperature: float, time: int):
+ return await self._unilabos_backend.heater_action(temperature, time)
+ async def move_plate(
</code_context>
<issue_to_address>
**issue (bug_risk):** heater_action now only logs and does not invoke the backend API, which likely breaks the feature.
This should invoke the backend heater action (as `shaker_action` does with `_unilabos_backend`). If the intent is still to control the device, ensure `heater_action` calls the backend rather than only logging/returning `None`, and keep the log only as an addition if needed.
</issue_to_address>
### Comment 2
<location> `unilabos/devices/liquid_handling/liquid_handler_abstract.py:32-34` </location>
<code_context>
from unilabos.ros.nodes.base_device_node import BaseROS2DeviceNode
-
+class SimpleReturn(TypedDict):
+ samples: list
+ volumes: list
class LiquidHandlerMiddleware(LiquidHandler):
</code_context>
<issue_to_address>
**issue (bug_risk):** SimpleReturn definition and usage are inconsistent in simulator vs non-simulator paths.
`aspirate`, `dispense`, and `set_liquid` now return `SimpleReturn`, but their simulator branches still return the simulator backend’s native type. This forces callers to handle two different return shapes based on `self._simulator`. Either adapt simulator results into `SimpleReturn` as well or clearly split these APIs so callers don’t need to perform type checks on the return value.
</issue_to_address>
### Comment 3
<location> `unilabos/devices/liquid_handling/liquid_handler_abstract.py:138-140` </location>
<code_context>
tip_spots, use_channels, offsets, allow_nonzero_volume, **backend_kwargs
)
- return await super().drop_tips(tip_spots, use_channels, offsets, allow_nonzero_volume, **backend_kwargs)
+ await super().drop_tips(tip_spots, use_channels, offsets, allow_nonzero_volume, **backend_kwargs)
+ self.pending_liquids_dict = {}
+ return
async def return_tips(
</code_context>
<issue_to_address>
**issue (bug_risk):** drop_tips and discard_tips now return None for non-simulator mode, which may break callers expecting a backend result.
These methods used to return the value from `super().drop_tips` / `super().discard_tips`, but now in non-simulator mode they await the super call, clear `pending_liquids_dict`, and explicitly return `None`. Any caller depending on the returned value (even just its truthiness) will see a behavior change, and only on real hardware. Please either keep returning the super result while clearing `pending_liquids_dict`, or clearly document and propagate this behavioral change so it’s consistent across simulator and non-simulator paths.
</issue_to_address>
### Comment 4
<location> `unilabos/ros/nodes/base_device_node.py:1278-1281` </location>
<code_context>
seen = set()
unique_resources = []
for rs in akv: # todo: 这里目前只支持plr的类型
- res = self.resource_tracker.parent_resource(rs) # 获取 resource 对象
+ if isinstance(rs, list):
+ for r in rs:
+ res = self.resource_tracker.parent_resource(r) # 获取 resource 对象
+ else:
+ res = self.resource_tracker.parent_resource(r)
</code_context>
<issue_to_address>
**issue (bug_risk):** The else branch in the resource collection logic uses an undefined variable `r`.
In `_handle_future_exception`, within `for rs in akv`, `r` is only defined inside the `if isinstance(rs, list)` block. In the `else` branch, `parent_resource(r)` uses `r` even though it’s undefined there; this will raise an `UnboundLocalError` whenever `rs` is not a list. The `else` branch should use `rs` (or the loop should be restructured) so that the correct variable is passed to `parent_resource` in all cases.
</issue_to_address>
### Comment 5
<location> `unilabos/utils/type_check.py:81-85` </location>
<code_context>
JSON字符串格式的结果信息
"""
- result_info = {"error": error, "suc": suc, "return_value": return_value}
+ samples = None
+ if isinstance(return_value, dict):
+ if "samples" in return_value:
+ samples = return_value.pop("samples")
+ result_info = {"error": error, "suc": suc, "return_value": return_value, "samples": samples}
return json.dumps(result_info, ensure_ascii=False, cls=ResultInfoEncoder)
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Mutating `return_value` by popping `samples` can surprise callers that reuse the dict.
This mutates the caller’s dict: after `get_result_info_str` returns, `return_value` will no longer contain `samples`. To avoid this side effect, copy the dict first (e.g. `rv = dict(return_value)`), pop from the copy, and use that in the JSON instead of changing the original.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| async def heater_action(self, temperature: float, time: int): | ||
| return await self._unilabos_backend.heater_action(temperature, time) | ||
| async def move_plate( | ||
| self, | ||
| plate: Plate, | ||
| to: Resource, | ||
| intermediate_locations: Optional[List[Coordinate]] = None, | ||
| pickup_offset: Coordinate = Coordinate.zero(), | ||
| destination_offset: Coordinate = Coordinate.zero(), | ||
| drop_direction: GripDirection = GripDirection.FRONT, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): heater_action now only logs and does not invoke the backend API, which likely breaks the feature.
This should invoke the backend heater action (as shaker_action does with _unilabos_backend). If the intent is still to control the device, ensure heater_action calls the backend rather than only logging/returning None, and keep the log only as an addition if needed.
| class SimpleReturn(TypedDict): | ||
| samples: list | ||
| volumes: list |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): SimpleReturn definition and usage are inconsistent in simulator vs non-simulator paths.
aspirate, dispense, and set_liquid now return SimpleReturn, but their simulator branches still return the simulator backend’s native type. This forces callers to handle two different return shapes based on self._simulator. Either adapt simulator results into SimpleReturn as well or clearly split these APIs so callers don’t need to perform type checks on the return value.
| await super().drop_tips(tip_spots, use_channels, offsets, allow_nonzero_volume, **backend_kwargs) | ||
| self.pending_liquids_dict = {} | ||
| return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): drop_tips and discard_tips now return None for non-simulator mode, which may break callers expecting a backend result.
These methods used to return the value from super().drop_tips / super().discard_tips, but now in non-simulator mode they await the super call, clear pending_liquids_dict, and explicitly return None. Any caller depending on the returned value (even just its truthiness) will see a behavior change, and only on real hardware. Please either keep returning the super result while clearing pending_liquids_dict, or clearly document and propagate this behavioral change so it’s consistent across simulator and non-simulator paths.
| for rs in akv: # todo: 这里目前只支持plr的类型 | ||
| res = self.resource_tracker.parent_resource(rs) # 获取 resource 对象 | ||
| if isinstance(rs, list): | ||
| for r in rs: | ||
| res = self.resource_tracker.parent_resource(r) # 获取 resource 对象 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): The else branch in the resource collection logic uses an undefined variable r.
In _handle_future_exception, within for rs in akv, r is only defined inside the if isinstance(rs, list) block. In the else branch, parent_resource(r) uses r even though it’s undefined there; this will raise an UnboundLocalError whenever rs is not a list. The else branch should use rs (or the loop should be restructured) so that the correct variable is passed to parent_resource in all cases.
| samples = None | ||
| if isinstance(return_value, dict): | ||
| if "samples" in return_value: | ||
| samples = return_value.pop("samples") | ||
| result_info = {"error": error, "suc": suc, "return_value": return_value, "samples": samples} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (bug_risk): Mutating return_value by popping samples can surprise callers that reuse the dict.
This mutates the caller’s dict: after get_result_info_str returns, return_value will no longer contain samples. To avoid this side effect, copy the dict first (e.g. rv = dict(return_value)), pop from the copy, and use that in the JSON instead of changing the original.
|
prcix9320 |
Summary by Sourcery
Enhance liquid handling backends, resource handling, and configuration schemas while removing deprecated Laiyu liquid device implementations.
New Features:
Bug Fixes:
Enhancements:
Documentation:
Tests:
Chores: