mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2025-12-17 21:11:12 +00:00
* add biomek.py demo implementation * 更新LiquidHandlerBiomek类,添加资源创建功能,优化协议创建方法,修复部分代码格式问题,更新YAML配置以支持新功能。 * Test * fix biomek success type * Convert LH action to biomek. * Update biomek.py * 注册表上报handle和schema (param input) * 修复biomek缺少的字段 * delete 's' * Remove warnings * Update biomek.py * Biomek test * Update biomek.py * 新增transfer_biomek的msg * New transfer_biomek * Updated transfer_biomek * 更新transfer_biomek的msg * 更新transfer_biomek的msg * 支持Biomek创建 * new action * fix key name typo * New parameter for biomek to run. * Refine * Update * new actions * new actions * 1 * registry * fix biomek startup add action handles * fix handles not as default entry * biomek_test.py biomek_test.py是最新的版本,运行它会生成complete_biomek_protocol.json * Update biomek.py * biomek_test.py * fix liquid_handler.biomek handles * host node新增resource add时间统计 create_resource新增handle bump version to 0.9.2 * 修正物料上传时间 改用biomek_test 增加ResultInfoEncoder 支持返回结果上传 * 正确发送return_info结果 * 同步执行状态信息 * 取消raiseValueError提示 * Update biomek_test.py * 0608 DONE * 同步了Biomek.py 现在应可用 * biomek switch back to non-test * temp disable initialize resource * 37-biomek-i5i7 (#40) * add biomek.py demo implementation * 更新LiquidHandlerBiomek类,添加资源创建功能,优化协议创建方法,修复部分代码格式问题,更新YAML配置以支持新功能。 * Test * fix biomek success type * Convert LH action to biomek. * Update biomek.py * 注册表上报handle和schema (param input) * 修复biomek缺少的字段 * delete 's' * Remove warnings * Update biomek.py * Biomek test * Update biomek.py * 新增transfer_biomek的msg * New transfer_biomek * Updated transfer_biomek * 更新transfer_biomek的msg * 更新transfer_biomek的msg * 支持Biomek创建 * new action * fix key name typo * New parameter for biomek to run. * Refine * Update * new actions * new actions * 1 * registry * fix biomek startup add action handles * fix handles not as default entry * biomek_test.py biomek_test.py是最新的版本,运行它会生成complete_biomek_protocol.json * Update biomek.py * biomek_test.py * fix liquid_handler.biomek handles * host node新增resource add时间统计 create_resource新增handle bump version to 0.9.2 * 修正物料上传时间 改用biomek_test 增加ResultInfoEncoder 支持返回结果上传 * 正确发送return_info结果 * 同步执行状态信息 * 取消raiseValueError提示 * Update biomek_test.py * 0608 DONE * 同步了Biomek.py 现在应可用 * biomek switch back to non-test * temp disable initialize resource * Refine biomek * Refine copy issue * Refine --------- Co-authored-by: Junhan Chang <changjh@pku.edu.cn> Co-authored-by: Guangxin Zhang <guangxin.zhang.bio@gmail.com> Co-authored-by: qxw138 <qxw@stu.pku.edu.cn> * Device visualization (#39) * Update README and MQTTClient for installation instructions and code improvements * feat: 支持local_config启动 add: 增加对crt path的说明,为传入config.py的相对路径 move: web component * add: registry description * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * feat: node_info_update srv fix: OTDeck cant create * close #12 feat: slave node registry * feat: show machine name fix: host node registry not uploaded * feat: add hplc registry * feat: add hplc registry * fix: hplc status typo * fix: devices/ * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * fix: device.class possible null * fix: HPLC additions with online service * fix: slave mode spin not working * fix: slave mode spin not working * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * feat: 多ProtocolNode 允许子设备ID相同 feat: 上报发现的ActionClient feat: Host重启动,通过discover机制要求slaveNode重新注册,实现信息及时上报 * feat: 支持env设置config * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * Device visualization (#14) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: missing hostname in devices_names fix: upload_file for model file * fix: missing paho-mqtt package bump version to 0.9.0 * fix startup add ResourceCreateFromOuter.action * fix type hint * update actions * update actions * host node add_resource_from_outer fix cmake list * pass device config to device class * add: bind_parent_ids to resource create action fix: message convert string * fix: host node should not be re_discovered * feat: resource tracker support dict * feat: add more necessary params * feat: fix boolean null in registry action data * feat: add outer resource * 编写mesh添加action * feat: append resource * add action * feat: vis 2d for plr * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate * Device visualization (#22) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * 编写mesh添加action * add action * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: multi channel * fix: aspirate * fix: aspirate * fix: aspirate * fix: aspirate * 提交 * fix: jobadd * fix: jobadd * fix: msg converter * tijiao * add resource creat easy action * identify debug msg * mq client id * 提取lh的joint发布 * unify liquid_handler definition * 修改物料跟随与物料添加逻辑 修改物料跟随与物料添加逻辑 将joint_publisher类移出lh的backends,但仍需要对lh的backends进行一些改写 * Revert "修改物料跟随与物料添加逻辑" This reverts commit498c997ad7. * Reapply "修改物料跟随与物料添加逻辑" This reverts commit3a60d2ae81. * Revert "Merge remote-tracking branch 'upstream/dev' into device_visualization" This reverts commitfa727220af, reversing changes made to498c997ad7. * 修改物料放下时的方法,如果选择 修改物料放下时的方法, 如果选择drop_trash,则删除物料显示 如果选择drop,则让其解除连接 * add biomek.py demo implementation * 更新LiquidHandlerBiomek类,添加资源创建功能,优化协议创建方法,修复部分代码格式问题,更新YAML配置以支持新功能。 * Test * fix biomek success type * Convert LH action to biomek. * Update biomek.py * 注册表上报handle和schema (param input) * 修复biomek缺少的字段 * delete 's' * Remove warnings * Update biomek.py * Biomek test * Update biomek.py * 新增transfer_biomek的msg * New transfer_biomek * Updated transfer_biomek * 更新transfer_biomek的msg * 更新transfer_biomek的msg * 支持Biomek创建 * new action * fix key name typo * New parameter for biomek to run. * Refine * Update * new actions * new actions * 1 * registry * fix biomek startup add action handles * fix handles not as default entry * unilab添加moveit启动 1,整合所有moveit节点到一个move_group中,并整合所有的controller依次激活 2,添加pymoveit2的节点,使用json可直接启动 3,修改机械臂规划方式,添加约束,让冗余关节不会进行过多移动 * biomek_test.py biomek_test.py是最新的版本,运行它会生成complete_biomek_protocol.json * Update biomek.py * biomek_test.py * fix liquid_handler.biomek handles * 修改物体attach时,多次赋值当前时间导致卡顿问题, * Revert "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit56d45b94f5. * Reapply "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit07d9db20c3. * 添加缺少物料:"plate_well_G12", * host node新增resource add时间统计 create_resource新增handle bump version to 0.9.2 * 修正物料上传时间 改用biomek_test 增加ResultInfoEncoder 支持返回结果上传 * 正确发送return_info结果 * 同步执行状态信息 * 取消raiseValueError提示 * Update biomek_test.py * 0608 DONE * 同步了Biomek.py 现在应可用 * biomek switch back to non-test * temp disable initialize resource * add * fix tip resource data * liquid states * change to debug level * Revert "change to debug level" This reverts commit5d9953c3e5. * Reapply "change to debug level" This reverts commit2487bb6ffc. * fix tip resource data * add full device * add moveit yaml * 修复moveit 增加post_init阶段,给予ros_node反向 * remove necessary node * fix moveit action client * remove necessary imports * Update moveit_interface.py * fix handler_key uppercase * json add liquids * fix setup * add * change to "sources" and "targets" for lh * bump version * remove parent's parent link --------- Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: Junhan Chang <changjh@pku.edu.cn> Co-authored-by: Guangxin Zhang <guangxin.zhang.bio@gmail.com> Co-authored-by: qxw138 <qxw@stu.pku.edu.cn> * Device visualization (#41) * Update README and MQTTClient for installation instructions and code improvements * feat: 支持local_config启动 add: 增加对crt path的说明,为传入config.py的相对路径 move: web component * add: registry description * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * feat: node_info_update srv fix: OTDeck cant create * close #12 feat: slave node registry * feat: show machine name fix: host node registry not uploaded * feat: add hplc registry * feat: add hplc registry * fix: hplc status typo * fix: devices/ * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * fix: device.class possible null * fix: HPLC additions with online service * fix: slave mode spin not working * fix: slave mode spin not working * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * feat: 多ProtocolNode 允许子设备ID相同 feat: 上报发现的ActionClient feat: Host重启动,通过discover机制要求slaveNode重新注册,实现信息及时上报 * feat: 支持env设置config * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * Device visualization (#14) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: missing hostname in devices_names fix: upload_file for model file * fix: missing paho-mqtt package bump version to 0.9.0 * fix startup add ResourceCreateFromOuter.action * fix type hint * update actions * update actions * host node add_resource_from_outer fix cmake list * pass device config to device class * add: bind_parent_ids to resource create action fix: message convert string * fix: host node should not be re_discovered * feat: resource tracker support dict * feat: add more necessary params * feat: fix boolean null in registry action data * feat: add outer resource * 编写mesh添加action * feat: append resource * add action * feat: vis 2d for plr * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate * Device visualization (#22) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * 编写mesh添加action * add action * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: multi channel * fix: aspirate * fix: aspirate * fix: aspirate * fix: aspirate * 提交 * fix: jobadd * fix: jobadd * fix: msg converter * tijiao * add resource creat easy action * identify debug msg * mq client id * 提取lh的joint发布 * unify liquid_handler definition * 修改物料跟随与物料添加逻辑 修改物料跟随与物料添加逻辑 将joint_publisher类移出lh的backends,但仍需要对lh的backends进行一些改写 * Revert "修改物料跟随与物料添加逻辑" This reverts commit498c997ad7. * Reapply "修改物料跟随与物料添加逻辑" This reverts commit3a60d2ae81. * Revert "Merge remote-tracking branch 'upstream/dev' into device_visualization" This reverts commitfa727220af, reversing changes made to498c997ad7. * 修改物料放下时的方法,如果选择 修改物料放下时的方法, 如果选择drop_trash,则删除物料显示 如果选择drop,则让其解除连接 * add biomek.py demo implementation * 更新LiquidHandlerBiomek类,添加资源创建功能,优化协议创建方法,修复部分代码格式问题,更新YAML配置以支持新功能。 * Test * fix biomek success type * Convert LH action to biomek. * Update biomek.py * 注册表上报handle和schema (param input) * 修复biomek缺少的字段 * delete 's' * Remove warnings * Update biomek.py * Biomek test * Update biomek.py * 新增transfer_biomek的msg * New transfer_biomek * Updated transfer_biomek * 更新transfer_biomek的msg * 更新transfer_biomek的msg * 支持Biomek创建 * new action * fix key name typo * New parameter for biomek to run. * Refine * Update * new actions * new actions * 1 * registry * fix biomek startup add action handles * fix handles not as default entry * unilab添加moveit启动 1,整合所有moveit节点到一个move_group中,并整合所有的controller依次激活 2,添加pymoveit2的节点,使用json可直接启动 3,修改机械臂规划方式,添加约束,让冗余关节不会进行过多移动 * biomek_test.py biomek_test.py是最新的版本,运行它会生成complete_biomek_protocol.json * Update biomek.py * biomek_test.py * fix liquid_handler.biomek handles * 修改物体attach时,多次赋值当前时间导致卡顿问题, * Revert "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit56d45b94f5. * Reapply "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit07d9db20c3. * 添加缺少物料:"plate_well_G12", * host node新增resource add时间统计 create_resource新增handle bump version to 0.9.2 * 修正物料上传时间 改用biomek_test 增加ResultInfoEncoder 支持返回结果上传 * 正确发送return_info结果 * 同步执行状态信息 * 取消raiseValueError提示 * Update biomek_test.py * 0608 DONE * 同步了Biomek.py 现在应可用 * biomek switch back to non-test * temp disable initialize resource * add * fix tip resource data * liquid states * change to debug level * Revert "change to debug level" This reverts commit5d9953c3e5. * Reapply "change to debug level" This reverts commit2487bb6ffc. * fix tip resource data * add full device * add moveit yaml * 修复moveit 增加post_init阶段,给予ros_node反向 * remove necessary node * fix moveit action client * remove necessary imports * Update moveit_interface.py * fix handler_key uppercase * json add liquids * fix setup * add * change to "sources" and "targets" for lh * bump version * remove parent's parent link * change arm's name * change name --------- Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: q434343 <73513873+q434343@users.noreply.github.com> Co-authored-by: Junhan Chang <changjh@pku.edu.cn> Co-authored-by: Guangxin Zhang <guangxin.zhang.bio@gmail.com> Co-authored-by: qxw138 <qxw@stu.pku.edu.cn> * fix move it * fix move it * create_resource * bump ver modify slot type * 增加modbus支持 调整protocol node以更好支持多种类型的read和write * 调整protocol node以更好支持多种类型的read和write * 补充日志 * Device visualization (#42) * Update README and MQTTClient for installation instructions and code improvements * feat: 支持local_config启动 add: 增加对crt path的说明,为传入config.py的相对路径 move: web component * add: registry description * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * feat: node_info_update srv fix: OTDeck cant create * close #12 feat: slave node registry * feat: show machine name fix: host node registry not uploaded * feat: add hplc registry * feat: add hplc registry * fix: hplc status typo * fix: devices/ * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * fix: device.class possible null * fix: HPLC additions with online service * fix: slave mode spin not working * fix: slave mode spin not working * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * feat: 多ProtocolNode 允许子设备ID相同 feat: 上报发现的ActionClient feat: Host重启动,通过discover机制要求slaveNode重新注册,实现信息及时上报 * feat: 支持env设置config * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * Device visualization (#14) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: missing hostname in devices_names fix: upload_file for model file * fix: missing paho-mqtt package bump version to 0.9.0 * fix startup add ResourceCreateFromOuter.action * fix type hint * update actions * update actions * host node add_resource_from_outer fix cmake list * pass device config to device class * add: bind_parent_ids to resource create action fix: message convert string * fix: host node should not be re_discovered * feat: resource tracker support dict * feat: add more necessary params * feat: fix boolean null in registry action data * feat: add outer resource * 编写mesh添加action * feat: append resource * add action * feat: vis 2d for plr * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate * Device visualization (#22) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * 编写mesh添加action * add action * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: multi channel * fix: aspirate * fix: aspirate * fix: aspirate * fix: aspirate * 提交 * fix: jobadd * fix: jobadd * fix: msg converter * tijiao * add resource creat easy action * identify debug msg * mq client id * 提取lh的joint发布 * unify liquid_handler definition * 修改物料跟随与物料添加逻辑 修改物料跟随与物料添加逻辑 将joint_publisher类移出lh的backends,但仍需要对lh的backends进行一些改写 * Revert "修改物料跟随与物料添加逻辑" This reverts commit498c997ad7. * Reapply "修改物料跟随与物料添加逻辑" This reverts commit3a60d2ae81. * Revert "Merge remote-tracking branch 'upstream/dev' into device_visualization" This reverts commitfa727220af, reversing changes made to498c997ad7. * 修改物料放下时的方法,如果选择 修改物料放下时的方法, 如果选择drop_trash,则删除物料显示 如果选择drop,则让其解除连接 * unilab添加moveit启动 1,整合所有moveit节点到一个move_group中,并整合所有的controller依次激活 2,添加pymoveit2的节点,使用json可直接启动 3,修改机械臂规划方式,添加约束,让冗余关节不会进行过多移动 * 修改物体attach时,多次赋值当前时间导致卡顿问题, * Revert "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit56d45b94f5. * Reapply "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit07d9db20c3. * 添加缺少物料:"plate_well_G12", * add * fix tip resource data * liquid states * change to debug level * Revert "change to debug level" This reverts commit5d9953c3e5. * Reapply "change to debug level" This reverts commit2487bb6ffc. * fix tip resource data * add full device * add moveit yaml * 修复moveit 增加post_init阶段,给予ros_node反向 * remove necessary node * fix moveit action client * remove necessary imports * Update moveit_interface.py * fix handler_key uppercase * json add liquids * fix setup * add * change to "sources" and "targets" for lh * bump version * remove parent's parent link * change arm's name * change name * fix ik error --------- Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: q434343 <73513873+q434343@users.noreply.github.com> Co-authored-by: Junhan Chang <changjh@pku.edu.cn> * Add Mock Device for Organic Synthesis\添加有机合成的虚拟仪器和Protocol (#43) * Add Device MockChiller Add device MockChiller * Add Device MockFilter * Add Device MockPump * Add Device MockRotavap * Add Device MockSeparator * Add Device MockStirrer * Add Device MockHeater * Add Device MockVacuum * Add Device MockSolenoidValve * Add Device Mock \_init_.py * 规范模拟设备代码与注册表信息 * 更改Mock大写文件夹名 * 删除大写目录 * Edited Mock device json * Match mock device with action * Edit mock device yaml * Add new action * Add Virtual Device, Action, YAML, Protocol for Organic Syn * 单独分类测试的protocol文件夹 * 更名Action --------- Co-authored-by: Xuwznln <18435084+Xuwznln@users.noreply.github.com> * bump version & protocol fix * hotfix: Add macos_sdk_config (#46) Co-authored-by: quehh <scienceol@outlook.com> * include device_mesh when pip install * 测试自动构建 * try build fix * try build * test artifacts * hotfix: Add .certs in .gitignore * create container * container 添加和更新完成 * Device registry port (#49) * Update README and MQTTClient for installation instructions and code improvements * feat: 支持local_config启动 add: 增加对crt path的说明,为传入config.py的相对路径 move: web component * add: registry description * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * feat: node_info_update srv fix: OTDeck cant create * close #12 feat: slave node registry * feat: show machine name fix: host node registry not uploaded * feat: add hplc registry * feat: add hplc registry * fix: hplc status typo * fix: devices/ * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * fix: device.class possible null * fix: HPLC additions with online service * fix: slave mode spin not working * fix: slave mode spin not working * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * feat: 多ProtocolNode 允许子设备ID相同 feat: 上报发现的ActionClient feat: Host重启动,通过discover机制要求slaveNode重新注册,实现信息及时上报 * feat: 支持env设置config * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * Device visualization (#14) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: missing hostname in devices_names fix: upload_file for model file * fix: missing paho-mqtt package bump version to 0.9.0 * fix startup add ResourceCreateFromOuter.action * fix type hint * update actions * update actions * host node add_resource_from_outer fix cmake list * pass device config to device class * add: bind_parent_ids to resource create action fix: message convert string * fix: host node should not be re_discovered * feat: resource tracker support dict * feat: add more necessary params * feat: fix boolean null in registry action data * feat: add outer resource * 编写mesh添加action * feat: append resource * add action * feat: vis 2d for plr * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate * Device visualization (#22) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * 编写mesh添加action * add action * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: multi channel * fix: aspirate * fix: aspirate * fix: aspirate * fix: aspirate * 提交 * fix: jobadd * fix: jobadd * fix: msg converter * tijiao * add resource creat easy action * identify debug msg * mq client id * unify liquid_handler definition * Update virtual_device.yaml * 更正了stir和heater的连接方式 * 区分了虚拟仪器中的八通阀和电磁阀,添加了两个阀门的驱动 * 修改了add protocol * 修复了阀门更新版的bug * 修复了添加protocol前缀导致的不能启动的bug * Fix handles * bump version to 0.9.6 * add resource edge upload * update container registry and handles * add virtual_separator virtual_rotavap fix transfer_pump * fix container value add parent_name to edge device id * 大图的问题都修复好了,添加了gassource和vacuum pump的驱动以及注册表 * default resource upload mode is false * 添加了icon的文件名在注册表里面 * 修改了json图中link的格式 * fix resource and edge upload * fix device ports * Fix edge id * 移除device的父节点关联 * separate registry sync and resource_add * 默认不进行注册表报送,通过命令unilabos-register或者增加启动参数 * 完善tip * protocol node不再嵌套显示 * bump version to 0.9.7 新增一个测试PumpTransferProtocol的teststation,亲测可以运行,将八通阀们和转移泵与pump_protocol适配 * protocol node 执行action不应携带自身device id * 添加了一套简易双八通阀工作站JSON,亲测能跑 * 修复了很多protocol,亲测能跑 * 添加了run column和filter through的protocol,亲测能跑 * fix mock_reactor * 修改了大图和小图的json,但是在前端上没看到改变 --------- Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: q434343 <73513873+q434343@users.noreply.github.com> Co-authored-by: Junhan Chang <changjh@pku.edu.cn> * 更新workstation注册表 * 添加了两个protocol的检索功能 (#51) * 添加了两个protocol的检索liquid type功能 * fix workstation registry * 修复了没连接的几个仪器的link,添加了container的icon * 修改了json和注册表,现在大图全部的device都链接上了 * 修复了小图的json图,线全部连上了 * add work_station protocol handles (ports) * fix workstation action handle --------- Co-authored-by: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Co-authored-by: Junhan Chang <changjh@dp.tech> * 新增注册表补全功能,修复Protocol执行失败 * 支持通过导入方式补全注册表,新增工作流unilabos_device_id字段 * 修复不启用注册表补充就无法启动的bug * 修复部分识别error * 修复静态方法识别get status,注册表支持python类型 * status types对于嵌套类型返回的对象,暂时处理成字符串,无法直接进行转换 * 支持通过list[int],list[float]进行Int64MultiArray,Float64MultiArray的替换 * 成功动态导入的不再需要使用静态导入 * Fix handle names (#55) * fix handle names * improve evacuateAndRefill gas source finding * add camera and dependency (#56) * 修复auto-的Action在protocol node下错误注册 * 匹配init param schema格式 * Add channel_sources config in conda_build_config.yaml (#58) * 修复任务执行传参 * Create 5 new protocols & bump version 0.9.8 (#59) * 添加了5个缺失的protocol,验证了可以运行 * bump version to 0.9.8 * 修复新增的Action的字段缺失 --------- Co-authored-by: Xuwznln <18435084+Xuwznln@users.noreply.github.com> * 转换到ros消息时,要进行基础类型转换 * Update work_station.yaml (#60) * Update work_station.yaml * Checklist里面有XDL跟protocol之间没对齐的问题,工作量有点大找时间写完 * Create prcxi.py * Update prcxi.py * Update Prcxi * 更新中析仪器,以及启动示例 * 修改moveit_interface,并在mqtt上报时发送一个时间戳,方便网页端对数据的筛选 (#62) * Update README and MQTTClient for installation instructions and code improvements * feat: 支持local_config启动 add: 增加对crt path的说明,为传入config.py的相对路径 move: web component * add: registry description * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * feat: node_info_update srv fix: OTDeck cant create * close #12 feat: slave node registry * feat: show machine name fix: host node registry not uploaded * feat: add hplc registry * feat: add hplc registry * fix: hplc status typo * fix: devices/ * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * fix: device.class possible null * fix: HPLC additions with online service * fix: slave mode spin not working * fix: slave mode spin not working * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * feat: 多ProtocolNode 允许子设备ID相同 feat: 上报发现的ActionClient feat: Host重启动,通过discover机制要求slaveNode重新注册,实现信息及时上报 * feat: 支持env设置config * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * Device visualization (#14) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: missing hostname in devices_names fix: upload_file for model file * fix: missing paho-mqtt package bump version to 0.9.0 * fix startup add ResourceCreateFromOuter.action * fix type hint * update actions * update actions * host node add_resource_from_outer fix cmake list * pass device config to device class * add: bind_parent_ids to resource create action fix: message convert string * fix: host node should not be re_discovered * feat: resource tracker support dict * feat: add more necessary params * feat: fix boolean null in registry action data * feat: add outer resource * 编写mesh添加action * feat: append resource * add action * feat: vis 2d for plr * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate * Device visualization (#22) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * 编写mesh添加action * add action * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: multi channel * fix: aspirate * fix: aspirate * fix: aspirate * fix: aspirate * 提交 * fix: jobadd * fix: jobadd * fix: msg converter * tijiao * add resource creat easy action * identify debug msg * mq client id * 提取lh的joint发布 * unify liquid_handler definition * 修改物料跟随与物料添加逻辑 修改物料跟随与物料添加逻辑 将joint_publisher类移出lh的backends,但仍需要对lh的backends进行一些改写 * Revert "修改物料跟随与物料添加逻辑" This reverts commit498c997ad7. * Reapply "修改物料跟随与物料添加逻辑" This reverts commit3a60d2ae81. * Revert "Merge remote-tracking branch 'upstream/dev' into device_visualization" This reverts commitfa727220af, reversing changes made to498c997ad7. * 修改物料放下时的方法,如果选择 修改物料放下时的方法, 如果选择drop_trash,则删除物料显示 如果选择drop,则让其解除连接 * unilab添加moveit启动 1,整合所有moveit节点到一个move_group中,并整合所有的controller依次激活 2,添加pymoveit2的节点,使用json可直接启动 3,修改机械臂规划方式,添加约束,让冗余关节不会进行过多移动 * 修改物体attach时,多次赋值当前时间导致卡顿问题, * Revert "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit56d45b94f5. * Reapply "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit07d9db20c3. * 添加缺少物料:"plate_well_G12", * add * fix tip resource data * liquid states * change to debug level * Revert "change to debug level" This reverts commit5d9953c3e5. * Reapply "change to debug level" This reverts commit2487bb6ffc. * fix tip resource data * add full device * add moveit yaml * 修复moveit 增加post_init阶段,给予ros_node反向 * remove necessary node * fix moveit action client * remove necessary imports * Update moveit_interface.py * fix handler_key uppercase * json add liquids * fix setup * add * change to "sources" and "targets" for lh * bump version * remove parent's parent link * change arm's name * change name * fix ik error * 修改moveit_interface,并在mqtt上报时发送一个时间戳 --------- Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: Junhan Chang <changjh@pku.edu.cn> * 更新实例 * 更新实例 * 更新实例 * 修正prcxi启动 * 更新PRCXI配置,修改主机地址和设置状态,并添加示例用法 * add pickup tips for prcxi * 任意执行错误都应该返回failed * 任意执行错误都应该返回failed * Add plateT6 to PRCXI configuration and enhance error handling in liquid handling * prcxi blending * assert blending_times > 0 * update prcxi * update prcxi registry * Update prcxi.py to fit the function in unilabos. * 不生成已配置action的动作,增加prcxi的debug模式 * 增加注册表版本参数,支持将auto-指令人工检查后非auto,不生成人工已检查的指令,取消不必要的description生成 * 增加注册表版本参数,支持将auto-指令人工检查后非auto,不生成人工已检查的指令,取消不必要的description生成 * Update prcxi.py * 修复了部分的protocol因为XDL更新导致的问题 (#61) * 修复了部分的protocol因为XDL更新导致的问题 但是pumptransfer,add,dissolve,separate还没修,后续还需要写virtual固体加料器 * 补充了四个action * 添加了固体加样器,丰富了json,修改了add protocol * bump version to 0.9.9 * fix bugs from new actions * protocol完整修复版本& bump version to 0.9.10 * 修补了一些单位处理,bump version to 0.9.11 * 优化了全protocol的运行时间,除了pumptransfer相关的还没 * 补充了剩下的几个protocol --------- Co-authored-by: Junhan Chang <changjh@dp.tech> Co-authored-by: Xuwznln <18435084+Xuwznln@users.noreply.github.com> * 修复action移除时的报错,更新注册表 * Update prcxi.py * Update prcxi.py * 新增simulator * Update prcxi.py * Update trash * Update prcxi.py * Update prcxi.py * Update for discard tips * Update prcxi.py * Update PRCXI * 更新axis等参数 * Update 9320 * get_well_container&get_tip_rack * update * Update 9320 * update * deck * 更新注册表&增加资源,parent应为resources字段 * Update 9320 * update * 新增set liquid方法 * 新增set liquid方法 * action to resource & 0.9.12 (#64) * action to resource & 0.9.12 * stir和adjustph的中的bug修不好 * modify prcxi * 0.9.12 update registry * update * update * registry upadte * Update * update * container_for_nothing * mix * registry fix * registry fix * registry fix * Update * Update prcxi.py * SET TIP RACK * bump version * update registry version & category * update set tip rack * yaml dump支持ordered dict,支持config_info * fix devices * fix resource check serialize * fix: Protocol node resource run (#65) * stir和adjustph的中的bug修不好 * fix sub-resource query in protocol node compiling * add resource placeholder to vessels * add the rest yaml * Update work_station.yaml --------- Co-authored-by: KCFeng425 <2100011801@stu.pku.edu.cn> * 采用http报送resource * 采用http报送resource * update * Update .gitignore * bump version to 0.10.0 * default param simulator * slim * Update * Update for prcxi * Update * Update * Refactor PRCXI9300Deck initialization and update plate configurations - Changed deck name from "PRCXI_Deck" to "PRCXI_Deck_9300". - Updated plate4 initialization to use get_well_container instead of get_tip_rack. - Modified plate4 material details with new UUID, code, and name. - Renamed output JSON file to "deck_9300_new.json". - Uncommented and adjusted liquid handling operations for clarity and future use. * test * update * Update prcxi_9300.json This one is good * update * fix protocol_node communication transfer * 修复注册表handles类型错误的问题 * 物料添加失败应该直接raise ValueError,不要等待 * 更正注册表中的数字类型 * Delete unnecessary files. * 新增lab_id直接传入 * fix vessel_id param passing in protocols * 新增dll预载,保证部分设备可正常使用unilabos_msgs * 修复可能的web template找不到的问题 新增联网获取json启动 删除非-g传入启动json的方式 兼容传参参数名短横线与下划线 * 修复可能的web template找不到的问题 新增联网获取json启动 删除非-g传入启动json的方式 兼容传参参数名短横线与下划线 更新版本到0.10.1 修复Upload Registry镜像不匹配 * 新增用户引导 * Device visualization (#67) * Update README and MQTTClient for installation instructions and code improvements * feat: 支持local_config启动 add: 增加对crt path的说明,为传入config.py的相对路径 move: web component * add: registry description * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * feat: node_info_update srv fix: OTDeck cant create * close #12 feat: slave node registry * feat: show machine name fix: host node registry not uploaded * feat: add hplc registry * feat: add hplc registry * fix: hplc status typo * fix: devices/ * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * fix: device.class possible null * fix: HPLC additions with online service * fix: slave mode spin not working * fix: slave mode spin not working * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * feat: 多ProtocolNode 允许子设备ID相同 feat: 上报发现的ActionClient feat: Host重启动,通过discover机制要求slaveNode重新注册,实现信息及时上报 * feat: 支持env设置config * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * Device visualization (#14) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: missing hostname in devices_names fix: upload_file for model file * fix: missing paho-mqtt package bump version to 0.9.0 * fix startup add ResourceCreateFromOuter.action * fix type hint * update actions * update actions * host node add_resource_from_outer fix cmake list * pass device config to device class * add: bind_parent_ids to resource create action fix: message convert string * fix: host node should not be re_discovered * feat: resource tracker support dict * feat: add more necessary params * feat: fix boolean null in registry action data * feat: add outer resource * 编写mesh添加action * feat: append resource * add action * feat: vis 2d for plr * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate * Device visualization (#22) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * 编写mesh添加action * add action * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: multi channel * fix: aspirate * fix: aspirate * fix: aspirate * fix: aspirate * 提交 * fix: jobadd * fix: jobadd * fix: msg converter * tijiao * add resource creat easy action * identify debug msg * mq client id * 提取lh的joint发布 * unify liquid_handler definition * 修改物料跟随与物料添加逻辑 修改物料跟随与物料添加逻辑 将joint_publisher类移出lh的backends,但仍需要对lh的backends进行一些改写 * Revert "修改物料跟随与物料添加逻辑" This reverts commit498c997ad7. * Reapply "修改物料跟随与物料添加逻辑" This reverts commit3a60d2ae81. * Revert "Merge remote-tracking branch 'upstream/dev' into device_visualization" This reverts commitfa727220af, reversing changes made to498c997ad7. * 修改物料放下时的方法,如果选择 修改物料放下时的方法, 如果选择drop_trash,则删除物料显示 如果选择drop,则让其解除连接 * unilab添加moveit启动 1,整合所有moveit节点到一个move_group中,并整合所有的controller依次激活 2,添加pymoveit2的节点,使用json可直接启动 3,修改机械臂规划方式,添加约束,让冗余关节不会进行过多移动 * 修改物体attach时,多次赋值当前时间导致卡顿问题, * Revert "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit56d45b94f5. * Reapply "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit07d9db20c3. * 添加缺少物料:"plate_well_G12", * add * fix tip resource data * liquid states * change to debug level * Revert "change to debug level" This reverts commit5d9953c3e5. * Reapply "change to debug level" This reverts commit2487bb6ffc. * fix tip resource data * add full device * add moveit yaml * 修复moveit 增加post_init阶段,给予ros_node反向 * remove necessary node * fix moveit action client * remove necessary imports * Update moveit_interface.py * fix handler_key uppercase * json add liquids * fix setup * add * change to "sources" and "targets" for lh * bump version * remove parent's parent link * change arm's name * change name * fix ik error * 修改moveit_interface,并在mqtt上报时发送一个时间戳 * 添加机械臂和移液站 * 添加 * 添加硬件 * update * 添加 --------- Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: Junhan Chang <changjh@pku.edu.cn> * 更新注册表 --------- Co-authored-by: Junhan Chang <changjh@pku.edu.cn> Co-authored-by: Guangxin Zhang <guangxin.zhang.bio@gmail.com> Co-authored-by: qxw138 <qxw@stu.pku.edu.cn> Co-authored-by: q434343 <73513873+q434343@users.noreply.github.com> Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: Kongchang Feng <2100011801@stu.pku.edu.cn> Co-authored-by: hh. <103566763+Mile-Away@users.noreply.github.com> Co-authored-by: quehh <scienceol@outlook.com> Co-authored-by: Harvey Que <quehaohui@dp.tech> Co-authored-by: Junhan Chang <changjh@dp.tech> Co-authored-by: ZiWei <131428629+ZiWei09@users.noreply.github.com>
1402 lines
55 KiB
Python
1402 lines
55 KiB
Python
import asyncio
|
||
import collections
|
||
import contextlib
|
||
import json
|
||
import socket
|
||
import time
|
||
from typing import Any, List, Dict, Optional, TypedDict, Union, Sequence, Iterator, Literal
|
||
|
||
from pylabrobot.liquid_handling import (
|
||
LiquidHandlerBackend,
|
||
Pickup,
|
||
SingleChannelAspiration,
|
||
Drop,
|
||
SingleChannelDispense,
|
||
PickupTipRack,
|
||
DropTipRack,
|
||
MultiHeadAspirationPlate, ChatterBoxBackend, LiquidHandlerChatterboxBackend,
|
||
)
|
||
from pylabrobot.liquid_handling.standard import (
|
||
MultiHeadAspirationContainer,
|
||
MultiHeadDispenseContainer,
|
||
MultiHeadDispensePlate,
|
||
ResourcePickup,
|
||
ResourceMove,
|
||
ResourceDrop,
|
||
)
|
||
from pylabrobot.resources import Tip, Deck, Plate, Well, TipRack, Resource, Container, Coordinate, TipSpot, Trash
|
||
|
||
from unilabos.devices.liquid_handling.liquid_handler_abstract import LiquidHandlerAbstract
|
||
|
||
|
||
class PRCXIError(RuntimeError):
|
||
"""Lilith 返回 Success=false 时抛出的业务异常"""
|
||
|
||
|
||
class Material(TypedDict): # 和Plate同关系
|
||
uuid: str
|
||
Code: Optional[str]
|
||
Name: Optional[str]
|
||
SummaryName: Optional[str]
|
||
PipetteHeight: Optional[int]
|
||
materialEnum: Optional[int]
|
||
|
||
|
||
class WorkTablets(TypedDict):
|
||
Number: int
|
||
Code: str
|
||
Material: Dict[str, Any]
|
||
|
||
|
||
class MatrixInfo(TypedDict):
|
||
MatrixId: str
|
||
MatrixName: str
|
||
MatrixCount: int
|
||
WorkTablets: list[WorkTablets]
|
||
|
||
|
||
class PRCXI9300Deck(Deck):
|
||
"""PRCXI 9300 的专用 Deck 类,继承自 Deck。
|
||
|
||
该类定义了 PRCXI 9300 的工作台布局和槽位信息。
|
||
"""
|
||
|
||
def __init__(self, name: str, size_x: float, size_y: float, size_z: float):
|
||
super().__init__(name, size_x, size_y, size_z)
|
||
self.slots = [None] * 6 # PRCXI 9300 有 6 个槽位
|
||
|
||
|
||
class PRCXI9300Container(Plate, TipRack):
|
||
"""PRCXI 9300 的专用 Deck 类,继承自 Deck。
|
||
|
||
该类定义了 PRCXI 9300 的工作台布局和槽位信息。
|
||
"""
|
||
|
||
def __init__(self, name: str, size_x: float, size_y: float, size_z: float, category: str, ordering: collections.OrderedDict, model: Optional[str] = None,):
|
||
super().__init__(name, size_x, size_y, size_z, category=category, ordering=ordering, model=model)
|
||
self._unilabos_state = {}
|
||
|
||
def load_state(self, state: Dict[str, Any]) -> None:
|
||
"""从给定的状态加载工作台信息。"""
|
||
super().load_state(state)
|
||
self._unilabos_state = state
|
||
|
||
def serialize_state(self) -> Dict[str, Dict[str, Any]]:
|
||
data = super().serialize_state()
|
||
data.update(self._unilabos_state)
|
||
return data
|
||
|
||
|
||
class PRCXI9300Trash(Trash):
|
||
"""PRCXI 9300 的专用 Trash 类,继承自 Trash。
|
||
|
||
该类定义了 PRCXI 9300 的工作台布局和槽位信息。
|
||
"""
|
||
|
||
def __init__(self, name: str, size_x: float, size_y: float, size_z: float, category: str, **kwargs):
|
||
if name != "trash":
|
||
name = "trash"
|
||
print("PRCXI9300Trash name must be 'trash', using 'trash' instead.")
|
||
super().__init__(name, size_x, size_y, size_z, category=category, **kwargs)
|
||
self._unilabos_state = {}
|
||
|
||
def load_state(self, state: Dict[str, Any]) -> None:
|
||
"""从给定的状态加载工作台信息。"""
|
||
#super().load_state(state)
|
||
self._unilabos_state = state
|
||
|
||
def serialize_state(self) -> Dict[str, Dict[str, Any]]:
|
||
data = super().serialize_state()
|
||
data.update(self._unilabos_state)
|
||
return data
|
||
|
||
class PRCXI9300Handler(LiquidHandlerAbstract):
|
||
support_touch_tip = False
|
||
|
||
@property
|
||
def reset_ok(self) -> bool:
|
||
"""检查设备是否已重置成功。"""
|
||
if self._unilabos_backend.debug:
|
||
return True
|
||
return self._unilabos_backend.is_reset_ok
|
||
|
||
def __init__(self, deck: Deck, host: str, port: int, timeout: float, channel_num=8, axis="Left", setup=True, debug=False, simulator=False, matrix_id=""):
|
||
tablets_info = []
|
||
count = 0
|
||
for child in deck.children:
|
||
if "Material" in child._unilabos_state:
|
||
count += 1
|
||
tablets_info.append(
|
||
WorkTablets(Number=count, Code=f"T{count}", Material=child._unilabos_state["Material"])
|
||
)
|
||
self._unilabos_backend = PRCXI9300Backend(tablets_info, host, port, timeout, channel_num, axis, setup, debug, matrix_id)
|
||
super().__init__(backend=self._unilabos_backend, deck=deck, simulator=simulator, channel_num=channel_num)
|
||
|
||
def set_liquid(self, wells: list[Well], liquid_names: list[str], volumes: list[float]):
|
||
return super().set_liquid(wells, liquid_names, volumes)
|
||
|
||
async def create_protocol(
|
||
self,
|
||
protocol_name: str = "",
|
||
protocol_description: str = "",
|
||
protocol_version: str = "",
|
||
protocol_author: str = "",
|
||
protocol_date: str = "",
|
||
protocol_type: str = "",
|
||
none_keys: List[str] = [],
|
||
):
|
||
self._unilabos_backend.create_protocol(protocol_name)
|
||
|
||
async def run_protocol(self):
|
||
return self._unilabos_backend.run_protocol()
|
||
|
||
async def remove_liquid(
|
||
self,
|
||
vols: List[float],
|
||
sources: Sequence[Container],
|
||
waste_liquid: Optional[Container] = None,
|
||
*,
|
||
use_channels: Optional[List[int]] = None,
|
||
flow_rates: Optional[List[Optional[float]]] = None,
|
||
offsets: Optional[List[Coordinate]] = None,
|
||
liquid_height: Optional[List[Optional[float]]] = None,
|
||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||
spread: Optional[Literal["wide", "tight", "custom"]] = "wide",
|
||
delays: Optional[List[int]] = None,
|
||
is_96_well: Optional[bool] = False,
|
||
top: Optional[List[float]] = None,
|
||
none_keys: List[str] = [],
|
||
):
|
||
return await super().remove_liquid(
|
||
vols,
|
||
sources,
|
||
waste_liquid,
|
||
use_channels=use_channels,
|
||
flow_rates=flow_rates,
|
||
offsets=offsets,
|
||
liquid_height=liquid_height,
|
||
blow_out_air_volume=blow_out_air_volume,
|
||
spread=spread,
|
||
delays=delays,
|
||
is_96_well=is_96_well,
|
||
top=top,
|
||
none_keys=none_keys,
|
||
)
|
||
|
||
async def add_liquid(
|
||
self,
|
||
asp_vols: Union[List[float], float],
|
||
dis_vols: Union[List[float], float],
|
||
reagent_sources: Sequence[Container],
|
||
targets: Sequence[Container],
|
||
*,
|
||
use_channels: Optional[List[int]] = None,
|
||
flow_rates: Optional[List[Optional[float]]] = None,
|
||
offsets: Optional[List[Coordinate]] = None,
|
||
liquid_height: Optional[List[Optional[float]]] = None,
|
||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||
spread: Optional[Literal["wide", "tight", "custom"]] = "wide",
|
||
is_96_well: bool = False,
|
||
delays: Optional[List[int]] = None,
|
||
mix_time: Optional[int] = None,
|
||
mix_vol: Optional[int] = None,
|
||
mix_rate: Optional[int] = None,
|
||
mix_liquid_height: Optional[float] = None,
|
||
none_keys: List[str] = [],
|
||
):
|
||
return await super().add_liquid(
|
||
asp_vols,
|
||
dis_vols,
|
||
reagent_sources,
|
||
targets,
|
||
use_channels=use_channels,
|
||
flow_rates=flow_rates,
|
||
offsets=offsets,
|
||
liquid_height=liquid_height,
|
||
blow_out_air_volume=blow_out_air_volume,
|
||
spread=spread,
|
||
is_96_well=is_96_well,
|
||
delays=delays,
|
||
mix_time=mix_time,
|
||
mix_vol=mix_vol,
|
||
mix_rate=mix_rate,
|
||
mix_liquid_height=mix_liquid_height,
|
||
none_keys=none_keys,
|
||
)
|
||
|
||
async def transfer_liquid(
|
||
self,
|
||
sources: Sequence[Container],
|
||
targets: Sequence[Container],
|
||
tip_racks: Sequence[TipRack],
|
||
*,
|
||
use_channels: Optional[List[int]] = None,
|
||
asp_vols: Union[List[float], float],
|
||
dis_vols: Union[List[float], float],
|
||
asp_flow_rates: Optional[List[Optional[float]]] = None,
|
||
dis_flow_rates: Optional[List[Optional[float]]] = None,
|
||
offsets: Optional[List[Coordinate]] = None,
|
||
touch_tip: bool = False,
|
||
liquid_height: Optional[List[Optional[float]]] = None,
|
||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||
spread: Literal["wide", "tight", "custom"] = "wide",
|
||
is_96_well: bool = False,
|
||
mix_stage: Optional[Literal["none", "before", "after", "both"]] = "none",
|
||
mix_times: Optional[List[int]] = None,
|
||
mix_vol: Optional[int] = None,
|
||
mix_rate: Optional[int] = None,
|
||
mix_liquid_height: Optional[float] = None,
|
||
delays: Optional[List[int]] = None,
|
||
none_keys: List[str] = [],
|
||
):
|
||
return await super().transfer_liquid(
|
||
sources,
|
||
targets,
|
||
tip_racks,
|
||
use_channels=use_channels,
|
||
asp_vols=asp_vols,
|
||
dis_vols=dis_vols,
|
||
asp_flow_rates=asp_flow_rates,
|
||
dis_flow_rates=dis_flow_rates,
|
||
offsets=offsets,
|
||
touch_tip=touch_tip,
|
||
liquid_height=liquid_height,
|
||
blow_out_air_volume=blow_out_air_volume,
|
||
spread=spread,
|
||
is_96_well=is_96_well,
|
||
mix_stage=mix_stage,
|
||
mix_times=mix_times,
|
||
mix_vol=mix_vol,
|
||
mix_rate=mix_rate,
|
||
mix_liquid_height=mix_liquid_height,
|
||
delays=delays,
|
||
none_keys=none_keys,
|
||
)
|
||
|
||
async def custom_delay(self, seconds=0, msg=None):
|
||
return await super().custom_delay(seconds, msg)
|
||
|
||
async def touch_tip(self, targets: Sequence[Container]):
|
||
return await super().touch_tip(targets)
|
||
|
||
async def mix(
|
||
self,
|
||
targets: Sequence[Container],
|
||
mix_time: int = None,
|
||
mix_vol: Optional[int] = None,
|
||
height_to_bottom: Optional[float] = None,
|
||
offsets: Optional[Coordinate] = None,
|
||
mix_rate: Optional[float] = None,
|
||
none_keys: List[str] = [],
|
||
):
|
||
return await self._unilabos_backend.mix(targets, mix_time, mix_vol, height_to_bottom, offsets, mix_rate, none_keys)
|
||
|
||
def iter_tips(self, tip_racks: Sequence[TipRack]) -> Iterator[Resource]:
|
||
return super().iter_tips(tip_racks)
|
||
|
||
async def pick_up_tips(self, tip_spots: List[TipSpot], use_channels: Optional[List[int]] = None,
|
||
offsets: Optional[List[Coordinate]] = None, **backend_kwargs):
|
||
return await super().pick_up_tips(tip_spots, use_channels, offsets, **backend_kwargs)
|
||
|
||
async def aspirate(self, resources: Sequence[Container], vols: List[float],
|
||
use_channels: Optional[List[int]] = None, flow_rates: Optional[List[Optional[float]]] = None,
|
||
offsets: Optional[List[Coordinate]] = None,
|
||
liquid_height: Optional[List[Optional[float]]] = None,
|
||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||
spread: Literal["wide", "tight", "custom"] = "wide", **backend_kwargs):
|
||
|
||
return await super().aspirate(resources, vols, use_channels, flow_rates, offsets, liquid_height,
|
||
blow_out_air_volume, spread, **backend_kwargs)
|
||
|
||
async def drop_tips(self, tip_spots: Sequence[Union[TipSpot, Trash]], use_channels: Optional[List[int]] = None,
|
||
offsets: Optional[List[Coordinate]] = None, allow_nonzero_volume: bool = False,
|
||
**backend_kwargs):
|
||
return await super().drop_tips(tip_spots, use_channels, offsets, allow_nonzero_volume, **backend_kwargs)
|
||
|
||
async def dispense(self, resources: Sequence[Container], vols: List[float],
|
||
use_channels: Optional[List[int]] = None, flow_rates: Optional[List[Optional[float]]] = None,
|
||
offsets: Optional[List[Coordinate]] = None,
|
||
liquid_height: Optional[List[Optional[float]]] = None,
|
||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||
spread: Literal["wide", "tight", "custom"] = "wide", **backend_kwargs):
|
||
return await super().dispense(resources, vols, use_channels, flow_rates, offsets, liquid_height,
|
||
blow_out_air_volume, spread, **backend_kwargs)
|
||
|
||
async def discard_tips(self, use_channels: Optional[List[int]] = None, allow_nonzero_volume: bool = True,
|
||
offsets: Optional[List[Coordinate]] = None, **backend_kwargs):
|
||
return await super().discard_tips(use_channels, allow_nonzero_volume, offsets, **backend_kwargs)
|
||
|
||
def set_tiprack(self, tip_racks: Sequence[TipRack]):
|
||
super().set_tiprack(tip_racks)
|
||
|
||
async def move_to(self, well: Well, dis_to_top: float = 0, channel: int = 0):
|
||
return await super().move_to(well, dis_to_top, channel)
|
||
|
||
|
||
class PRCXI9300Backend(LiquidHandlerBackend):
|
||
"""PRCXI 9300 的后端实现,继承自 LiquidHandlerBackend。
|
||
|
||
该类提供了与 PRCXI 9300 设备进行通信的基本方法,包括方案管理、自动化控制、运行状态查询等。
|
||
"""
|
||
|
||
_num_channels = 8 # 默认通道数为 8
|
||
_is_reset_ok = False
|
||
|
||
@property
|
||
def is_reset_ok(self) -> bool:
|
||
self._is_reset_ok = self.api_client.get_reset_status()
|
||
return self._is_reset_ok
|
||
|
||
matrix_info: MatrixInfo
|
||
protocol_name: str
|
||
steps_todo_list = []
|
||
|
||
def __init__(
|
||
self,
|
||
tablets_info: list[WorkTablets],
|
||
host: str = "127.0.0.1",
|
||
port: int = 9999,
|
||
timeout: float = 10.0,
|
||
channel_num: int=8,
|
||
axis: str="Left",
|
||
setup=True,
|
||
debug=False,
|
||
matrix_id="",
|
||
) -> None:
|
||
super().__init__()
|
||
self.tablets_info = tablets_info
|
||
self.matrix_id = matrix_id
|
||
self.api_client = PRCXI9300Api(host, port, timeout, axis, debug)
|
||
self.host, self.port, self.timeout = host, port, timeout
|
||
self._num_channels = channel_num
|
||
self._execute_setup = setup
|
||
self.debug = debug
|
||
|
||
def create_protocol(self, protocol_name):
|
||
self.protocol_name = protocol_name
|
||
self.steps_todo_list = []
|
||
|
||
def run_protocol(self):
|
||
assert self.is_reset_ok, "PRCXI9300Backend is not reset successfully. Please call setup() first."
|
||
run_time = time.time()
|
||
self.matrix_info = MatrixInfo(
|
||
MatrixId=f"{int(run_time)}",
|
||
MatrixName=f"protocol_{run_time}",
|
||
MatrixCount=len(self.tablets_info),
|
||
WorkTablets=self.tablets_info,
|
||
)
|
||
#print(json.dumps(self.matrix_info, indent=2))
|
||
if not len(self.matrix_id):
|
||
res = self.api_client.add_WorkTablet_Matrix(self.matrix_info)
|
||
assert res["Success"], f"Failed to create matrix: {res.get('Message', 'Unknown error')}"
|
||
print(f"PRCXI9300Backend created matrix with ID: {self.matrix_info['MatrixId']}, result: {res}")
|
||
solution_id = self.api_client.add_solution(
|
||
f"protocol_{run_time}", self.matrix_info["MatrixId"], self.steps_todo_list
|
||
)
|
||
else:
|
||
print(f"PRCXI9300Backend using predefined worktable {self.matrix_id}, skipping matrix creation.")
|
||
solution_id = self.api_client.add_solution(
|
||
f"protocol_{run_time}", self.matrix_id, self.steps_todo_list
|
||
)
|
||
print(f"PRCXI9300Backend created solution with ID: {solution_id}")
|
||
self.api_client.load_solution(solution_id)
|
||
print(json.dumps(self.steps_todo_list, indent=2))
|
||
return self.api_client.start()
|
||
|
||
@classmethod
|
||
def check_channels(cls, use_channels: List[int]) -> List[int]:
|
||
"""检查通道是否符合要求,PRCXI9300Backend 只支持所有 8 个通道。"""
|
||
if use_channels != [0, 1, 2, 3, 4, 5, 6, 7]:
|
||
print("PRCXI9300Backend only supports all 8 channels, using default [0, 1, 2, 3, 4, 5, 6, 7].")
|
||
return [0, 1, 2, 3, 4, 5, 6, 7]
|
||
return use_channels
|
||
|
||
async def setup(self):
|
||
await super().setup()
|
||
try:
|
||
if self._execute_setup:
|
||
self.api_client.call("IAutomation", "Reset")
|
||
while not self.is_reset_ok:
|
||
print("Waiting for PRCXI9300 to reset...")
|
||
await asyncio.sleep(1)
|
||
print("PRCXI9300 reset successfully.")
|
||
except ConnectionRefusedError as e:
|
||
raise RuntimeError(
|
||
f"Failed to connect to PRCXI9300 API at {self.host}:{self.port}. "
|
||
"Please ensure the PRCXI9300 service is running."
|
||
) from e
|
||
|
||
async def stop(self):
|
||
self.api_client.call("IAutomation", "Stop")
|
||
|
||
async def pick_up_tips(self, ops: List[Pickup], use_channels: List[int] = None):
|
||
"""Pick up tips from the specified resource."""
|
||
print('where?'*200)
|
||
plate_indexes = []
|
||
for op in ops:
|
||
plate = op.resource.parent
|
||
deck = plate.parent
|
||
plate_index = deck.children.index(plate)
|
||
print(f"Plate index: {plate_index}, Plate name: {plate.name}")
|
||
print(f"Number of children in deck: {len(deck.children)}")
|
||
|
||
plate_indexes.append(plate_index)
|
||
|
||
if len(set(plate_indexes)) != 1:
|
||
raise ValueError("All pickups must be from the same plate. Found different plates: " + str(plate_indexes))
|
||
|
||
tip_columns = []
|
||
for op in ops:
|
||
tipspot = op.resource
|
||
tipspot_index = tipspot.parent.children.index(tipspot)
|
||
tip_columns.append(tipspot_index // 8)
|
||
if len(set(tip_columns)) != 1:
|
||
raise ValueError("All pickups must be from the same tip column. Found different columns: " + str(tip_columns))
|
||
# print('111'*99)
|
||
# print(plate_indexes[0])
|
||
PlateNo = plate_indexes[0] + 1
|
||
hole_col = tip_columns[0] + 1
|
||
hole_row = 1
|
||
if self._num_channels == 1:
|
||
hole_row = tipspot_index % 8 + 1
|
||
|
||
step = self.api_client.Load(dosage=0, plate_no=PlateNo, is_whole_plate=False, hole_row=hole_row, hole_col=hole_col,
|
||
blending_times=0, balance_height=0, plate_or_hole=f"H{hole_col}-8,T{PlateNo}",
|
||
hole_numbers="1,2,3,4,5,6,7,8")
|
||
self.steps_todo_list.append(step)
|
||
|
||
async def drop_tips(self, ops: List[Drop], use_channels: List[int] = None):
|
||
"""Pick up tips from the specified resource."""
|
||
|
||
# 检查trash #
|
||
if ops[0].resource.name == "trash":
|
||
|
||
PlateNo = ops[0].resource.parent.children.index(ops[0].resource) + 1
|
||
|
||
step = self.api_client.UnLoad(
|
||
dosage=0,
|
||
plate_no=PlateNo,
|
||
is_whole_plate=False,
|
||
hole_row=1,
|
||
hole_col=3,
|
||
blending_times=0,
|
||
balance_height=0,
|
||
plate_or_hole=f"H{1}-8,T{PlateNo}",
|
||
hole_numbers="1,2,3,4,5,6,7,8",
|
||
)
|
||
self.steps_todo_list.append(step)
|
||
return
|
||
#print(ops[0].resource.parent.children.index(ops[0].resource))
|
||
|
||
|
||
plate_indexes = []
|
||
for op in ops:
|
||
plate = op.resource.parent
|
||
deck = plate.parent
|
||
plate_index = deck.children.index(plate)
|
||
plate_indexes.append(plate_index)
|
||
if len(set(plate_indexes)) != 1:
|
||
raise ValueError("All drop_tips must be from the same plate. Found different plates: " + str(plate_indexes))
|
||
|
||
tip_columns = []
|
||
for op in ops:
|
||
tipspot = op.resource
|
||
tipspot_index = tipspot.parent.children.index(tipspot)
|
||
tip_columns.append(tipspot_index // 8)
|
||
if len(set(tip_columns)) != 1:
|
||
raise ValueError("All drop_tips must be from the same tip column. Found different columns: " + str(tip_columns))
|
||
|
||
PlateNo = plate_indexes[0] + 1
|
||
hole_col = tip_columns[0] + 1
|
||
|
||
if self.channel_num == 1:
|
||
hole_row = tipspot_index % 8 + 1
|
||
|
||
step = self.api_client.UnLoad(
|
||
dosage=0,
|
||
plate_no=PlateNo,
|
||
is_whole_plate=False,
|
||
hole_row=hole_row,
|
||
hole_col=hole_col,
|
||
blending_times=0,
|
||
balance_height=0,
|
||
plate_or_hole=f"H{hole_col}-8,T{PlateNo}",
|
||
hole_numbers="1,2,3,4,5,6,7,8",
|
||
)
|
||
self.steps_todo_list.append(step)
|
||
|
||
async def mix(
|
||
self,
|
||
targets: Sequence[Container],
|
||
mix_time: int = None,
|
||
mix_vol: Optional[int] = None,
|
||
height_to_bottom: Optional[float] = None,
|
||
offsets: Optional[Coordinate] = None,
|
||
mix_rate: Optional[float] = None,
|
||
none_keys: List[str] = [],
|
||
):
|
||
|
||
"""Mix liquid in the specified resources."""
|
||
|
||
plate_indexes = []
|
||
for op in targets:
|
||
deck = op.parent.parent
|
||
plate = op.parent
|
||
plate_index = deck.children.index(plate)
|
||
plate_indexes.append(plate_index)
|
||
|
||
if len(set(plate_indexes)) != 1:
|
||
raise ValueError("All pickups must be from the same plate. Found different plates: " + str(plate_indexes))
|
||
|
||
tip_columns = []
|
||
for op in targets:
|
||
tipspot_index = op.parent.children.index(op)
|
||
tip_columns.append(tipspot_index // 8)
|
||
|
||
if len(set(tip_columns)) != 1:
|
||
raise ValueError("All pickups must be from the same tip column. Found different columns: " + str(tip_columns))
|
||
|
||
PlateNo = plate_indexes[0] + 1
|
||
hole_col = tip_columns[0] + 1
|
||
hole_row = 1
|
||
if self.num_channels == 1:
|
||
hole_row = tipspot_index % 8 + 1
|
||
|
||
assert mix_time > 0
|
||
step = self.api_client.Blending(
|
||
dosage=mix_vol,
|
||
plate_no=PlateNo,
|
||
is_whole_plate=False,
|
||
hole_row=hole_row,
|
||
hole_col=hole_col,
|
||
blending_times=mix_time,
|
||
balance_height=0,
|
||
plate_or_hole=f"H{hole_col}-8,T{PlateNo}",
|
||
hole_numbers="1,2,3,4,5,6,7,8",
|
||
)
|
||
self.steps_todo_list.append(step)
|
||
|
||
async def aspirate(self, ops: List[SingleChannelAspiration], use_channels: List[int] = None):
|
||
|
||
"""Aspirate liquid from the specified resources."""
|
||
|
||
plate_indexes = []
|
||
for op in ops:
|
||
plate = op.resource.parent
|
||
deck = plate.parent
|
||
plate_index = deck.children.index(plate)
|
||
plate_indexes.append(plate_index)
|
||
|
||
if len(set(plate_indexes)) != 1:
|
||
raise ValueError("All pickups must be from the same plate. Found different plates: " + str(plate_indexes))
|
||
|
||
tip_columns = []
|
||
for op in ops:
|
||
tipspot = op.resource
|
||
tipspot_index = tipspot.parent.children.index(tipspot)
|
||
tip_columns.append(tipspot_index // 8)
|
||
|
||
if len(set(tip_columns)) != 1:
|
||
raise ValueError("All pickups must be from the same tip column. Found different columns: " + str(tip_columns))
|
||
|
||
volumes = [op.volume for op in ops]
|
||
if len(set(volumes)) != 1:
|
||
raise ValueError("All aspirate volumes must be the same. Found different volumes: " + str(volumes))
|
||
|
||
PlateNo = plate_indexes[0] + 1
|
||
hole_col = tip_columns[0] + 1
|
||
hole_row = 1
|
||
if self.num_channels == 1:
|
||
hole_row = tipspot_index % 8 + 1
|
||
|
||
step = self.api_client.Imbibing(dosage=int(volumes[0]), plate_no=PlateNo, is_whole_plate=False, hole_row=hole_row,
|
||
hole_col=hole_col, blending_times=0, balance_height=0,
|
||
plate_or_hole=f"H{hole_col}-8,T{PlateNo}", hole_numbers="1,2,3,4,5,6,7,8")
|
||
self.steps_todo_list.append(step)
|
||
|
||
|
||
|
||
async def dispense(self, ops: List[SingleChannelDispense], use_channels: List[int] = None):
|
||
|
||
"""Dispense liquid into the specified resources."""
|
||
|
||
plate_indexes = []
|
||
for op in ops:
|
||
plate = op.resource.parent
|
||
deck = plate.parent
|
||
plate_index = deck.children.index(plate)
|
||
plate_indexes.append(plate_index)
|
||
|
||
if len(set(plate_indexes)) != 1:
|
||
raise ValueError("All dispense must be from the same plate. Found different plates: " + str(plate_indexes))
|
||
|
||
tip_columns = []
|
||
for op in ops:
|
||
tipspot = op.resource
|
||
tipspot_index = tipspot.parent.children.index(tipspot)
|
||
tip_columns.append(tipspot_index // 8)
|
||
|
||
if len(set(tip_columns)) != 1:
|
||
raise ValueError("All dispense must be from the same tip column. Found different columns: " + str(tip_columns))
|
||
|
||
volumes = [op.volume for op in ops]
|
||
if len(set(volumes)) != 1:
|
||
raise ValueError("All dispense volumes must be the same. Found different volumes: " + str(volumes))
|
||
|
||
PlateNo = plate_indexes[0] + 1
|
||
hole_col = tip_columns[0] + 1
|
||
|
||
hole_row = 1
|
||
if self.num_channels == 1:
|
||
hole_row = tipspot_index % 8 + 1
|
||
|
||
step = self.api_client.Tapping(
|
||
dosage=int(volumes[0]),
|
||
plate_no=PlateNo,
|
||
is_whole_plate=False,
|
||
hole_row=hole_row,
|
||
hole_col=hole_col,
|
||
blending_times=0,
|
||
balance_height=0,
|
||
plate_or_hole=f"H{hole_col}-8,T{PlateNo}",
|
||
hole_numbers="1,2,3,4,5,6,7,8",
|
||
)
|
||
self.steps_todo_list.append(step)
|
||
|
||
async def pick_up_tips96(self, pickup: PickupTipRack):
|
||
raise NotImplementedError("The PRCXI backend does not support the 96 head.")
|
||
|
||
async def drop_tips96(self, drop: DropTipRack):
|
||
raise NotImplementedError("The PRCXI backend does not support the 96 head.")
|
||
|
||
async def aspirate96(self, aspiration: Union[MultiHeadAspirationPlate, MultiHeadAspirationContainer]):
|
||
raise NotImplementedError("The Opentrons backend does not support the 96 head.")
|
||
|
||
async def dispense96(self, dispense: Union[MultiHeadDispensePlate, MultiHeadDispenseContainer]):
|
||
raise NotImplementedError("The Opentrons backend does not support the 96 head.")
|
||
|
||
async def pick_up_resource(self, pickup: ResourcePickup):
|
||
raise NotImplementedError("The Opentrons backend does not support the robotic arm.")
|
||
|
||
async def move_picked_up_resource(self, move: ResourceMove):
|
||
raise NotImplementedError("The Opentrons backend does not support the robotic arm.")
|
||
|
||
async def drop_resource(self, drop: ResourceDrop):
|
||
raise NotImplementedError("The Opentrons backend does not support the robotic arm.")
|
||
|
||
def can_pick_up_tip(self, channel_idx: int, tip: Tip) -> bool:
|
||
return True # PRCXI9300Backend does not have tip compatibility issues
|
||
|
||
def serialize(self) -> dict:
|
||
raise NotImplementedError()
|
||
|
||
@property
|
||
def num_channels(self) -> int:
|
||
return self._num_channels
|
||
|
||
|
||
class PRCXI9300Api:
|
||
def __init__(self, host: str = "127.0.0.1", port: int = 9999, timeout: float = 10.0, axis="Left", debug: bool = False) -> None:
|
||
self.host, self.port, self.timeout = host, port, timeout
|
||
self.debug = debug
|
||
self.axis = axis
|
||
|
||
@staticmethod
|
||
def _len_prefix(n: int) -> bytes:
|
||
return bytes.fromhex(format(n, "016x"))
|
||
|
||
def _raw_request(self, payload: str) -> str:
|
||
if self.debug:
|
||
return " "
|
||
with contextlib.closing(socket.socket()) as sock:
|
||
sock.settimeout(self.timeout)
|
||
sock.connect((self.host, self.port))
|
||
data = payload.encode()
|
||
sock.sendall(self._len_prefix(len(data)) + data)
|
||
|
||
chunks, first = [], True
|
||
while True:
|
||
chunk = sock.recv(4096)
|
||
if not chunk:
|
||
break
|
||
if first:
|
||
chunk, first = chunk[8:], False
|
||
chunks.append(chunk)
|
||
return b"".join(chunks).decode()
|
||
|
||
# ---------------------------------------------------- 方案相关(ISolution)
|
||
def list_solutions(self) -> List[Dict[str, Any]]:
|
||
"""GetSolutionList"""
|
||
return self.call("ISolution", "GetSolutionList")
|
||
|
||
def load_solution(self, solution_id: str) -> bool:
|
||
"""LoadSolution"""
|
||
return self.call("ISolution", "LoadSolution", [solution_id])
|
||
|
||
def add_solution(self, name: str, matrix_id: str, steps: List[Dict[str, Any]]) -> str:
|
||
"""AddSolution → 返回新方案 GUID"""
|
||
return self.call("ISolution", "AddSolution", [name, matrix_id, steps])
|
||
|
||
# ---------------------------------------------------- 自动化控制(IAutomation)
|
||
def start(self) -> bool:
|
||
return self.call("IAutomation", "Start")
|
||
|
||
def call(self, service: str, method: str, params: Optional[list] = None) -> Any:
|
||
payload = json.dumps(
|
||
{"ServiceName": service, "MethodName": method, "Paramters": params or []}, separators=(",", ":")
|
||
)
|
||
resp = json.loads(self._raw_request(payload))
|
||
if not resp.get("Success", False):
|
||
raise PRCXIError(resp.get("Msg", "Unknown error"))
|
||
data = resp.get("Data")
|
||
try:
|
||
return json.loads(data)
|
||
except (TypeError, json.JSONDecodeError):
|
||
return data
|
||
|
||
def pause(self) -> bool:
|
||
"""Pause"""
|
||
return self.call("IAutomation", "Pause")
|
||
|
||
def resume(self) -> bool:
|
||
"""Resume"""
|
||
return self.call("IAutomation", "Resume")
|
||
|
||
def get_error_code(self) -> Optional[str]:
|
||
"""GetErrorCode"""
|
||
return self.call("IAutomation", "GetErrorCode")
|
||
|
||
def get_reset_status(self) -> bool:
|
||
"""GetErrorCode"""
|
||
if self.debug:
|
||
return True
|
||
res = self.call("IAutomation", "GetResetStatus")
|
||
return not res
|
||
|
||
def clear_error_code(self) -> bool:
|
||
"""RemoveErrorCodet"""
|
||
return self.call("IAutomation", "RemoveErrorCodet")
|
||
|
||
# ---------------------------------------------------- 运行状态(IMachineState)
|
||
def step_state_list(self) -> List[Dict[str, Any]]:
|
||
"""GetStepStateList"""
|
||
return self.call("IMachineState", "GetStepStateList")
|
||
|
||
def step_status(self, seq_num: int) -> Dict[str, Any]:
|
||
"""GetStepStatus"""
|
||
return self.call("IMachineState", "GetStepStatus", [seq_num])
|
||
|
||
def step_state(self, seq_num: int) -> Dict[str, Any]:
|
||
"""GetStepState"""
|
||
return self.call("IMachineState", "GetStepState", [seq_num])
|
||
|
||
def axis_location(self, axis_num: int = 1) -> Dict[str, Any]:
|
||
"""GetLocation"""
|
||
return self.call("IMachineState", "GetLocation", [axis_num])
|
||
|
||
# ---------------------------------------------------- 版位矩阵(IMatrix)
|
||
def list_matrices(self) -> List[Dict[str, Any]]:
|
||
"""GetWorkTabletMatrices"""
|
||
return self.call("IMatrix", "GetWorkTabletMatrices")
|
||
|
||
def matrix_by_id(self, matrix_id: str) -> Dict[str, Any]:
|
||
"""GetWorkTabletMatrixById"""
|
||
return self.call("IMatrix", "GetWorkTabletMatrixById", [matrix_id])
|
||
|
||
def add_WorkTablet_Matrix(self, matrix: MatrixInfo):
|
||
return self.call("IMatrix", "AddWorkTabletMatrix", [matrix])
|
||
|
||
def Load(self, dosage: int, plate_no: int, is_whole_plate: bool, hole_row: int, hole_col: int, blending_times: int,
|
||
balance_height: int, plate_or_hole: str, hole_numbers: str, assist_fun1: str = "", assist_fun2: str = "",
|
||
assist_fun3: str = "", assist_fun4: str = "", assist_fun5: str = "",
|
||
liquid_method: str = "NormalDispense") -> Dict[str, Any]:
|
||
return {
|
||
"StepAxis": self.axis,
|
||
"Function": "Load",
|
||
"DosageNum": dosage,
|
||
"PlateNo": plate_no,
|
||
"IsWholePlate": is_whole_plate,
|
||
"HoleRow": hole_row,
|
||
"HoleCol": hole_col,
|
||
"BlendingTimes": blending_times,
|
||
"BalanceHeight": balance_height,
|
||
"PlateOrHoleNum": plate_or_hole,
|
||
"AssistFun1": assist_fun1,
|
||
"AssistFun2": assist_fun2,
|
||
"AssistFun3": assist_fun3,
|
||
"AssistFun4": assist_fun4,
|
||
"AssistFun5": assist_fun5,
|
||
"HoleNumbers": hole_numbers,
|
||
"LiquidDispensingMethod": liquid_method,
|
||
}
|
||
|
||
def Imbibing(self, dosage: int, plate_no: int, is_whole_plate: bool, hole_row: int, hole_col: int,
|
||
blending_times: int, balance_height: int, plate_or_hole: str, hole_numbers: str, assist_fun1: str = "",
|
||
assist_fun2: str = "", assist_fun3: str = "", assist_fun4: str = "", assist_fun5: str = "",
|
||
liquid_method: str = "NormalDispense") -> Dict[str, Any]:
|
||
return {
|
||
"StepAxis": self.axis,
|
||
"Function": "Imbibing",
|
||
"DosageNum": dosage,
|
||
"PlateNo": plate_no,
|
||
"IsWholePlate": is_whole_plate,
|
||
"HoleRow": hole_row,
|
||
"HoleCol": hole_col,
|
||
"BlendingTimes": blending_times,
|
||
"BalanceHeight": balance_height,
|
||
"PlateOrHoleNum": plate_or_hole,
|
||
"AssistFun1": assist_fun1,
|
||
"AssistFun2": assist_fun2,
|
||
"AssistFun3": assist_fun3,
|
||
"AssistFun4": assist_fun4,
|
||
"AssistFun5": assist_fun5,
|
||
"HoleNumbers": hole_numbers,
|
||
"LiquidDispensingMethod": liquid_method,
|
||
}
|
||
|
||
def Tapping(
|
||
self,
|
||
dosage: int,
|
||
plate_no: int,
|
||
is_whole_plate: bool,
|
||
hole_row: int,
|
||
hole_col: int,
|
||
blending_times: int,
|
||
balance_height: int,
|
||
plate_or_hole: str,
|
||
hole_numbers: str,
|
||
assist_fun1: str = "",
|
||
assist_fun2: str = "",
|
||
assist_fun3: str = "",
|
||
assist_fun4: str = "",
|
||
assist_fun5: str = "",
|
||
liquid_method: str = "NormalDispense",
|
||
) -> Dict[str, Any]:
|
||
return {
|
||
"StepAxis": self.axis,
|
||
"Function": "Tapping",
|
||
"DosageNum": dosage,
|
||
"PlateNo": plate_no,
|
||
"IsWholePlate": is_whole_plate,
|
||
"HoleRow": hole_row,
|
||
"HoleCol": hole_col,
|
||
"BlendingTimes": blending_times,
|
||
"BalanceHeight": balance_height,
|
||
"PlateOrHoleNum": plate_or_hole,
|
||
"AssistFun1": assist_fun1,
|
||
"AssistFun2": assist_fun2,
|
||
"AssistFun3": assist_fun3,
|
||
"AssistFun4": assist_fun4,
|
||
"AssistFun5": assist_fun5,
|
||
"HoleNumbers": hole_numbers,
|
||
"LiquidDispensingMethod": liquid_method,
|
||
}
|
||
|
||
def Blending(
|
||
self,
|
||
dosage: int,
|
||
plate_no: int,
|
||
is_whole_plate: bool,
|
||
hole_row: int,
|
||
hole_col: int,
|
||
blending_times: int,
|
||
balance_height: int,
|
||
plate_or_hole: str,
|
||
hole_numbers: str,
|
||
assist_fun1: str = "",
|
||
assist_fun2: str = "",
|
||
assist_fun3: str = "",
|
||
assist_fun4: str = "",
|
||
assist_fun5: str = "",
|
||
liquid_method: str = "NormalDispense",
|
||
) -> Dict[str, Any]:
|
||
return {
|
||
"StepAxis": self.axis,
|
||
"Function": "Blending",
|
||
"DosageNum": dosage,
|
||
"PlateNo": plate_no,
|
||
"IsWholePlate": is_whole_plate,
|
||
"HoleRow": hole_row,
|
||
"HoleCol": hole_col,
|
||
"BlendingTimes": blending_times,
|
||
"BalanceHeight": balance_height,
|
||
"PlateOrHoleNum": plate_or_hole,
|
||
"AssistFun1": assist_fun1,
|
||
"AssistFun2": assist_fun2,
|
||
"AssistFun3": assist_fun3,
|
||
"AssistFun4": assist_fun4,
|
||
"AssistFun5": assist_fun5,
|
||
"HoleNumbers": hole_numbers,
|
||
"LiquidDispensingMethod": liquid_method,
|
||
}
|
||
|
||
def UnLoad(
|
||
self,
|
||
dosage: int,
|
||
plate_no: int,
|
||
is_whole_plate: bool,
|
||
hole_row: int,
|
||
hole_col: int,
|
||
blending_times: int,
|
||
balance_height: int,
|
||
plate_or_hole: str,
|
||
hole_numbers: str,
|
||
assist_fun1: str = "",
|
||
assist_fun2: str = "",
|
||
assist_fun3: str = "",
|
||
assist_fun4: str = "",
|
||
assist_fun5: str = "",
|
||
liquid_method: str = "NormalDispense",
|
||
) -> Dict[str, Any]:
|
||
return {
|
||
"StepAxis": self.axis,
|
||
"Function": "UnLoad",
|
||
"DosageNum": dosage,
|
||
"PlateNo": plate_no,
|
||
"IsWholePlate": is_whole_plate,
|
||
"HoleRow": hole_row,
|
||
"HoleCol": hole_col,
|
||
"BlendingTimes": blending_times,
|
||
"BalanceHeight": balance_height,
|
||
"PlateOrHoleNum": plate_or_hole,
|
||
"AssistFun1": assist_fun1,
|
||
"AssistFun2": assist_fun2,
|
||
"AssistFun3": assist_fun3,
|
||
"AssistFun4": assist_fun4,
|
||
"AssistFun5": assist_fun5,
|
||
"HoleNumbers": hole_numbers,
|
||
"LiquidDispensingMethod": liquid_method,
|
||
}
|
||
|
||
|
||
if __name__ == "__main__":
|
||
# Example usage
|
||
# 1. 用导出的json,给每个T1 T2板子设定相应的物料,如果是孔板和枪头盒,要对应区分
|
||
# 2. backend需要支持num channel为1的情况
|
||
# 3. 设计一个单点动作流程,可以跑
|
||
# 4.
|
||
|
||
|
||
# deck = PRCXI9300Deck(name="PRCXI_Deck_9300", size_x=100, size_y=100, size_z=100)
|
||
|
||
# from pylabrobot.resources.opentrons.tip_racks import opentrons_96_tiprack_300ul,opentrons_96_tiprack_10ul
|
||
# from pylabrobot.resources.opentrons.plates import corning_96_wellplate_360ul_flat, nest_96_wellplate_2ml_deep
|
||
|
||
# def get_well_container(name: str) -> PRCXI9300Container:
|
||
# well_containers = corning_96_wellplate_360ul_flat(name).serialize()
|
||
# plate = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="plate",
|
||
# ordering=collections.OrderedDict())
|
||
# plate_serialized = plate.serialize()
|
||
# plate_serialized["parent_name"] = deck.name
|
||
# well_containers.update({k: v for k, v in plate_serialized.items() if k not in ["children"]})
|
||
# new_plate: PRCXI9300Container = PRCXI9300Container.deserialize(well_containers)
|
||
# return new_plate
|
||
|
||
# def get_tip_rack(name: str) -> PRCXI9300Container:
|
||
# tip_racks = opentrons_96_tiprack_300ul("name").serialize()
|
||
# tip_rack = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="tip_rack",
|
||
# ordering=collections.OrderedDict())
|
||
# tip_rack_serialized = tip_rack.serialize()
|
||
# tip_rack_serialized["parent_name"] = deck.name
|
||
# tip_racks.update({k: v for k, v in tip_rack_serialized.items() if k not in ["children"]})
|
||
# new_tip_rack: PRCXI9300Container = PRCXI9300Container.deserialize(tip_racks)
|
||
# return new_tip_rack
|
||
|
||
# plate1 = get_tip_rack("RackT1")
|
||
# plate1.load_state({
|
||
# "Material": {
|
||
# "uuid": "076250742950465b9d6ea29a225dfb00",
|
||
# "Code": "ZX-001-300",
|
||
# "Name": "300μL Tip头"
|
||
# }
|
||
# })
|
||
|
||
# plate2 = get_well_container("PlateT2")
|
||
# plate2.load_state({
|
||
# "Material": {
|
||
# "uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||
# "Code": "ZX-019-2.2",
|
||
# "Name": "96深孔板"
|
||
# }
|
||
# })
|
||
|
||
|
||
# plate3 = PRCXI9300Trash("trash", size_x=50, size_y=100, size_z=10, category="trash")
|
||
# plate3.load_state({
|
||
# "Material": {
|
||
# "uuid": "730067cf07ae43849ddf4034299030e9"
|
||
# }
|
||
# })
|
||
|
||
# plate4 = get_well_container("PlateT4")
|
||
# plate4.load_state({
|
||
# "Material": {
|
||
# "uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||
# "Code": "ZX-019-2.2",
|
||
# "Name": "96深孔板"
|
||
# }
|
||
# })
|
||
|
||
# plate5 = get_well_container("PlateT5")
|
||
# plate5.load_state({
|
||
# "Material": {
|
||
# "uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||
# "Code": "ZX-019-2.2",
|
||
# "Name": "96深孔板"
|
||
# }
|
||
# })
|
||
# plate6 = get_well_container("PlateT6")
|
||
|
||
# plate6.load_state({
|
||
# "Material": {
|
||
# "uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||
# "Code": "ZX-019-2.2",
|
||
# "Name": "96深孔板"
|
||
# }
|
||
# })
|
||
|
||
# deck.assign_child_resource(plate1, location=Coordinate(0, 0, 0))
|
||
# deck.assign_child_resource(plate2, location=Coordinate(0, 0, 0))
|
||
# deck.assign_child_resource(plate3, location=Coordinate(0, 0, 0))
|
||
# deck.assign_child_resource(plate4, location=Coordinate(0, 0, 0))
|
||
# deck.assign_child_resource(plate5, location=Coordinate(0, 0, 0))
|
||
# deck.assign_child_resource(plate6, location=Coordinate(0, 0, 0))
|
||
|
||
# # print(plate2)
|
||
# plate_2_liquids = [[('water', 500)]]*96
|
||
# plate2.set_well_liquids(plate_2_liquids)
|
||
|
||
# handler = PRCXI9300Handler(deck=deck, host="10.181.214.132", port=9999,
|
||
# timeout=10.0, setup=False, debug=False,
|
||
# matrix_id="71593",
|
||
# channel_num=8, axis="Left") # Initialize the handler with the deck and host settings
|
||
|
||
|
||
# handler.set_tiprack([plate1])
|
||
|
||
# asyncio.run(handler.setup()) # Initialize the handler and setup the connection
|
||
# from pylabrobot.resources import set_volume_tracking
|
||
# # from pylabrobot.resources import set_tip_tracking
|
||
# set_volume_tracking(enabled=True)
|
||
# from unilabos.resources.graphio import *
|
||
# A = tree_to_list([resource_plr_to_ulab(deck)])
|
||
# with open("deck_9300_new.json", "w", encoding="utf-8") as f:
|
||
# json.dump(A, f, indent=4, ensure_ascii=False)
|
||
# asyncio.run(handler.create_protocol(protocol_name="Test Protocol")) # Initialize the backend and setup the connection
|
||
|
||
# # asyncio.run(handler.pick_up_tips(plate1.children[:8],[0,1,2,3,4,5,6,7]))
|
||
# # print(plate1.children[:8])
|
||
# # asyncio.run(handler.aspirate(plate2.children[:8],[50]*8, [0,1,2,3,4,5,6,7]))
|
||
# # print(plate2.children[:8])
|
||
# # asyncio.run(handler.dispense(plate5.children[:8],[50]*8,[0,1,2,3,4,5,6,7]))
|
||
# # print(plate5.children[:8])
|
||
|
||
# # # # # asyncio.run(handler.drop_tips(tip_rack.children[8:16],[0,1,2,3,4,5,6,7]))
|
||
# # asyncio.run(handler.discard_tips())
|
||
|
||
# # asyncio.run(handler.mix(well_containers.children[:8
|
||
# # ], mix_time=3, mix_vol=50, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100))
|
||
# # #print(json.dumps(handler._unilabos_backend.steps_todo_list, indent=2)) # Print matrix info
|
||
# # asyncio.run(handler.add_liquid(
|
||
# # asp_vols=[100]*16,
|
||
# # dis_vols=[100]*16,
|
||
# # reagent_sources=plate2.children[:16],
|
||
# # targets=plate5.children[:16],
|
||
# # use_channels=[0, 1, 2, 3, 4, 5, 6, 7],
|
||
# # flow_rates=[None] * 32,
|
||
# # offsets=[Coordinate(0, 0, 0)] * 32,
|
||
# # liquid_height=[None] * 16,
|
||
# # blow_out_air_volume=[None] * 16,
|
||
# # delays=None,
|
||
# # mix_time=3,
|
||
# # mix_vol=50,
|
||
# # spread="wide",
|
||
# # ))
|
||
# # asyncio.run(handler.run_protocol()) # Run the protocol
|
||
# # asyncio.run(handler.remove_liquid(
|
||
# # vols=[100]*16,
|
||
# # sources=plate2.children[-16:],
|
||
# # waste_liquid=plate5.children[:16], # 这个有些奇怪,但是好像也只能这么写
|
||
# # use_channels=[0, 1, 2, 3, 4, 5, 6, 7],
|
||
# # flow_rates=[None] * 32,
|
||
# # offsets=[Coordinate(0, 0, 0)] * 32,
|
||
# # liquid_height=[None] * 32,
|
||
# # blow_out_air_volume=[None] * 32,
|
||
# # spread="wide",
|
||
# # ))
|
||
|
||
# acid = [20]*8+[40]*8+[60]*8+[80]*8+[100]*8+[120]*8+[140]*8+[160]*8+[180]*8+[200]*8+[220]*8+[240]*8
|
||
# alkaline = acid[::-1] # Reverse the acid list for alkaline
|
||
# asyncio.run(handler.transfer_liquid(
|
||
# asp_vols=acid,
|
||
# dis_vols=acid,
|
||
# tip_racks=[plate1],
|
||
# sources=plate2.children[:],
|
||
# targets=plate5.children[:],
|
||
# use_channels=[0, 1, 2, 3, 4, 5, 6, 7],
|
||
# offsets=[Coordinate(0, 0, 0)] * 32,
|
||
# asp_flow_rates=[None] * 16,
|
||
# dis_flow_rates=[None] * 16,
|
||
# liquid_height=[None] * 32,
|
||
# blow_out_air_volume=[None] * 32,
|
||
# mix_times=3,
|
||
# mix_vol=50,
|
||
# spread="wide",
|
||
# ))
|
||
# asyncio.run(handler.run_protocol()) # Run the protocol
|
||
# # # input("Running protocol...")
|
||
# # # input("Press Enter to continue...") # Wait for user input before proceeding
|
||
# # # print("PRCXI9300Handler initialized with deck and host settings.")
|
||
|
||
# # Example usage
|
||
# # 1. 用导出的json,给每个T1 T2板子设定相应的物料,如果是孔板和枪头盒,要对应区分
|
||
# # 2. 设计一个单点动作流程,可以跑
|
||
# # 3.
|
||
|
||
|
||
deck = PRCXI9300Deck(name="PRCXI_Deck", size_x=100, size_y=100, size_z=100)
|
||
|
||
from pylabrobot.resources.opentrons.tip_racks import tipone_96_tiprack_200ul,opentrons_96_tiprack_10ul
|
||
from pylabrobot.resources.opentrons.plates import corning_96_wellplate_360ul_flat, nest_96_wellplate_2ml_deep
|
||
|
||
def get_well_container(name: str) -> PRCXI9300Container:
|
||
well_containers = corning_96_wellplate_360ul_flat(name).serialize()
|
||
plate = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="plate",
|
||
ordering=collections.OrderedDict())
|
||
plate_serialized = plate.serialize()
|
||
plate_serialized["parent_name"] = deck.name
|
||
well_containers.update({k: v for k, v in plate_serialized.items() if k not in ["children"]})
|
||
new_plate: PRCXI9300Container = PRCXI9300Container.deserialize(well_containers)
|
||
return new_plate
|
||
|
||
def get_tip_rack(name: str) -> PRCXI9300Container:
|
||
tip_racks = opentrons_96_tiprack_10ul("name").serialize()
|
||
tip_rack = PRCXI9300Container(name=name, size_x=50, size_y=50, size_z=10, category="tip_rack",
|
||
ordering=collections.OrderedDict())
|
||
tip_rack_serialized = tip_rack.serialize()
|
||
tip_rack_serialized["parent_name"] = deck.name
|
||
tip_racks.update({k: v for k, v in tip_rack_serialized.items() if k not in ["children"]})
|
||
new_tip_rack: PRCXI9300Container = PRCXI9300Container.deserialize(tip_racks)
|
||
return new_tip_rack
|
||
|
||
plate1 = get_well_container("HPLCPlateT1")
|
||
plate1.load_state({
|
||
"Material": {
|
||
"uuid": "548bbc3df0d4447586f2c19d2c0c0c55",
|
||
"Code": "HPLC01",
|
||
"Name": "HPLC料盘"
|
||
}
|
||
})
|
||
plate2 = get_well_container("PlateT2")
|
||
plate2.load_state({
|
||
"Material": {
|
||
"uuid": "04211a2dc93547fe9bf6121eac533650",
|
||
}
|
||
})
|
||
plate3 = get_well_container("PlateT3")
|
||
plate3.load_state({
|
||
"Material": {
|
||
"uuid": "04211a2dc93547fe9bf6121eac533650",
|
||
}
|
||
})
|
||
trash = PRCXI9300Trash(name="trash", size_x=50, size_y=50, size_z=10, category="trash")
|
||
trash.load_state({
|
||
"Material": {
|
||
"uuid": "730067cf07ae43849ddf4034299030e9"
|
||
}
|
||
})
|
||
plate5 = get_well_container("PlateT5")
|
||
plate5.load_state({
|
||
"Material": {
|
||
"uuid": "04211a2dc93547fe9bf6121eac533650",
|
||
}
|
||
})
|
||
plate6 = get_well_container("PlateT6")
|
||
plate6.load_state({
|
||
"Material": {
|
||
"uuid": "04211a2dc93547fe9bf6121eac533650"
|
||
}
|
||
})
|
||
plate7 = PRCXI9300Container(name="plateT7", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict())
|
||
plate7.load_state({
|
||
"Material": {
|
||
"uuid": "04211a2dc93547fe9bf6121eac533650"
|
||
}
|
||
})
|
||
plate8 = get_tip_rack("RackT8")
|
||
plate8.load_state({
|
||
"Material": {
|
||
"uuid": "068b3815e36b4a72a59bae017011b29f",
|
||
"Code": "ZX-001-10+",
|
||
"Name": "10μL加长 Tip头"
|
||
}
|
||
})
|
||
plate9 = get_well_container("PlateT9")
|
||
plate9.load_state({
|
||
"Material": {
|
||
"uuid": "04211a2dc93547fe9bf6121eac533650"
|
||
}
|
||
})
|
||
plate10 = get_well_container("PlateT10")
|
||
plate10.load_state({
|
||
"Material": {
|
||
"uuid": "04211a2dc93547fe9bf6121eac533650"
|
||
}
|
||
})
|
||
plate11 = get_well_container("PlateT11")
|
||
plate11.load_state({
|
||
"Material": {
|
||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||
}
|
||
})
|
||
plate12 = get_well_container("PlateT12")
|
||
plate12.load_state({
|
||
"Material": {
|
||
"uuid": "04211a2dc93547fe9bf6121eac533650"
|
||
}
|
||
})
|
||
plate13 = get_well_container("PlateT13")
|
||
plate13.load_state({
|
||
"Material": {
|
||
"uuid": "04211a2dc93547fe9bf6121eac533650"
|
||
}
|
||
})
|
||
|
||
# container_for_nothing = PRCXI9300Container(name="container_for_nothing", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict())
|
||
|
||
deck.assign_child_resource(plate1, location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing1", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing2", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(trash, location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing3", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing4", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(plate8, location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing5", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing6", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(plate11, location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing7", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0))
|
||
deck.assign_child_resource(PRCXI9300Container(name="container_for_nothing8", size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()), location=Coordinate(0, 0, 0))
|
||
|
||
handler = PRCXI9300Handler(deck=deck, host="10.181.102.13", port=9999,
|
||
timeout=10.0, setup=False, debug=False,
|
||
matrix_id="fd383e6d-2d0e-40b5-9c01-1b2870b1f1b1",
|
||
channel_num=1, axis="Right") # Initialize the handler with the deck and host settings
|
||
|
||
handler.set_tiprack([plate8]) # Set the tip rack for the handler
|
||
asyncio.run(handler.setup()) # Initialize the handler and setup the connection
|
||
from pylabrobot.resources import set_volume_tracking
|
||
# from pylabrobot.resources import set_tip_tracking
|
||
set_volume_tracking(enabled=True)
|
||
|
||
plate11.set_well_liquids([("Water", 100) if (i % 8 == 0 and i // 8 < 6) else (None, 100) for i in range(96)]) # Set liquids for every 8 wells in plate8
|
||
|
||
from unilabos.resources.graphio import *
|
||
|
||
A = tree_to_list([resource_plr_to_ulab(deck)])
|
||
# with open("deck.json", "w", encoding="utf-8") as f:
|
||
# json.dump(A, f, indent=4, ensure_ascii=False)
|
||
|
||
print(plate11.get_well(0).tracker.get_used_volume())
|
||
asyncio.run(handler.create_protocol(protocol_name="Test Protocol")) # Initialize the backend and setup the connection
|
||
|
||
# asyncio.run(handler.pick_up_tips([plate8.children[8]],[0]))
|
||
# print(plate8.children[8])
|
||
# # asyncio.run(handler.run_protocol())
|
||
# asyncio.run(handler.aspirate([plate11.children[0]],[10], [0]))
|
||
# print(plate11.children[0])
|
||
# # asyncio.run(handler.run_protocol())
|
||
# asyncio.run(handler.dispense([plate1.children[0]],[10],[0]))
|
||
# print(plate1.children[0])
|
||
# # asyncio.run(handler.run_protocol())
|
||
# asyncio.run(handler.mix([plate1.children[0]], mix_time=3, mix_vol=5, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100))
|
||
# print(plate1.children[0])
|
||
# asyncio.run(handler.discard_tips())
|
||
|
||
asyncio.run(handler.add_liquid(
|
||
asp_vols=[10]*7,
|
||
dis_vols=[10]*7,
|
||
reagent_sources=plate11.children[:7],
|
||
targets=plate1.children[2:9],
|
||
use_channels=[0],
|
||
flow_rates=[None] * 7,
|
||
offsets=[Coordinate(0, 0, 0)] * 7,
|
||
liquid_height=[None] * 7,
|
||
blow_out_air_volume=[None] * 2,
|
||
delays=None,
|
||
mix_time=3,
|
||
mix_vol=5,
|
||
spread="custom",
|
||
))
|
||
|
||
asyncio.run(handler.run_protocol()) # Run the protocol
|
||
# # asyncio.run(handler.transfer_liquid(
|
||
# # asp_vols=[10]*2,
|
||
# # dis_vols=[10]*2,
|
||
# # sources=plate11.children[:2],
|
||
# # targets=plate11.children[-2:],
|
||
# # use_channels=[0],
|
||
# # offsets=[Coordinate(0, 0, 0)] * 4,
|
||
# # liquid_height=[None] * 2,
|
||
# # blow_out_air_volume=[None] * 2,
|
||
# # delays=None,
|
||
# # mix_times=3,
|
||
# # mix_vol=5,
|
||
# # spread="wide",
|
||
# # tip_racks=[plate8]
|
||
# # ))
|
||
|
||
# # asyncio.run(handler.remove_liquid(
|
||
# # vols=[10]*2,
|
||
# # sources=plate11.children[:2],
|
||
# # waste_liquid=plate11.children[43],
|
||
# # use_channels=[0],
|
||
# # offsets=[Coordinate(0, 0, 0)] * 4,
|
||
# # liquid_height=[None] * 2,
|
||
# # blow_out_air_volume=[None] * 2,
|
||
# # delays=None,
|
||
# # spread="wide"
|
||
# # ))
|
||
# asyncio.run(handler.run_protocol())
|
||
|
||
# # asyncio.run(handler.discard_tips())
|
||
# # asyncio.run(handler.mix(well_containers.children[:8
|
||
# # ], mix_time=3, mix_vol=50, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100))
|
||
# #print(json.dumps(handler._unilabos_backend.steps_todo_list, indent=2)) # Print matrix info
|
||
|
||
|
||
# # asyncio.run(handler.remove_liquid(
|
||
# # vols=[100]*16,
|
||
# # sources=well_containers.children[-16:],
|
||
# # waste_liquid=well_containers.children[:16], # 这个有些奇怪,但是好像也只能这么写
|
||
# # use_channels=[0, 1, 2, 3, 4, 5, 6, 7],
|
||
# # flow_rates=[None] * 32,
|
||
# # offsets=[Coordinate(0, 0, 0)] * 32,
|
||
# # liquid_height=[None] * 32,
|
||
# # blow_out_air_volume=[None] * 32,
|
||
# # spread="wide",
|
||
# # ))
|
||
# # asyncio.run(handler.transfer_liquid(
|
||
# # asp_vols=[100]*16,
|
||
# # dis_vols=[100]*16,
|
||
# # tip_racks=[tip_rack],
|
||
# # sources=well_containers.children[-16:],
|
||
# # targets=well_containers.children[:16],
|
||
# # use_channels=[0, 1, 2, 3, 4, 5, 6, 7],
|
||
# # offsets=[Coordinate(0, 0, 0)] * 32,
|
||
# # asp_flow_rates=[None] * 16,
|
||
# # dis_flow_rates=[None] * 16,
|
||
# # liquid_height=[None] * 32,
|
||
# # blow_out_air_volume=[None] * 32,
|
||
# # mix_times=3,
|
||
# # mix_vol=50,
|
||
# # spread="wide",
|
||
# # ))
|
||
print(json.dumps(handler._unilabos_backend.steps_todo_list, indent=2)) # Print matrix info
|
||
# # input("pick_up_tips add step")
|
||
# #asyncio.run(handler.run_protocol()) # Run the protocol
|
||
# # input("Running protocol...")
|
||
# # input("Press Enter to continue...") # Wait for user input before proceeding
|
||
# # print("PRCXI9300Handler initialized with deck and host settings.")
|
||
|