mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2026-02-04 13:25:13 +00:00
Merge dptech/workstation_dev_YB4: resolve conflicts by keeping local changes (ours)
This commit is contained in:
14473
bioyond_yihua_YB.json
Normal file
14473
bioyond_yihua_YB.json
Normal file
File diff suppressed because it is too large
Load Diff
2521
button_battery_station_resources_unilab.json
Normal file
2521
button_battery_station_resources_unilab.json
Normal file
File diff suppressed because it is too large
Load Diff
54
new_cellconfig.json
Normal file
54
new_cellconfig.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "BatteryStation",
|
||||
"name": "扣电工作站",
|
||||
"parent": null,
|
||||
"children": [
|
||||
"coin_cell_deck"
|
||||
],
|
||||
"type": "device",
|
||||
"class":"coincellassemblyworkstation_device",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"deck": {
|
||||
"data": {
|
||||
"_resource_child_name": "YB_YH_Deck",
|
||||
"_resource_type": "unilabos.devices.workstation.coin_cell_assembly.YB_YH_materials:CoincellDeck"
|
||||
}
|
||||
},
|
||||
"debug_mode": true,
|
||||
"protocol_type": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "YB_YH_Deck",
|
||||
"name": "YB_YH_Deck",
|
||||
"children": [],
|
||||
"parent": "BatteryStation",
|
||||
"type": "deck",
|
||||
"class": "CoincellDeck",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"type": "CoincellDeck",
|
||||
"setup": true,
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"type": "Rotation"
|
||||
}
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
],
|
||||
"links": []
|
||||
}
|
||||
72
test/experiments/reaction_station_bioyond.json
Normal file
72
test/experiments/reaction_station_bioyond.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "reaction_station_bioyond",
|
||||
"name": "reaction_station_bioyond",
|
||||
"parent": null,
|
||||
"children": [
|
||||
"Bioyond_Deck"
|
||||
],
|
||||
"type": "device",
|
||||
"class": "reaction_station.bioyond",
|
||||
"config": {
|
||||
"config": {
|
||||
"api_key": "DE9BDDA0",
|
||||
"api_host": "http://192.168.1.200:44402",
|
||||
"workflow_mappings": {
|
||||
"reactor_taken_out": "3a16081e-4788-ca37-eff4-ceed8d7019d1",
|
||||
"reactor_taken_in": "3a160df6-76b3-0957-9eb0-cb496d5721c6",
|
||||
"Solid_feeding_vials": "3a160877-87e7-7699-7bc6-ec72b05eb5e6",
|
||||
"Liquid_feeding_vials(non-titration)": "3a167d99-6158-c6f0-15b5-eb030f7d8e47",
|
||||
"Liquid_feeding_solvents": "3a160824-0665-01ed-285a-51ef817a9046",
|
||||
"Liquid_feeding(titration)": "3a16082a-96ac-0449-446a-4ed39f3365b6",
|
||||
"liquid_feeding_beaker": "3a16087e-124f-8ddb-8ec1-c2dff09ca784",
|
||||
"Drip_back": "3a162cf9-6aac-565a-ddd7-682ba1796a4a"
|
||||
},
|
||||
"material_type_mappings": {
|
||||
"烧杯": ["YB_1FlaskCarrier", "3a14196b-24f2-ca49-9081-0cab8021bf1a"],
|
||||
"试剂瓶": ["YB_1BottleCarrier", ""],
|
||||
"样品板": ["YB_6StockCarrier", "3a14196e-b7a0-a5da-1931-35f3000281e9"],
|
||||
"分装板": ["YB_6VialCarrier", "3a14196e-5dfe-6e21-0c79-fe2036d052c4"],
|
||||
"样品瓶": ["YB_Solid_Stock", "3a14196a-cf7d-8aea-48d8-b9662c7dba94"],
|
||||
"90%分装小瓶": ["YB_Solid_Vial", "3a14196c-cdcf-088d-dc7d-5cf38f0ad9ea"],
|
||||
"10%分装小瓶": ["YB_Liquid_Vial", "3a14196c-76be-2279-4e22-7310d69aed68"]
|
||||
}
|
||||
},
|
||||
"deck": {
|
||||
"data": {
|
||||
"_resource_child_name": "Bioyond_Deck",
|
||||
"_resource_type": "unilabos.resources.bioyond.decks:BIOYOND_PolymerReactionStation_Deck"
|
||||
}
|
||||
},
|
||||
"protocol_type": []
|
||||
},
|
||||
"data": {}
|
||||
},
|
||||
{
|
||||
"id": "Bioyond_Deck",
|
||||
"name": "Bioyond_Deck",
|
||||
"children": [
|
||||
],
|
||||
"parent": "reaction_station_bioyond",
|
||||
"type": "deck",
|
||||
"class": "BIOYOND_PolymerReactionStation_Deck",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"type": "BIOYOND_PolymerReactionStation_Deck",
|
||||
"setup": true,
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"type": "Rotation"
|
||||
}
|
||||
},
|
||||
"data": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
52
test/resources/YB_materials_info.json
Normal file
52
test/resources/YB_materials_info.json
Normal file
@@ -0,0 +1,52 @@
|
||||
[
|
||||
{
|
||||
"id": "3a1d377b-299d-d0f2-ced9-48257f60dfad",
|
||||
"typeName": "加样头(大)",
|
||||
"code": "0005-00145",
|
||||
"barCode": "",
|
||||
"name": "LiDFOB",
|
||||
"quantity": 9999.0,
|
||||
"lockQuantity": 0.0,
|
||||
"unit": "个",
|
||||
"status": 1,
|
||||
"isUse": false,
|
||||
"locations": [
|
||||
{
|
||||
"id": "3a19da56-1379-ff7c-1745-07e200b44ce2",
|
||||
"whid": "3a19da56-1378-613b-29f2-871e1a287aa5",
|
||||
"whName": "粉末加样头堆栈",
|
||||
"code": "0005-0001",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1,
|
||||
"quantity": 0
|
||||
}
|
||||
],
|
||||
"detail": []
|
||||
},
|
||||
{
|
||||
"id": "3a1d377b-6a81-6a7e-147c-f89f6463656d",
|
||||
"typeName": "液",
|
||||
"code": "0006-00141",
|
||||
"barCode": "",
|
||||
"name": "EMC",
|
||||
"quantity": 99999.0,
|
||||
"lockQuantity": 0.0,
|
||||
"unit": "g",
|
||||
"status": 1,
|
||||
"isUse": false,
|
||||
"locations": [
|
||||
{
|
||||
"id": "3a1baa20-a7b1-c665-8b9c-d8099d07d2f6",
|
||||
"whid": "3a1baa20-a7b0-5c19-8844-5de8924d4e78",
|
||||
"whName": "4号手套箱内部堆栈",
|
||||
"code": "0015-0001",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1,
|
||||
"quantity": 0
|
||||
}
|
||||
],
|
||||
"detail": []
|
||||
}
|
||||
]
|
||||
99
test/resources/test copy.json
Normal file
99
test/resources/test copy.json
Normal file
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"typeId": "3a190c8b-3284-af78-d29f-9a69463ad047",
|
||||
"code": "",
|
||||
"barCode": "",
|
||||
"name": "test",
|
||||
"unit": "",
|
||||
"parameters": "{}",
|
||||
"quantity": "",
|
||||
"details": [
|
||||
{
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb",
|
||||
"code": "",
|
||||
"name": "配液瓶(小)11",
|
||||
"quantity": "1",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1,
|
||||
"unit": "",
|
||||
"parameters": "{}"
|
||||
},
|
||||
{
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb",
|
||||
"code": "",
|
||||
"name": "配液瓶(小)21",
|
||||
"quantity": "1",
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"z": 1,
|
||||
"unit": "",
|
||||
"parameters": "{}"
|
||||
},
|
||||
{
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb",
|
||||
"code": "",
|
||||
"name": "配液瓶(小)12",
|
||||
"quantity": "1",
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
"z": 1,
|
||||
"unit": "",
|
||||
"parameters": "{}"
|
||||
},
|
||||
{
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb",
|
||||
"code": "",
|
||||
"name": "配液瓶(小)22",
|
||||
"quantity": "1",
|
||||
"x": 2,
|
||||
"y": 2,
|
||||
"z": 1,
|
||||
"unit": "",
|
||||
"parameters": "{}"
|
||||
},
|
||||
{
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb",
|
||||
"code": "",
|
||||
"name": "配液瓶(小)13",
|
||||
"quantity": "1",
|
||||
"x": 1,
|
||||
"y": 3,
|
||||
"z": 1,
|
||||
"unit": "",
|
||||
"parameters": "{}"
|
||||
},
|
||||
{
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb",
|
||||
"code": "",
|
||||
"name": "配液瓶(小)23",
|
||||
"quantity": "1",
|
||||
"x": 2,
|
||||
"y": 3,
|
||||
"z": 1,
|
||||
"unit": "",
|
||||
"parameters": "{}"
|
||||
},
|
||||
{
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb",
|
||||
"code": "",
|
||||
"name": "配液瓶(小)14",
|
||||
"quantity": "1",
|
||||
"x": 1,
|
||||
"y": 4,
|
||||
"z": 1,
|
||||
"unit": "",
|
||||
"parameters": "{}"
|
||||
},
|
||||
{
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb",
|
||||
"code": "",
|
||||
"name": "配液瓶(小)24",
|
||||
"quantity": "1",
|
||||
"x": 2,
|
||||
"y": 4,
|
||||
"z": 1,
|
||||
"unit": "",
|
||||
"parameters": "{}"
|
||||
}
|
||||
]
|
||||
}
|
||||
148
test/resources/test.json
Normal file
148
test/resources/test.json
Normal file
@@ -0,0 +1,148 @@
|
||||
[
|
||||
{
|
||||
"id": "3a1d4c14-a9fb-d7dc-9e96-7a3ad6e50219",
|
||||
"typeName": "配液瓶(小)板",
|
||||
"code": "0001-00093",
|
||||
"barCode": "",
|
||||
"name": "test",
|
||||
"quantity": 2.0,
|
||||
"lockQuantity": 0.0,
|
||||
"unit": "块",
|
||||
"status": 1,
|
||||
"isUse": false,
|
||||
"locations": [
|
||||
{
|
||||
"id": "3a19deae-2c7a-36f5-5e41-02c5b66feaea",
|
||||
"whid": "3a19deae-2c79-05a3-9c76-8e6760424841",
|
||||
"whName": "手动堆栈",
|
||||
"code": "1",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1,
|
||||
"quantity": 0
|
||||
}
|
||||
],
|
||||
"detail": [
|
||||
{
|
||||
"id": "3a1d4c14-a9fc-1daa-71fa-146cb1ccb930",
|
||||
"detailMaterialId": "3a1d4c14-a9fc-4f38-4c48-68486c391c42",
|
||||
"code": "0001-00093 - 05",
|
||||
"name": "配液瓶(小)",
|
||||
"quantity": "1",
|
||||
"lockQuantity": "0",
|
||||
"unit": "个",
|
||||
"x": 1,
|
||||
"y": 3,
|
||||
"z": 1,
|
||||
"associateId": null,
|
||||
"typeName": "配液瓶(小)",
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"
|
||||
},
|
||||
{
|
||||
"id": "3a1d4c14-a9fc-3659-ea61-cd587da9e131",
|
||||
"detailMaterialId": "3a1d4c14-a9fc-018f-93e5-c49343d37758",
|
||||
"code": "0001-00093 - 08",
|
||||
"name": "配液瓶(小)",
|
||||
"quantity": "1",
|
||||
"lockQuantity": "0",
|
||||
"unit": "个",
|
||||
"x": 2,
|
||||
"y": 4,
|
||||
"z": 1,
|
||||
"associateId": null,
|
||||
"typeName": "配液瓶(小)",
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"
|
||||
},
|
||||
{
|
||||
"id": "3a1d4c14-a9fc-3f94-de83-979d2646e313",
|
||||
"detailMaterialId": "3a1d4c14-a9fc-9987-c0ef-4b7cbad49e6b",
|
||||
"code": "0001-00093 - 01",
|
||||
"name": "配液瓶(小)",
|
||||
"quantity": "1",
|
||||
"lockQuantity": "0",
|
||||
"unit": "个",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1,
|
||||
"associateId": null,
|
||||
"typeName": "配液瓶(小)",
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"
|
||||
},
|
||||
{
|
||||
"id": "3a1d4c14-a9fc-8c35-6b25-913b11dbaf4e",
|
||||
"detailMaterialId": "3a1d4c14-a9fc-9a83-865b-0c26ea5e8cc4",
|
||||
"code": "0001-00093 - 03",
|
||||
"name": "配液瓶(小)",
|
||||
"quantity": "1",
|
||||
"lockQuantity": "0",
|
||||
"unit": "个",
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
"z": 1,
|
||||
"associateId": null,
|
||||
"typeName": "配液瓶(小)",
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"
|
||||
},
|
||||
{
|
||||
"id": "3a1d4c14-a9fc-b41f-e968-64953bfddccd",
|
||||
"detailMaterialId": "3a1d4c14-a9fc-daf7-9d64-e5ec8d3ae0e2",
|
||||
"code": "0001-00093 - 07",
|
||||
"name": "配液瓶(小)",
|
||||
"quantity": "1",
|
||||
"lockQuantity": "0",
|
||||
"unit": "个",
|
||||
"x": 1,
|
||||
"y": 4,
|
||||
"z": 1,
|
||||
"associateId": null,
|
||||
"typeName": "配液瓶(小)",
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"
|
||||
},
|
||||
{
|
||||
"id": "3a1d4c14-a9fc-c20f-c26e-b1bb2cdc3bca",
|
||||
"detailMaterialId": "3a1d4c14-a9fc-673b-ac83-aaaf71287f1f",
|
||||
"code": "0001-00093 - 06",
|
||||
"name": "配液瓶(小)",
|
||||
"quantity": "1",
|
||||
"lockQuantity": "0",
|
||||
"unit": "个",
|
||||
"x": 2,
|
||||
"y": 3,
|
||||
"z": 1,
|
||||
"associateId": null,
|
||||
"typeName": "配液瓶(小)",
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"
|
||||
},
|
||||
{
|
||||
"id": "3a1d4c14-a9fc-cf21-059c-fde361d82b6f",
|
||||
"detailMaterialId": "3a1d4c14-a9fc-25b1-e736-6b0d8dac0fae",
|
||||
"code": "0001-00093 - 02",
|
||||
"name": "配液瓶(小)",
|
||||
"quantity": "1",
|
||||
"lockQuantity": "0",
|
||||
"unit": "个",
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"z": 1,
|
||||
"associateId": null,
|
||||
"typeName": "配液瓶(小)",
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"
|
||||
},
|
||||
{
|
||||
"id": "3a1d4c14-a9fc-d732-2b93-9b2bd2bf581b",
|
||||
"detailMaterialId": "3a1d4c14-a9fc-7f5d-b6b6-8bcb2e15f320",
|
||||
"code": "0001-00093 - 04",
|
||||
"name": "配液瓶(小)",
|
||||
"quantity": "1",
|
||||
"lockQuantity": "0",
|
||||
"unit": "个",
|
||||
"x": 2,
|
||||
"y": 2,
|
||||
"z": 1,
|
||||
"associateId": null,
|
||||
"typeName": "配液瓶(小)",
|
||||
"typeId": "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,7 +1,7 @@
|
||||
import pytest
|
||||
|
||||
from unilabos.resources.bioyond.bottle_carriers import BIOYOND_Electrolyte_6VialCarrier, BIOYOND_Electrolyte_1BottleCarrier
|
||||
from unilabos.resources.bioyond.bottles import BIOYOND_PolymerStation_Solid_Vial, BIOYOND_PolymerStation_Solution_Beaker, BIOYOND_PolymerStation_Reagent_Bottle
|
||||
from unilabos.resources.bioyond.bottles import YB_Solid_Vial, YB_Solution_Beaker, YB_Reagent_Bottle
|
||||
|
||||
|
||||
def test_bottle_carrier() -> "BottleCarrier":
|
||||
@@ -16,9 +16,9 @@ def test_bottle_carrier() -> "BottleCarrier":
|
||||
print(f"1烧杯载架: {beaker_carrier.name}, 位置数: {len(beaker_carrier.sites)}")
|
||||
|
||||
# 创建瓶子和烧杯
|
||||
powder_bottle = BIOYOND_PolymerStation_Solid_Vial("powder_bottle_01")
|
||||
solution_beaker = BIOYOND_PolymerStation_Solution_Beaker("solution_beaker_01")
|
||||
reagent_bottle = BIOYOND_PolymerStation_Reagent_Bottle("reagent_bottle_01")
|
||||
powder_bottle = YB_Solid_Vial("powder_bottle_01")
|
||||
solution_beaker = YB_Solution_Beaker("solution_beaker_01")
|
||||
reagent_bottle = YB_Reagent_Bottle("reagent_bottle_01")
|
||||
|
||||
print(f"\n创建的物料:")
|
||||
print(f"粉末瓶: {powder_bottle.name} - {powder_bottle.diameter}mm x {powder_bottle.height}mm, {powder_bottle.max_volume}μL")
|
||||
|
||||
@@ -12,13 +12,13 @@ lab_registry.setup()
|
||||
|
||||
|
||||
type_mapping = {
|
||||
"烧杯": ("BIOYOND_PolymerStation_1FlaskCarrier", "3a14196b-24f2-ca49-9081-0cab8021bf1a"),
|
||||
"试剂瓶": ("BIOYOND_PolymerStation_1BottleCarrier", ""),
|
||||
"样品板": ("BIOYOND_PolymerStation_6StockCarrier", "3a14196e-b7a0-a5da-1931-35f3000281e9"),
|
||||
"分装板": ("BIOYOND_PolymerStation_6VialCarrier", "3a14196e-5dfe-6e21-0c79-fe2036d052c4"),
|
||||
"样品瓶": ("BIOYOND_PolymerStation_Solid_Stock", "3a14196a-cf7d-8aea-48d8-b9662c7dba94"),
|
||||
"90%分装小瓶": ("BIOYOND_PolymerStation_Solid_Vial", "3a14196c-cdcf-088d-dc7d-5cf38f0ad9ea"),
|
||||
"10%分装小瓶": ("BIOYOND_PolymerStation_Liquid_Vial", "3a14196c-76be-2279-4e22-7310d69aed68"),
|
||||
"烧杯": ("YB_1FlaskCarrier", "3a14196b-24f2-ca49-9081-0cab8021bf1a"),
|
||||
"试剂瓶": ("YB_1BottleCarrier", ""),
|
||||
"样品板": ("YB_6StockCarrier", "3a14196e-b7a0-a5da-1931-35f3000281e9"),
|
||||
"分装板": ("YB_6VialCarrier", "3a14196e-5dfe-6e21-0c79-fe2036d052c4"),
|
||||
"样品瓶": ("YB_Solid_Stock", "3a14196a-cf7d-8aea-48d8-b9662c7dba94"),
|
||||
"90%分装小瓶": ("YB_Solid_Vial", "3a14196c-cdcf-088d-dc7d-5cf38f0ad9ea"),
|
||||
"10%分装小瓶": ("YB_Liquid_Vial", "3a14196c-76be-2279-4e22-7310d69aed68"),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from ast import If
|
||||
import pytest
|
||||
import json
|
||||
import os
|
||||
@@ -8,18 +9,16 @@ from unilabos.ros.nodes.resource_tracker import ResourceTreeSet
|
||||
from unilabos.registry.registry import lab_registry
|
||||
|
||||
from unilabos.resources.bioyond.decks import BIOYOND_PolymerReactionStation_Deck
|
||||
from unilabos.resources.bioyond.decks import YB_Deck
|
||||
|
||||
lab_registry.setup()
|
||||
|
||||
|
||||
type_mapping = {
|
||||
"烧杯": ("BIOYOND_PolymerStation_1FlaskCarrier", "3a14196b-24f2-ca49-9081-0cab8021bf1a"),
|
||||
"试剂瓶": ("BIOYOND_PolymerStation_1BottleCarrier", ""),
|
||||
"样品板": ("BIOYOND_PolymerStation_6StockCarrier", "3a14196e-b7a0-a5da-1931-35f3000281e9"),
|
||||
"分装板": ("BIOYOND_PolymerStation_6VialCarrier", "3a14196e-5dfe-6e21-0c79-fe2036d052c4"),
|
||||
"样品瓶": ("BIOYOND_PolymerStation_Solid_Stock", "3a14196a-cf7d-8aea-48d8-b9662c7dba94"),
|
||||
"90%分装小瓶": ("BIOYOND_PolymerStation_Solid_Vial", "3a14196c-cdcf-088d-dc7d-5cf38f0ad9ea"),
|
||||
"10%分装小瓶": ("BIOYOND_PolymerStation_Liquid_Vial", "3a14196c-76be-2279-4e22-7310d69aed68"),
|
||||
"加样头(大)": ("YB_jia_yang_tou_da", "3a190ca0-b2f6-9aeb-8067-547e72c11469"),
|
||||
"液": ("YB_1BottleCarrier", "3a190ca1-2add-2b23-f8e1-bbd348b7f790"),
|
||||
"配液瓶(小)板": ("YB_peiyepingxiaoban", "3a190c8b-3284-af78-d29f-9a69463ad047"),
|
||||
"配液瓶(小)": ("YB_pei_ye_xiao_Bottler", "3a190c8c-fe8f-bf48-0dc3-97afc7f508eb"),
|
||||
}
|
||||
|
||||
|
||||
@@ -57,12 +56,20 @@ def bioyond_materials_liquidhandling_2() -> list[dict]:
|
||||
"bioyond_materials_reaction",
|
||||
"bioyond_materials_liquidhandling_1",
|
||||
])
|
||||
def test_resourcetreeset_from_plr(materials_fixture, request) -> list[dict]:
|
||||
materials = request.getfixturevalue(materials_fixture)
|
||||
deck = BIOYOND_PolymerReactionStation_Deck("test_deck")
|
||||
def test_resourcetreeset_from_plr() -> list[dict]:
|
||||
# 直接加载 bioyond_materials_reaction.json 文件
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
json_path = os.path.join(current_dir, "test.json")
|
||||
with open(json_path, "r", encoding="utf-8") as f:
|
||||
materials = json.load(f)
|
||||
deck = YB_Deck("test_deck")
|
||||
output = resource_bioyond_to_plr(materials, type_mapping=type_mapping, deck=deck)
|
||||
print(deck.summary())
|
||||
print(output)
|
||||
# print(deck.summary())
|
||||
|
||||
r = ResourceTreeSet.from_plr_resources([deck])
|
||||
print(r.dump())
|
||||
# json.dump(deck.serialize(), open("test.json", "w", encoding="utf-8"), indent=4)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_resourcetreeset_from_plr()
|
||||
|
||||
@@ -421,7 +421,7 @@ class MessageProcessor:
|
||||
ssl_context = ssl_module.create_default_context()
|
||||
|
||||
ws_logger = logging.getLogger("websockets.client")
|
||||
ws_logger.setLevel(logging.INFO)
|
||||
# 日志级别已在 unilabos.utils.log 中统一配置为 WARNING
|
||||
|
||||
async with websockets.connect(
|
||||
self.websocket_url,
|
||||
@@ -1240,7 +1240,7 @@ class WebSocketClient(BaseCommunicationClient):
|
||||
},
|
||||
}
|
||||
self.message_processor.send_message(message)
|
||||
logger.debug(f"[WebSocketClient] Device status published: {device_id}.{property_name}")
|
||||
logger.trace(f"[WebSocketClient] Device status published: {device_id}.{property_name}")
|
||||
|
||||
def publish_job_status(
|
||||
self, feedback_data: dict, item: QueueItem, status: str, return_info: Optional[dict] = None
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import serial
|
||||
import time
|
||||
import csv
|
||||
import threading
|
||||
import os
|
||||
from collections import deque
|
||||
from typing import Dict, Any, Optional
|
||||
from pylabrobot.resources import Deck
|
||||
|
||||
from unilabos.devices.workstation.workstation_base import WorkstationBase
|
||||
|
||||
|
||||
class ElectrolysisWaterPlatform(WorkstationBase):
|
||||
"""
|
||||
电解水平台工作站
|
||||
基于 WorkstationBase 的电解水实验平台,支持串口通信和数据采集
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
deck: Deck,
|
||||
port: str = "COM10",
|
||||
baudrate: int = 115200,
|
||||
csv_path: Optional[str] = None,
|
||||
timeout: float = 0.2,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(deck, **kwargs)
|
||||
|
||||
# ========== 配置 ==========
|
||||
self.port = port
|
||||
self.baudrate = baudrate
|
||||
# 如果没有指定路径,默认保存在代码文件所在目录
|
||||
if csv_path is None:
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
self.csv_path = os.path.join(current_dir, "stm32_data.csv")
|
||||
else:
|
||||
self.csv_path = csv_path
|
||||
self.ser_timeout = timeout
|
||||
self.chunk_read = 128
|
||||
|
||||
# 串口对象
|
||||
self.ser: Optional[serial.Serial] = None
|
||||
self.stop_flag = False
|
||||
|
||||
# 线程对象
|
||||
self.rx_thread: Optional[threading.Thread] = None
|
||||
self.tx_thread: Optional[threading.Thread] = None
|
||||
|
||||
# ==== 接收(下位机->上位机):固定 1+13+1 = 15 字节 ====
|
||||
self.RX_HEAD = 0x3E
|
||||
self.RX_TAIL = 0x3E
|
||||
self.RX_FRAME_LEN = 1 + 13 + 1 # 15
|
||||
|
||||
# ==== 发送(上位机->下位机):固定 1+9+1 = 11 字节 ====
|
||||
self.TX_HEAD = 0x3E
|
||||
self.TX_TAIL = 0xE3 # 协议图中标注 E3 作为帧尾
|
||||
self.TX_FRAME_LEN = 1 + 9 + 1 # 11
|
||||
|
||||
def open_serial(self, port: Optional[str] = None, baudrate: Optional[int] = None, timeout: Optional[float] = None) -> Optional[serial.Serial]:
|
||||
"""打开串口"""
|
||||
port = port or self.port
|
||||
baudrate = baudrate or self.baudrate
|
||||
timeout = timeout or self.ser_timeout
|
||||
try:
|
||||
ser = serial.Serial(port, baudrate, timeout=timeout)
|
||||
print(f"[OK] 串口 {port} 已打开,波特率 {baudrate}")
|
||||
ser.reset_input_buffer()
|
||||
ser.reset_output_buffer()
|
||||
self.ser = ser
|
||||
return ser
|
||||
except serial.SerialException as e:
|
||||
print(f"[ERR] 无法打开串口 {port}: {e}")
|
||||
return None
|
||||
|
||||
def close_serial(self):
|
||||
"""关闭串口"""
|
||||
if self.ser and self.ser.is_open:
|
||||
self.ser.close()
|
||||
print("[INFO] 串口已关闭")
|
||||
|
||||
@staticmethod
|
||||
def u16_be(h: int, l: int) -> int:
|
||||
"""将两个字节组合成16位无符号整数(大端序)"""
|
||||
return ((h & 0xFF) << 8) | (l & 0xFF)
|
||||
|
||||
@staticmethod
|
||||
def split_u16_be(val: int) -> tuple:
|
||||
"""返回 (高字节, 低字节),输入会夹到 0..65535"""
|
||||
v = int(max(0, min(65535, int(val))))
|
||||
return (v >> 8) & 0xFF, v & 0xFF
|
||||
|
||||
# ================== 接收:固定15字节 ==================
|
||||
def parse_rx_payload(self, dat13: bytes) -> Optional[Dict[str, Any]]:
|
||||
"""解析 13 字节数据区(下位机发送到上位机)"""
|
||||
if len(dat13) != 13:
|
||||
return None
|
||||
current_mA = self.u16_be(dat13[0], dat13[1])
|
||||
voltage_mV = self.u16_be(dat13[2], dat13[3])
|
||||
temperature_raw = self.u16_be(dat13[4], dat13[5])
|
||||
tds_ppm = self.u16_be(dat13[6], dat13[7])
|
||||
gas_sccm = self.u16_be(dat13[8], dat13[9])
|
||||
liquid_mL = self.u16_be(dat13[10], dat13[11])
|
||||
ph_raw = dat13[12] & 0xFF
|
||||
|
||||
return {
|
||||
"Current_mA": current_mA,
|
||||
"Voltage_mV": voltage_mV,
|
||||
"Temperature_C": round(temperature_raw / 100.0, 2),
|
||||
"TDS_ppm": tds_ppm,
|
||||
"GasFlow_sccm": gas_sccm,
|
||||
"LiquidFlow_mL": liquid_mL,
|
||||
"pH": round(ph_raw / 10.0, 2)
|
||||
}
|
||||
|
||||
def try_parse_rx_frame(self, frame15: bytes) -> Optional[Dict[str, Any]]:
|
||||
"""尝试解析接收帧"""
|
||||
if len(frame15) != self.RX_FRAME_LEN:
|
||||
return None
|
||||
if frame15[0] != self.RX_HEAD or frame15[-1] != self.RX_TAIL:
|
||||
return None
|
||||
return self.parse_rx_payload(frame15[1:-1])
|
||||
|
||||
def rx_thread_fn(self):
|
||||
"""接收线程函数"""
|
||||
headers = ["Timestamp", "Current_mA", "Voltage_mV",
|
||||
"Temperature_C", "TDS_ppm", "GasFlow_sccm", "LiquidFlow_mL", "pH"]
|
||||
|
||||
new_file = not os.path.exists(self.csv_path)
|
||||
f = open(self.csv_path, mode='a', newline='', encoding='utf-8')
|
||||
writer = csv.writer(f)
|
||||
if new_file:
|
||||
writer.writerow(headers)
|
||||
f.flush()
|
||||
|
||||
buf = deque(maxlen=8192)
|
||||
print(f"[RX] 开始接收(帧长 {self.RX_FRAME_LEN} 字节);写入:{self.csv_path}")
|
||||
|
||||
try:
|
||||
while not self.stop_flag and self.ser and self.ser.is_open:
|
||||
chunk = self.ser.read(self.chunk_read)
|
||||
if chunk:
|
||||
buf.extend(chunk)
|
||||
while True:
|
||||
# 找帧头
|
||||
try:
|
||||
start = next(i for i, b in enumerate(buf) if b == self.RX_HEAD)
|
||||
except StopIteration:
|
||||
buf.clear()
|
||||
break
|
||||
if start > 0:
|
||||
for _ in range(start):
|
||||
buf.popleft()
|
||||
if len(buf) < self.RX_FRAME_LEN:
|
||||
break
|
||||
candidate = bytes([buf[i] for i in range(self.RX_FRAME_LEN)])
|
||||
if candidate[-1] == self.RX_TAIL:
|
||||
parsed = self.try_parse_rx_frame(candidate)
|
||||
for _ in range(self.RX_FRAME_LEN):
|
||||
buf.popleft()
|
||||
if parsed:
|
||||
ts = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
row = [ts,
|
||||
parsed["Current_mA"], parsed["Voltage_mV"],
|
||||
parsed["Temperature_C"], parsed["TDS_ppm"],
|
||||
parsed["GasFlow_sccm"], parsed["LiquidFlow_mL"],
|
||||
parsed["pH"]]
|
||||
writer.writerow(row)
|
||||
f.flush()
|
||||
# 若不想打印可注释下一行
|
||||
# print(f"[{ts}] I={parsed['Current_mA']} mA, V={parsed['Voltage_mV']} mV, "
|
||||
# f"T={parsed['Temperature_C']} °C, TDS={parsed['TDS_ppm']}, "
|
||||
# f"Gas={parsed['GasFlow_sccm']} sccm, Liq={parsed['LiquidFlow_mL']} mL, pH={parsed['pH']}")
|
||||
else:
|
||||
# 头不变,尾不对,丢1字节继续对齐
|
||||
buf.popleft()
|
||||
else:
|
||||
time.sleep(0.01)
|
||||
finally:
|
||||
f.close()
|
||||
print("[RX] 接收线程退出,CSV 已关闭")
|
||||
|
||||
# ================== 发送:固定11字节 ==================
|
||||
def build_tx_frame(self, mode: int, current_ma: int, voltage_mv: int, temp_c: float, ki: float, pump_percent: float) -> bytes:
|
||||
"""
|
||||
发送帧:HEAD + [mode, I_hi, I_lo, V_hi, V_lo, T_hi, T_lo, Ki_byte, Pump_byte] + TAIL
|
||||
- mode: 0=恒压, 1=恒流
|
||||
- current_ma: mA (0..65535)
|
||||
- voltage_mv: mV (0..65535)
|
||||
- temp_c: ℃,将 *100 后拆分为高/低字节
|
||||
- ki: 0.0..20.0 -> byte = round(ki * 10) 夹到 0..200
|
||||
- pump_percent: 0..100 -> byte = round(pump * 2) 夹到 0..200
|
||||
"""
|
||||
mode_b = 1 if int(mode) == 1 else 0
|
||||
|
||||
i_hi, i_lo = self.split_u16_be(current_ma)
|
||||
v_hi, v_lo = self.split_u16_be(voltage_mv)
|
||||
|
||||
t100 = int(round(float(temp_c) * 100.0))
|
||||
t_hi, t_lo = self.split_u16_be(t100)
|
||||
|
||||
ki_b = int(max(0, min(200, round(float(ki) * 10))))
|
||||
pump_b = int(max(0, min(200, round(float(pump_percent) * 2))))
|
||||
|
||||
return bytes((
|
||||
self.TX_HEAD,
|
||||
mode_b,
|
||||
i_hi, i_lo,
|
||||
v_hi, v_lo,
|
||||
t_hi, t_lo,
|
||||
ki_b,
|
||||
pump_b,
|
||||
self.TX_TAIL
|
||||
))
|
||||
|
||||
def tx_thread_fn(self):
|
||||
"""
|
||||
发送线程函数
|
||||
用户输入 6 个用逗号分隔的数值:
|
||||
mode,current_mA,voltage_mV,set_temp_C,Ki,pump_percent
|
||||
例如: 0,1000,500,0,0,50
|
||||
"""
|
||||
print("\n输入 6 个值(用英文逗号分隔),顺序为:")
|
||||
print("mode,current_mA,voltage_mV,set_temp_C,Ki,pump_percent")
|
||||
print("示例恒压:0,500,1000,25,0,100 (stop 结束)\n")
|
||||
print("示例恒流:1,1000,500,25,0,100 (stop 结束)\n")
|
||||
print("示例恒流:1,2000,500,25,0,100 (stop 结束)\n")
|
||||
# 1,2000,500,25,0,100
|
||||
|
||||
while not self.stop_flag and self.ser and self.ser.is_open:
|
||||
try:
|
||||
line = input(">>> ").strip()
|
||||
except EOFError:
|
||||
self.stop_flag = True
|
||||
break
|
||||
|
||||
if not line:
|
||||
continue
|
||||
if line.lower() == "stop":
|
||||
self.stop_flag = True
|
||||
print("[SYS] 停止程序")
|
||||
break
|
||||
|
||||
try:
|
||||
parts = [p.strip() for p in line.split(",")]
|
||||
if len(parts) != 6:
|
||||
raise ValueError("需要 6 个逗号分隔的数值")
|
||||
mode = int(parts[0])
|
||||
i_ma = int(float(parts[1]))
|
||||
v_mv = int(float(parts[2]))
|
||||
t_c = float(parts[3])
|
||||
ki = float(parts[4])
|
||||
pump = float(parts[5])
|
||||
|
||||
frame = self.build_tx_frame(mode, i_ma, v_mv, t_c, ki, pump)
|
||||
self.ser.write(frame)
|
||||
print("[TX]", " ".join(f"{b:02X}" for b in frame))
|
||||
except Exception as e:
|
||||
print("[TX] 输入/打包失败:", e)
|
||||
print("格式:mode,current_mA,voltage_mV,set_temp_C,Ki,pump_percent")
|
||||
continue
|
||||
|
||||
def start(self):
|
||||
"""启动电解水平台"""
|
||||
self.ser = self.open_serial()
|
||||
if self.ser:
|
||||
try:
|
||||
self.rx_thread = threading.Thread(target=self.rx_thread_fn, daemon=True)
|
||||
self.tx_thread = threading.Thread(target=self.tx_thread_fn, daemon=True)
|
||||
self.rx_thread.start()
|
||||
self.tx_thread.start()
|
||||
print("[INFO] 电解水平台已启动")
|
||||
self.tx_thread.join() # 等待用户输入线程结束(输入 stop)
|
||||
finally:
|
||||
self.close_serial()
|
||||
|
||||
def stop(self):
|
||||
"""停止电解水平台"""
|
||||
self.stop_flag = True
|
||||
if self.rx_thread and self.rx_thread.is_alive():
|
||||
self.rx_thread.join(timeout=2.0)
|
||||
if self.tx_thread and self.tx_thread.is_alive():
|
||||
self.tx_thread.join(timeout=2.0)
|
||||
self.close_serial()
|
||||
print("[INFO] 电解水平台已停止")
|
||||
|
||||
|
||||
# ================== 主入口 ==================
|
||||
if __name__ == "__main__":
|
||||
# 创建一个简单的 Deck 用于测试
|
||||
from pylabrobot.resources import Deck
|
||||
|
||||
deck = Deck()
|
||||
platform = ElectrolysisWaterPlatform(deck)
|
||||
platform.start()
|
||||
@@ -1,231 +1,3 @@
|
||||
hplc.agilent:
|
||||
category:
|
||||
- characterization_chromatic
|
||||
class:
|
||||
action_value_mappings:
|
||||
auto-check_status:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default: {}
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 检查安捷伦HPLC设备状态的函数。用于监控设备的运行状态、连接状态、错误信息等关键指标。该函数定期查询设备状态,确保系统稳定运行,及时发现和报告设备异常。适用于自动化流程中的设备监控、故障诊断、系统维护等场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: check_status参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-extract_data_from_txt:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
file_path: null
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 从文本文件中提取分析数据的函数。用于解析安捷伦HPLC生成的结果文件,提取峰面积、保留时间、浓度等关键分析数据。支持多种文件格式的自动识别和数据结构化处理,为后续数据分析和报告生成提供标准化的数据格式。适用于批量数据处理、结果验证、质量控制等分析工作流程。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
file_path:
|
||||
type: string
|
||||
required:
|
||||
- file_path
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: extract_data_from_txt参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-start_sequence:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
params: null
|
||||
resource: null
|
||||
wf_name: null
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 启动安捷伦HPLC分析序列的函数。用于执行预定义的分析方法序列,包括样品进样、色谱分离、检测等完整的分析流程。支持参数配置、资源分配、工作流程管理等功能,实现全自动的样品分析。适用于批量样品处理、标准化分析、质量检测等需要连续自动分析的应用场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
params:
|
||||
type: string
|
||||
resource:
|
||||
type: object
|
||||
wf_name:
|
||||
type: string
|
||||
required:
|
||||
- wf_name
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: start_sequence参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-try_close_sub_device:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
device_name: null
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 尝试关闭HPLC子设备的函数。用于安全地关闭泵、检测器、进样器等各个子模块,确保设备正常断开连接并保护硬件安全。该函数提供错误处理和状态确认机制,避免强制关闭可能造成的设备损坏。适用于设备维护、系统重启、紧急停机等需要安全关闭设备的场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
device_name:
|
||||
type: string
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: try_close_sub_device参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-try_open_sub_device:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
device_name: null
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 尝试打开HPLC子设备的函数。用于初始化和连接泵、检测器、进样器等各个子模块,建立设备通信并进行自检。该函数提供连接验证和错误恢复机制,确保子设备正常启动并准备就绪。适用于设备初始化、系统启动、设备重连等需要建立设备连接的场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
device_name:
|
||||
type: string
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: try_open_sub_device参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
execute_command_from_outer:
|
||||
feedback: {}
|
||||
goal:
|
||||
command: command
|
||||
goal_default:
|
||||
command: ''
|
||||
handles: {}
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
success:
|
||||
type: boolean
|
||||
required:
|
||||
- return_info
|
||||
- success
|
||||
title: SendCmd_Result
|
||||
type: object
|
||||
required:
|
||||
- goal
|
||||
title: SendCmd
|
||||
type: object
|
||||
type: SendCmd
|
||||
module: unilabos.devices.hplc.AgilentHPLC:HPLCDriver
|
||||
status_types:
|
||||
could_run: bool
|
||||
data_file: String
|
||||
device_status: str
|
||||
driver_init_ok: bool
|
||||
finish_status: str
|
||||
is_running: bool
|
||||
status_text: str
|
||||
success: bool
|
||||
type: python
|
||||
config_info: []
|
||||
description: 安捷伦高效液相色谱(HPLC)分析设备,用于复杂化合物的分离、检测和定量分析。该设备通过UI自动化技术控制安捷伦ChemStation软件,实现全自动的样品分析流程。具备序列启动、设备状态监控、数据文件提取、结果处理等功能。支持多样品批量处理和实时状态反馈,适用于药物分析、环境检测、食品安全、化学研究等需要高精度色谱分析的实验室应用。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
config:
|
||||
properties:
|
||||
driver_debug:
|
||||
default: false
|
||||
type: string
|
||||
required: []
|
||||
type: object
|
||||
data:
|
||||
properties:
|
||||
could_run:
|
||||
type: boolean
|
||||
data_file:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
device_status:
|
||||
type: string
|
||||
driver_init_ok:
|
||||
type: boolean
|
||||
finish_status:
|
||||
type: string
|
||||
is_running:
|
||||
type: boolean
|
||||
status_text:
|
||||
type: string
|
||||
success:
|
||||
type: boolean
|
||||
required:
|
||||
- status_text
|
||||
- device_status
|
||||
- could_run
|
||||
- driver_init_ok
|
||||
- is_running
|
||||
- success
|
||||
- finish_status
|
||||
- data_file
|
||||
type: object
|
||||
version: 1.0.0
|
||||
hplc.agilent-zhida:
|
||||
category:
|
||||
- characterization_chromatic
|
||||
|
||||
@@ -1,194 +1 @@
|
||||
raman.home_made:
|
||||
category:
|
||||
- characterization_optic
|
||||
class:
|
||||
action_value_mappings:
|
||||
auto-ccd_time:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
int_time: null
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 设置CCD检测器积分时间的函数。用于配置拉曼光谱仪的信号采集时间,控制光谱数据的质量和信噪比。较长的积分时间可获得更高的信号强度和更好的光谱质量,但会增加测量时间。该函数允许根据样品特性和测量要求动态调整检测参数,优化测量效果。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
int_time:
|
||||
type: string
|
||||
required:
|
||||
- int_time
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: ccd_time参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-laser_on_power:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
output_voltage_laser: null
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 设置激光器输出功率的函数。用于控制拉曼光谱仪激光器的功率输出,调节激光强度以适应不同样品的测量需求。适当的激光功率能够获得良好的拉曼信号同时避免样品损伤。该函数支持精确的功率控制,确保测量结果的稳定性和重现性。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
output_voltage_laser:
|
||||
type: string
|
||||
required:
|
||||
- output_voltage_laser
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: laser_on_power参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-raman_without_background:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
int_time: null
|
||||
laser_power: null
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 执行无背景扣除的拉曼光谱测量函数。用于直接采集样品的拉曼光谱信号,不进行背景校正处理。该函数配置积分时间和激光功率参数,获取原始光谱数据用于后续的数据处理分析。适用于对光谱数据质量要求较高或需要自定义背景处理流程的测量场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
int_time:
|
||||
type: string
|
||||
laser_power:
|
||||
type: string
|
||||
required:
|
||||
- int_time
|
||||
- laser_power
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: raman_without_background参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-raman_without_background_average:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
average: null
|
||||
int_time: null
|
||||
laser_power: null
|
||||
sample_name: null
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 执行多次平均的无背景拉曼光谱测量函数。通过多次测量取平均值来提高光谱数据的信噪比和测量精度,减少随机噪声影响。该函数支持自定义平均次数、积分时间、激光功率等参数,并可为样品指定名称便于数据管理。适用于对测量精度要求较高的定量分析和研究应用。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
average:
|
||||
type: string
|
||||
int_time:
|
||||
type: string
|
||||
laser_power:
|
||||
type: string
|
||||
sample_name:
|
||||
type: string
|
||||
required:
|
||||
- sample_name
|
||||
- int_time
|
||||
- laser_power
|
||||
- average
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: raman_without_background_average参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
raman_cmd:
|
||||
feedback: {}
|
||||
goal:
|
||||
command: command
|
||||
goal_default:
|
||||
command: ''
|
||||
handles: {}
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
success:
|
||||
type: boolean
|
||||
required:
|
||||
- return_info
|
||||
- success
|
||||
title: SendCmd_Result
|
||||
type: object
|
||||
required:
|
||||
- goal
|
||||
title: SendCmd
|
||||
type: object
|
||||
type: SendCmd
|
||||
module: unilabos.devices.raman_uv.home_made_raman:RamanObj
|
||||
status_types: {}
|
||||
type: python
|
||||
config_info: []
|
||||
description: 拉曼光谱分析设备,用于物质的分子结构和化学成分表征。该设备集成激光器和CCD检测器,通过串口通信控制激光功率和光谱采集。具备背景扣除、多次平均、自动数据处理等功能,支持高精度的拉曼光谱测量。适用于材料表征、化学分析、质量控制、研究开发等需要分子指纹识别和结构分析的实验应用。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
config:
|
||||
properties:
|
||||
baudrate_ccd:
|
||||
default: 921600
|
||||
type: string
|
||||
baudrate_laser:
|
||||
default: 9600
|
||||
type: string
|
||||
port_ccd:
|
||||
type: string
|
||||
port_laser:
|
||||
type: string
|
||||
required:
|
||||
- port_laser
|
||||
- port_ccd
|
||||
type: object
|
||||
data:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
version: 1.0.0
|
||||
{}
|
||||
|
||||
@@ -834,174 +834,3 @@ linear_motion.toyo_xyz.sim:
|
||||
mesh: toyo_xyz
|
||||
type: device
|
||||
version: 1.0.0
|
||||
motor.iCL42:
|
||||
category:
|
||||
- robot_linear_motion
|
||||
class:
|
||||
action_value_mappings:
|
||||
auto-execute_run_motor:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
mode: null
|
||||
position: null
|
||||
velocity: null
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 步进电机执行运动函数。直接执行电机运动命令,包括位置设定、速度控制和路径规划。该函数处理底层的电机控制协议,消除警告信息,设置运动参数并启动电机运行。适用于需要直接控制电机运动的应用场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
mode:
|
||||
type: string
|
||||
position:
|
||||
type: number
|
||||
velocity:
|
||||
type: integer
|
||||
required:
|
||||
- mode
|
||||
- position
|
||||
- velocity
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: execute_run_motor参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-init_device:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default: {}
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: iCL42电机设备初始化函数。建立与iCL42步进电机驱动器的串口通信连接,配置通信参数包括波特率、数据位、校验位等。该函数是电机使用前的必要步骤,确保驱动器处于可控状态并准备接收运动指令。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: init_device参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-run_motor:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
mode: null
|
||||
position: null
|
||||
velocity: null
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 步进电机运动控制函数。根据指定的运动模式、目标位置和速度参数控制电机运动。支持多种运动模式和精确的位置控制,自动处理运动轨迹规划和执行。该函数提供异步执行和状态反馈,确保运动的准确性和可靠性。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
mode:
|
||||
type: string
|
||||
position:
|
||||
type: number
|
||||
velocity:
|
||||
type: integer
|
||||
required:
|
||||
- mode
|
||||
- position
|
||||
- velocity
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: run_motor参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
execute_command_from_outer:
|
||||
feedback: {}
|
||||
goal:
|
||||
command: command
|
||||
goal_default:
|
||||
command: ''
|
||||
handles: {}
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
success:
|
||||
type: boolean
|
||||
required:
|
||||
- return_info
|
||||
- success
|
||||
title: SendCmd_Result
|
||||
type: object
|
||||
required:
|
||||
- goal
|
||||
title: SendCmd
|
||||
type: object
|
||||
type: SendCmd
|
||||
module: unilabos.devices.motor.iCL42:iCL42Driver
|
||||
status_types:
|
||||
is_executing_run: bool
|
||||
motor_position: int
|
||||
success: bool
|
||||
type: python
|
||||
config_info: []
|
||||
description: iCL42步进电机驱动器,用于实验室设备的精密线性运动控制。该设备通过串口通信控制iCL42型步进电机驱动器,支持多种运动模式和精确的位置、速度控制。具备位置反馈、运行状态监控和故障检测功能。适用于自动进样器、样品传送、精密定位平台等需要准确线性运动控制的实验室自动化设备。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
config:
|
||||
properties:
|
||||
device_address:
|
||||
default: 1
|
||||
type: integer
|
||||
device_com:
|
||||
default: COM9
|
||||
type: string
|
||||
required: []
|
||||
type: object
|
||||
data:
|
||||
properties:
|
||||
is_executing_run:
|
||||
type: boolean
|
||||
motor_position:
|
||||
type: integer
|
||||
success:
|
||||
type: boolean
|
||||
required:
|
||||
- motor_position
|
||||
- is_executing_run
|
||||
- success
|
||||
type: object
|
||||
version: 1.0.0
|
||||
|
||||
92
unilabos/registry/resources/bioyond/YB_bottle.yaml
Normal file
92
unilabos/registry/resources/bioyond/YB_bottle.yaml
Normal file
@@ -0,0 +1,92 @@
|
||||
YB_20ml_fenyeping:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottles:YB_20ml_fenyeping
|
||||
type: pylabrobot
|
||||
description: YB_20ml_fenyeping
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_5ml_fenyeping:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottles:YB_5ml_fenyeping
|
||||
type: pylabrobot
|
||||
description: YB_5ml_fenyeping
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_jia_yang_tou_da:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottles:YB_jia_yang_tou_da
|
||||
type: pylabrobot
|
||||
description: YB_jia_yang_tou_da
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_pei_ye_da_Bottle:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottles:YB_pei_ye_da_Bottle
|
||||
type: pylabrobot
|
||||
description: YB_pei_ye_da_Bottle
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_pei_ye_xiao_Bottle:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottles:YB_pei_ye_xiao_Bottle
|
||||
type: pylabrobot
|
||||
description: YB_pei_ye_xiao_Bottle
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_qiang_tou:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottles:YB_qiang_tou
|
||||
type: pylabrobot
|
||||
description: YB_qiang_tou
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_ye_Bottle:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
- YB_bottle
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottles:YB_ye_Bottle
|
||||
type: pylabrobot
|
||||
description: YB_ye_Bottle
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
182
unilabos/registry/resources/bioyond/YB_bottle_carriers.yaml
Normal file
182
unilabos/registry/resources/bioyond/YB_bottle_carriers.yaml
Normal file
@@ -0,0 +1,182 @@
|
||||
YB_100ml_yeti:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_100ml_yeti
|
||||
type: pylabrobot
|
||||
description: YB_100ml_yeti
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_20ml_fenyepingban:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_20ml_fenyepingban
|
||||
type: pylabrobot
|
||||
description: YB_20ml_fenyepingban
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_5ml_fenyepingban:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_5ml_fenyepingban
|
||||
type: pylabrobot
|
||||
description: YB_5ml_fenyepingban
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_6StockCarrier:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_6StockCarrier
|
||||
type: pylabrobot
|
||||
description: YB_6StockCarrier
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_6VialCarrier:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_6VialCarrier
|
||||
type: pylabrobot
|
||||
description: YB_6VialCarrier
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_gao_nian_ye_Bottle:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottles:YB_gao_nian_ye_Bottle
|
||||
type: pylabrobot
|
||||
description: YB_gao_nian_ye_Bottle
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_gaonianye:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_gaonianye
|
||||
type: pylabrobot
|
||||
description: YB_gaonianye
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_jia_yang_tou_da_Carrier:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_jia_yang_tou_da_Carrier
|
||||
type: pylabrobot
|
||||
description: YB_jia_yang_tou_da_Carrier
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_peiyepingdaban:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_peiyepingdaban
|
||||
type: pylabrobot
|
||||
description: YB_peiyepingdaban
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_peiyepingxiaoban:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_peiyepingxiaoban
|
||||
type: pylabrobot
|
||||
description: YB_peiyepingxiaoban
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_qiang_tou_he:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_qiang_tou_he
|
||||
type: pylabrobot
|
||||
description: YB_qiang_tou_he
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_shi_pei_qi_kuai:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_shi_pei_qi_kuai
|
||||
type: pylabrobot
|
||||
description: YB_shi_pei_qi_kuai
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_ye:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottle_carriers:YB_ye
|
||||
type: pylabrobot
|
||||
description: YB_ye_Bottle_Carrier
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
YB_ye_100ml_Bottle:
|
||||
category:
|
||||
- yb3
|
||||
- YB_bottle_carriers
|
||||
class:
|
||||
module: unilabos.resources.bioyond.YB_bottles:YB_ye_100ml_Bottle
|
||||
type: pylabrobot
|
||||
description: YB_ye_100ml_Bottle
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema: {}
|
||||
registry_type: resource
|
||||
version: 1.0.0
|
||||
0
unilabos/resources/battery/__init__.py
Normal file
0
unilabos/resources/battery/__init__.py
Normal file
56
unilabos/resources/battery/bottle_carriers.py
Normal file
56
unilabos/resources/battery/bottle_carriers.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from pylabrobot.resources import create_homogeneous_resources, Coordinate, ResourceHolder, create_ordered_items_2d
|
||||
|
||||
from unilabos.resources.itemized_carrier import Bottle, BottleCarrier
|
||||
from unilabos.resources.bioyond.YB_bottles import (
|
||||
YB_pei_ye_xiao_Bottle,
|
||||
)
|
||||
# 命名约定:试剂瓶-Bottle,烧杯-Beaker,烧瓶-Flask,小瓶-Vial
|
||||
|
||||
|
||||
def YIHUA_Electrolyte_12VialCarrier(name: str) -> BottleCarrier:
|
||||
"""12瓶载架 - 2x6布局"""
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 120.0
|
||||
carrier_size_y = 250.0
|
||||
carrier_size_z = 50.0
|
||||
|
||||
# 瓶位尺寸
|
||||
bottle_diameter = 35.0
|
||||
bottle_spacing_x = 35.0 # X方向间距
|
||||
bottle_spacing_y = 35.0 # Y方向间距
|
||||
|
||||
# 计算起始位置 (居中排列)
|
||||
start_x = (carrier_size_x - (2 - 1) * bottle_spacing_x - bottle_diameter) / 2
|
||||
start_y = (carrier_size_y - (6 - 1) * bottle_spacing_y - bottle_diameter) / 2
|
||||
|
||||
sites = create_ordered_items_2d(
|
||||
klass=ResourceHolder,
|
||||
num_items_x=2,
|
||||
num_items_y=6,
|
||||
dx=start_x,
|
||||
dy=start_y,
|
||||
dz=5.0,
|
||||
item_dx=bottle_spacing_x,
|
||||
item_dy=bottle_spacing_y,
|
||||
|
||||
size_x=bottle_diameter,
|
||||
size_y=bottle_diameter,
|
||||
size_z=carrier_size_z,
|
||||
)
|
||||
for k, v in sites.items():
|
||||
v.name = f"{name}_{v.name}"
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=sites,
|
||||
model="Electrolyte_12VialCarrier",
|
||||
)
|
||||
carrier.num_items_x = 2
|
||||
carrier.num_items_y = 6
|
||||
carrier.num_items_z = 1
|
||||
for i in range(12):
|
||||
carrier[i] = YB_pei_ye_xiao_Bottle(f"{name}_vial_{i+1}")
|
||||
return carrier
|
||||
179
unilabos/resources/battery/electrode_sheet.py
Normal file
179
unilabos/resources/battery/electrode_sheet.py
Normal file
@@ -0,0 +1,179 @@
|
||||
from typing import Any, Dict, Optional, TypedDict
|
||||
|
||||
from pylabrobot.resources import Resource as ResourcePLR
|
||||
from pylabrobot.resources import Container
|
||||
|
||||
|
||||
electrode_colors = {
|
||||
"PositiveCan": "#ff0000",
|
||||
"PositiveElectrode": "#cc3333",
|
||||
"NegativeCan": "#000000",
|
||||
"NegativeElectrode": "#666666",
|
||||
"SpringWasher": "#8b7355",
|
||||
"FlatWasher": "a9a9a9",
|
||||
"AluminumFoil": "#ffcccc",
|
||||
"Battery": "#00ff00",
|
||||
}
|
||||
|
||||
class ElectrodeSheetState(TypedDict):
|
||||
mass: float # 质量 (g)
|
||||
material_type: str # 材料类型(铜、铝、不锈钢、弹簧钢等)
|
||||
color: str # 材料类型对应的颜色
|
||||
|
||||
|
||||
class ElectrodeSheet(ResourcePLR):
|
||||
"""极片类 - 包含正负极片、隔膜、弹片、垫片、铝箔等所有片状材料"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "极片",
|
||||
size_x=10,
|
||||
size_y=10,
|
||||
size_z=10,
|
||||
category: str = "electrode_sheet",
|
||||
model: Optional[str] = None,
|
||||
):
|
||||
"""初始化极片
|
||||
|
||||
Args:
|
||||
name: 极片名称
|
||||
category: 类别
|
||||
model: 型号
|
||||
"""
|
||||
super().__init__(
|
||||
name=name,
|
||||
size_x=size_x,
|
||||
size_y=size_y,
|
||||
size_z=size_z,
|
||||
category=category,
|
||||
model=model,
|
||||
)
|
||||
self._unilabos_state: ElectrodeSheetState = ElectrodeSheetState(
|
||||
diameter=14,
|
||||
thickness=0.1,
|
||||
mass=0.5,
|
||||
material_type="copper",
|
||||
info=None
|
||||
)
|
||||
|
||||
# TODO: 这个还要不要?给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) # Container自身的信息,云端物料将保存这一data,本地也通过这里的data进行读写,当前类用来表示这个物料的长宽高大小的属性,而data(state用来表示物料的内容,细节等)
|
||||
return data
|
||||
|
||||
|
||||
def PositiveCan(name: str) -> ElectrodeSheet:
|
||||
"""创建正极壳"""
|
||||
sheet = ElectrodeSheet(name=name, size_x=12, size_y=12, size_z=3.0, model="PositiveCan")
|
||||
sheet.load_state({"material_type": "aluminum", "color": electrode_colors["PositiveCan"]})
|
||||
return sheet
|
||||
|
||||
|
||||
def PositiveElectrode(name: str) -> ElectrodeSheet:
|
||||
"""创建正极片"""
|
||||
sheet = ElectrodeSheet(name=name, size_x=10, size_y=10, size_z=0.1, model="PositiveElectrode")
|
||||
sheet.load_state({"material_type": "positive_electrode", "color": electrode_colors["PositiveElectrode"]})
|
||||
return sheet
|
||||
|
||||
|
||||
def NegativeCan(name: str) -> ElectrodeSheet:
|
||||
"""创建负极壳"""
|
||||
sheet = ElectrodeSheet(name=name, size_x=12, size_y=12, size_z=2.0, model="NegativeCan")
|
||||
sheet.load_state({"material_type": "steel", "color": electrode_colors["NegativeCan"]})
|
||||
return sheet
|
||||
|
||||
|
||||
def NegativeElectrode(name: str) -> ElectrodeSheet:
|
||||
"""创建负极片"""
|
||||
sheet = ElectrodeSheet(name=name, size_x=10, size_y=10, size_z=0.1, model="NegativeElectrode")
|
||||
sheet.load_state({"material_type": "negative_electrode", "color": electrode_colors["NegativeElectrode"]})
|
||||
return sheet
|
||||
|
||||
|
||||
def SpringWasher(name: str) -> ElectrodeSheet:
|
||||
"""创建弹片"""
|
||||
sheet = ElectrodeSheet(name=name, size_x=10, size_y=10, size_z=0.5, model="SpringWasher")
|
||||
sheet.load_state({"material_type": "spring_steel", "color": electrode_colors["SpringWasher"]})
|
||||
return sheet
|
||||
|
||||
|
||||
def FlatWasher(name: str) -> ElectrodeSheet:
|
||||
"""创建垫片"""
|
||||
sheet = ElectrodeSheet(name=name, size_x=10, size_y=10, size_z=0.2, model="FlatWasher")
|
||||
sheet.load_state({"material_type": "steel", "color": electrode_colors["FlatWasher"]})
|
||||
return sheet
|
||||
|
||||
|
||||
def AluminumFoil(name: str) -> ElectrodeSheet:
|
||||
"""创建铝箔"""
|
||||
sheet = ElectrodeSheet(name=name, size_x=10, size_y=10, size_z=0.05, model="AluminumFoil")
|
||||
sheet.load_state({"material_type": "aluminum", "color": electrode_colors["AluminumFoil"]})
|
||||
return sheet
|
||||
|
||||
|
||||
class BatteryState(TypedDict):
|
||||
color: str # 材料类型对应的颜色
|
||||
electrolyte_name: str
|
||||
data_electrolyte_code: str
|
||||
open_circuit_voltage: float
|
||||
assembly_pressure: float
|
||||
electrolyte_volume: float
|
||||
|
||||
info: Optional[str] # 附加信息
|
||||
|
||||
|
||||
class Battery(Container):
|
||||
"""电池类 - 包含组装好的电池"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "电池",
|
||||
size_x=12,
|
||||
size_y=12,
|
||||
size_z=6,
|
||||
category: str = "battery",
|
||||
model: Optional[str] = None,
|
||||
):
|
||||
"""初始化电池
|
||||
|
||||
Args:
|
||||
name: 电池名称
|
||||
category: 类别
|
||||
model: 型号
|
||||
"""
|
||||
super().__init__(
|
||||
name=name,
|
||||
size_x=size_x,
|
||||
size_y=size_y,
|
||||
size_z=size_z,
|
||||
category=category,
|
||||
model=model,
|
||||
)
|
||||
self._unilabos_state: BatteryState = BatteryState(
|
||||
color=electrode_colors["Battery"],
|
||||
electrolyte_name="无",
|
||||
data_electrolyte_code="",
|
||||
open_circuit_voltage=0.0,
|
||||
assembly_pressure=0.0,
|
||||
electrolyte_volume=0.0,
|
||||
info=None
|
||||
)
|
||||
|
||||
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) # Container自身的信息,云端物料将保存这一data,本地也通过这里的data进行读写,当前类用来表示这个物料的长宽高大小的属性,而data(state用来表示物料的内容,细节等)
|
||||
return data
|
||||
344
unilabos/resources/battery/magazine.py
Normal file
344
unilabos/resources/battery/magazine.py
Normal file
@@ -0,0 +1,344 @@
|
||||
from typing import Dict, List, Optional, OrderedDict, Union, Callable
|
||||
import math
|
||||
|
||||
from pylabrobot.resources.coordinate import Coordinate
|
||||
from pylabrobot.resources import Resource, ResourceStack, ItemizedResource
|
||||
from pylabrobot.resources.carrier import create_homogeneous_resources
|
||||
|
||||
from unilabos.resources.battery.electrode_sheet import (
|
||||
PositiveCan, PositiveElectrode,
|
||||
NegativeCan, NegativeElectrode,
|
||||
SpringWasher, FlatWasher,
|
||||
AluminumFoil,
|
||||
Battery
|
||||
)
|
||||
|
||||
|
||||
class Magazine(ResourceStack):
|
||||
"""子弹夹洞位类"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
direction: str = 'z',
|
||||
resources: Optional[List[Resource]] = None,
|
||||
max_sheets: int = 100,
|
||||
**kwargs
|
||||
):
|
||||
"""初始化子弹夹洞位
|
||||
|
||||
Args:
|
||||
name: 洞位名称
|
||||
direction: 堆叠方向
|
||||
resources: 资源列表
|
||||
max_sheets: 最大极片数量
|
||||
"""
|
||||
super().__init__(
|
||||
name=name,
|
||||
direction=direction,
|
||||
resources=resources,
|
||||
)
|
||||
self.max_sheets = max_sheets
|
||||
|
||||
@property
|
||||
def size_x(self) -> float:
|
||||
return self.get_size_x()
|
||||
|
||||
@property
|
||||
def size_y(self) -> float:
|
||||
return self.get_size_y()
|
||||
|
||||
@property
|
||||
def size_z(self) -> float:
|
||||
return self.get_size_z()
|
||||
|
||||
def serialize(self) -> dict:
|
||||
return {
|
||||
**super().serialize(),
|
||||
"size_x": self.size_x or 10.0,
|
||||
"size_y": self.size_y or 10.0,
|
||||
"size_z": self.size_z or 10.0,
|
||||
"max_sheets": self.max_sheets,
|
||||
}
|
||||
|
||||
|
||||
class MagazineHolder(ItemizedResource):
|
||||
"""子弹夹类 - 有多个洞位,每个洞位放多个极片"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
size_x: float,
|
||||
size_y: float,
|
||||
size_z: float,
|
||||
ordered_items: Optional[Dict[str, Magazine]] = None,
|
||||
ordering: Optional[OrderedDict[str, str]] = None,
|
||||
hole_diameter: float = 14.0,
|
||||
hole_depth: float = 10.0,
|
||||
max_sheets_per_hole: int = 100,
|
||||
cross_section_type: str = "circle",
|
||||
category: str = "magazine_holder",
|
||||
model: Optional[str] = None,
|
||||
):
|
||||
"""初始化子弹夹
|
||||
|
||||
Args:
|
||||
name: 子弹夹名称
|
||||
size_x: 长度 (mm)
|
||||
size_y: 宽度 (mm)
|
||||
size_z: 高度 (mm)
|
||||
hole_diameter: 洞直径 (mm)
|
||||
hole_depth: 洞深度 (mm)
|
||||
max_sheets_per_hole: 每个洞位最大极片数量
|
||||
category: 类别
|
||||
model: 型号
|
||||
"""
|
||||
|
||||
super().__init__(
|
||||
name=name,
|
||||
size_x=size_x,
|
||||
size_y=size_y,
|
||||
size_z=size_z,
|
||||
ordered_items=ordered_items,
|
||||
ordering=ordering,
|
||||
category=category,
|
||||
model=model,
|
||||
)
|
||||
|
||||
# 保存洞位的直径和深度
|
||||
self.hole_diameter = hole_diameter
|
||||
self.hole_depth = hole_depth
|
||||
self.max_sheets_per_hole = max_sheets_per_hole
|
||||
self.cross_section_type = cross_section_type
|
||||
|
||||
def serialize(self) -> dict:
|
||||
return {
|
||||
**super().serialize(),
|
||||
"hole_diameter": self.hole_diameter,
|
||||
"hole_depth": self.hole_depth,
|
||||
"max_sheets_per_hole": self.max_sheets_per_hole,
|
||||
"cross_section_type": self.cross_section_type,
|
||||
}
|
||||
|
||||
|
||||
def magazine_factory(
|
||||
name: str,
|
||||
size_x: float,
|
||||
size_y: float,
|
||||
size_z: float,
|
||||
locations: List[Coordinate],
|
||||
klasses: Optional[List[Callable[[str], str]]] = None,
|
||||
hole_diameter: float = 14.0,
|
||||
hole_depth: float = 10.0,
|
||||
max_sheets_per_hole: int = 100,
|
||||
category: str = "magazine_holder",
|
||||
model: Optional[str] = None,
|
||||
) -> 'MagazineHolder':
|
||||
"""工厂函数:创建子弹夹
|
||||
|
||||
Args:
|
||||
name: 子弹夹名称
|
||||
size_x: 长度 (mm)
|
||||
size_y: 宽度 (mm)
|
||||
size_z: 高度 (mm)
|
||||
locations: 洞位坐标列表
|
||||
klasses: 每个洞位中极片的类列表
|
||||
hole_diameter: 洞直径 (mm)
|
||||
hole_depth: 洞深度 (mm)
|
||||
max_sheets_per_hole: 每个洞位最大极片数量
|
||||
category: 类别
|
||||
model: 型号
|
||||
"""
|
||||
for loc in locations:
|
||||
loc.x -= hole_diameter / 2
|
||||
loc.y -= hole_diameter / 2
|
||||
|
||||
# 创建洞位
|
||||
_sites = create_homogeneous_resources(
|
||||
klass=Magazine,
|
||||
locations=locations,
|
||||
resource_size_x=hole_diameter,
|
||||
resource_size_y=hole_diameter,
|
||||
name_prefix=name,
|
||||
max_sheets=max_sheets_per_hole,
|
||||
)
|
||||
|
||||
# 生成编号键
|
||||
keys = [f"A{i+1}" for i in range(len(locations))]
|
||||
sites = dict(zip(keys, _sites.values()))
|
||||
|
||||
holder = MagazineHolder(
|
||||
name=name,
|
||||
size_x=size_x,
|
||||
size_y=size_y,
|
||||
size_z=size_z,
|
||||
ordered_items=sites,
|
||||
hole_diameter=hole_diameter,
|
||||
hole_depth=hole_depth,
|
||||
max_sheets_per_hole=max_sheets_per_hole,
|
||||
category=category,
|
||||
model=model,
|
||||
)
|
||||
|
||||
if klasses is not None:
|
||||
for i, klass in enumerate(klasses):
|
||||
hole_key = keys[i]
|
||||
hole = holder.children[i]
|
||||
for j in reversed(range(max_sheets_per_hole)):
|
||||
item_name = f"{hole_key}_sheet{j+1}"
|
||||
item = klass(name=item_name)
|
||||
hole.assign_child_resource(item)
|
||||
return holder
|
||||
|
||||
|
||||
def MagazineHolder_6_Cathode(
|
||||
name: str,
|
||||
size_x: float = 80.0,
|
||||
size_y: float = 80.0,
|
||||
size_z: float = 40.0,
|
||||
hole_diameter: float = 14.0,
|
||||
hole_depth: float = 10.0,
|
||||
hole_spacing: float = 20.0,
|
||||
max_sheets_per_hole: int = 100,
|
||||
) -> MagazineHolder:
|
||||
"""创建6孔子弹夹 - 六边形排布"""
|
||||
center_x = size_x / 2
|
||||
center_y = size_y / 2
|
||||
|
||||
locations = []
|
||||
|
||||
# 周围6个孔,按六边形排布
|
||||
for i in range(6):
|
||||
angle = i * 60 * math.pi / 180 # 每60度一个孔
|
||||
x = center_x + hole_spacing * math.cos(angle)
|
||||
y = center_y + hole_spacing * math.sin(angle)
|
||||
locations.append(Coordinate(x, y, size_z - hole_depth))
|
||||
|
||||
return magazine_factory(
|
||||
name=name,
|
||||
size_x=size_x,
|
||||
size_y=size_y,
|
||||
size_z=size_z,
|
||||
locations=locations,
|
||||
klasses=[FlatWasher, PositiveCan, PositiveCan, FlatWasher, PositiveCan, PositiveCan],
|
||||
hole_diameter=hole_diameter,
|
||||
hole_depth=hole_depth,
|
||||
max_sheets_per_hole=max_sheets_per_hole,
|
||||
category="magazine_holder",
|
||||
model="MagazineHolder_6_Cathode",
|
||||
)
|
||||
|
||||
|
||||
def MagazineHolder_6_Anode(
|
||||
name: str,
|
||||
size_x: float = 80.0,
|
||||
size_y: float = 80.0,
|
||||
size_z: float = 40.0,
|
||||
hole_diameter: float = 14.0,
|
||||
hole_depth: float = 10.0,
|
||||
hole_spacing: float = 20.0,
|
||||
max_sheets_per_hole: int = 100,
|
||||
) -> MagazineHolder:
|
||||
"""创建6孔子弹夹 - 六边形排布"""
|
||||
center_x = size_x / 2
|
||||
center_y = size_y / 2
|
||||
|
||||
locations = []
|
||||
|
||||
# 周围6个孔,按六边形排布
|
||||
for i in range(6):
|
||||
angle = i * 60 * math.pi / 180 # 每60度一个孔
|
||||
x = center_x + hole_spacing * math.cos(angle)
|
||||
y = center_y + hole_spacing * math.sin(angle)
|
||||
locations.append(Coordinate(x, y, size_z - hole_depth))
|
||||
|
||||
return magazine_factory(
|
||||
name=name,
|
||||
size_x=size_x,
|
||||
size_y=size_y,
|
||||
size_z=size_z,
|
||||
locations=locations,
|
||||
klasses=[SpringWasher, NegativeCan, NegativeCan, SpringWasher, NegativeCan, NegativeCan],
|
||||
hole_diameter=hole_diameter,
|
||||
hole_depth=hole_depth,
|
||||
max_sheets_per_hole=max_sheets_per_hole,
|
||||
category="magazine_holder",
|
||||
model="MagazineHolder_6_Anode",
|
||||
)
|
||||
|
||||
|
||||
def MagazineHolder_6_Battery(
|
||||
name: str,
|
||||
size_x: float = 80.0,
|
||||
size_y: float = 80.0,
|
||||
size_z: float = 40.0,
|
||||
hole_diameter: float = 14.0,
|
||||
hole_depth: float = 10.0,
|
||||
hole_spacing: float = 20.0,
|
||||
max_sheets_per_hole: int = 100,
|
||||
) -> MagazineHolder:
|
||||
"""创建6孔子弹夹 - 六边形排布"""
|
||||
center_x = size_x / 2
|
||||
center_y = size_y / 2
|
||||
|
||||
locations = []
|
||||
|
||||
# 周围6个孔,按六边形排布
|
||||
for i in range(6):
|
||||
angle = i * 60 * math.pi / 180 # 每60度一个孔
|
||||
x = center_x + hole_spacing * math.cos(angle)
|
||||
y = center_y + hole_spacing * math.sin(angle)
|
||||
locations.append(Coordinate(x, y, size_z - hole_depth))
|
||||
|
||||
return magazine_factory(
|
||||
name=name,
|
||||
size_x=size_x,
|
||||
size_y=size_y,
|
||||
size_z=size_z,
|
||||
locations=locations,
|
||||
klasses=None, # 初始化时,不放入装好的电池
|
||||
hole_diameter=hole_diameter,
|
||||
hole_depth=hole_depth,
|
||||
max_sheets_per_hole=max_sheets_per_hole,
|
||||
category="magazine_holder",
|
||||
model="MagazineHolder_6_Battery",
|
||||
)
|
||||
|
||||
|
||||
def MagazineHolder_4_Cathode(
|
||||
name: str,
|
||||
) -> MagazineHolder:
|
||||
"""创建4孔子弹夹 - 正方形四角排布"""
|
||||
size_x: float = 80.0
|
||||
size_y: float = 80.0
|
||||
size_z: float = 10.0
|
||||
hole_diameter: float = 14.0
|
||||
hole_depth: float = 10.0
|
||||
hole_spacing: float = 25.0
|
||||
max_sheets_per_hole: int = 100
|
||||
|
||||
# 计算4个洞位的坐标(正方形四角排布)
|
||||
center_x = size_x / 2
|
||||
center_y = size_y / 2
|
||||
offset = hole_spacing / 2
|
||||
|
||||
locations = [
|
||||
Coordinate(center_x - offset, center_y - offset, size_z - hole_depth), # 左下
|
||||
Coordinate(center_x + offset, center_y - offset, size_z - hole_depth), # 右下
|
||||
Coordinate(center_x - offset, center_y + offset, size_z - hole_depth), # 左上
|
||||
Coordinate(center_x + offset, center_y + offset, size_z - hole_depth), # 右上
|
||||
]
|
||||
|
||||
return magazine_factory(
|
||||
name=name,
|
||||
size_x=size_x,
|
||||
size_y=size_y,
|
||||
size_z=size_z,
|
||||
locations=locations,
|
||||
klasses=[AluminumFoil, PositiveElectrode, PositiveElectrode, PositiveElectrode],
|
||||
hole_diameter=hole_diameter,
|
||||
hole_depth=hole_depth,
|
||||
max_sheets_per_hole=max_sheets_per_hole,
|
||||
category="magazine_holder",
|
||||
model="MagazineHolder_4_Cathode",
|
||||
)
|
||||
653
unilabos/resources/bioyond/YB_bottle_carriers.py
Normal file
653
unilabos/resources/bioyond/YB_bottle_carriers.py
Normal file
@@ -0,0 +1,653 @@
|
||||
from pylabrobot.resources import create_homogeneous_resources, Coordinate, ResourceHolder, create_ordered_items_2d
|
||||
|
||||
from unilabos.resources.itemized_carrier import Bottle, BottleCarrier
|
||||
from unilabos.resources.bioyond.YB_bottles import (
|
||||
YB_jia_yang_tou_da,
|
||||
YB_ye_Bottle,
|
||||
YB_ye_100ml_Bottle,
|
||||
YB_gao_nian_ye_Bottle,
|
||||
YB_5ml_fenyeping,
|
||||
YB_20ml_fenyeping,
|
||||
YB_pei_ye_xiao_Bottle,
|
||||
YB_pei_ye_da_Bottle,
|
||||
YB_qiang_tou,
|
||||
)
|
||||
# 命名约定:试剂瓶-Bottle,烧杯-Beaker,烧瓶-Flask,小瓶-Vial
|
||||
|
||||
|
||||
def BIOYOND_Electrolyte_6VialCarrier(name: str) -> BottleCarrier:
|
||||
"""6瓶载架 - 2x3布局"""
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 50.0
|
||||
|
||||
# 瓶位尺寸
|
||||
bottle_diameter = 30.0
|
||||
bottle_spacing_x = 42.0 # X方向间距
|
||||
bottle_spacing_y = 35.0 # Y方向间距
|
||||
|
||||
# 计算起始位置 (居中排列)
|
||||
start_x = (carrier_size_x - (3 - 1) * bottle_spacing_x - bottle_diameter) / 2
|
||||
start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2
|
||||
|
||||
sites = create_ordered_items_2d(
|
||||
klass=ResourceHolder,
|
||||
num_items_x=3,
|
||||
num_items_y=2,
|
||||
dx=start_x,
|
||||
dy=start_y,
|
||||
dz=5.0,
|
||||
item_dx=bottle_spacing_x,
|
||||
item_dy=bottle_spacing_y,
|
||||
|
||||
size_x=bottle_diameter,
|
||||
size_y=bottle_diameter,
|
||||
size_z=carrier_size_z,
|
||||
)
|
||||
for k, v in sites.items():
|
||||
v.name = f"{name}_{v.name}"
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=sites,
|
||||
model="Electrolyte_6VialCarrier",
|
||||
)
|
||||
carrier.num_items_x = 3
|
||||
carrier.num_items_y = 2
|
||||
carrier.num_items_z = 1
|
||||
# for i in range(6):
|
||||
# carrier[i] = YB_Solid_Vial(f"{name}_vial_{i+1}")
|
||||
return carrier
|
||||
|
||||
|
||||
def BIOYOND_Electrolyte_1BottleCarrier(name: str) -> BottleCarrier:
|
||||
"""1瓶载架 - 单个中央位置"""
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 100.0
|
||||
|
||||
# 烧杯尺寸
|
||||
beaker_diameter = 80.0
|
||||
|
||||
# 计算中央位置
|
||||
center_x = (carrier_size_x - beaker_diameter) / 2
|
||||
center_y = (carrier_size_y - beaker_diameter) / 2
|
||||
center_z = 5.0
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=create_homogeneous_resources(
|
||||
klass=ResourceHolder,
|
||||
locations=[Coordinate(center_x, center_y, center_z)],
|
||||
resource_size_x=beaker_diameter,
|
||||
resource_size_y=beaker_diameter,
|
||||
name_prefix=name,
|
||||
),
|
||||
model="Electrolyte_1BottleCarrier",
|
||||
)
|
||||
carrier.num_items_x = 1
|
||||
carrier.num_items_y = 1
|
||||
carrier.num_items_z = 1
|
||||
# carrier[0] = YB_Solution_Beaker(f"{name}_beaker_1")
|
||||
return carrier
|
||||
|
||||
|
||||
def YB_6StockCarrier(name: str) -> BottleCarrier:
|
||||
"""6瓶载架 - 2x3布局"""
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 50.0
|
||||
|
||||
# 瓶位尺寸
|
||||
bottle_diameter = 20.0
|
||||
bottle_spacing_x = 42.0 # X方向间距
|
||||
bottle_spacing_y = 35.0 # Y方向间距
|
||||
|
||||
# 计算起始位置 (居中排列)
|
||||
start_x = (carrier_size_x - (3 - 1) * bottle_spacing_x - bottle_diameter) / 2
|
||||
start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2
|
||||
|
||||
sites = create_ordered_items_2d(
|
||||
klass=ResourceHolder,
|
||||
num_items_x=3,
|
||||
num_items_y=2,
|
||||
dx=start_x,
|
||||
dy=start_y,
|
||||
dz=5.0,
|
||||
item_dx=bottle_spacing_x,
|
||||
item_dy=bottle_spacing_y,
|
||||
|
||||
size_x=bottle_diameter,
|
||||
size_y=bottle_diameter,
|
||||
size_z=carrier_size_z,
|
||||
)
|
||||
for k, v in sites.items():
|
||||
v.name = f"{name}_{v.name}"
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=sites,
|
||||
model="6StockCarrier",
|
||||
)
|
||||
carrier.num_items_x = 3
|
||||
carrier.num_items_y = 2
|
||||
carrier.num_items_z = 1
|
||||
ordering = ["A1", "A2", "A3", "B1", "B2", "B3"] # 自定义顺序
|
||||
# for i in range(6):
|
||||
# carrier[i] = YB_Solid_Stock(f"{name}_vial_{ordering[i]}")
|
||||
return carrier
|
||||
|
||||
|
||||
def YB_6VialCarrier(name: str) -> BottleCarrier:
|
||||
"""6瓶载架 - 2x3布局"""
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 50.0
|
||||
|
||||
# 瓶位尺寸
|
||||
bottle_diameter = 30.0
|
||||
bottle_spacing_x = 42.0 # X方向间距
|
||||
bottle_spacing_y = 35.0 # Y方向间距
|
||||
|
||||
# 计算起始位置 (居中排列)
|
||||
start_x = (carrier_size_x - (3 - 1) * bottle_spacing_x - bottle_diameter) / 2
|
||||
start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2
|
||||
|
||||
sites = create_ordered_items_2d(
|
||||
klass=ResourceHolder,
|
||||
num_items_x=3,
|
||||
num_items_y=2,
|
||||
dx=start_x,
|
||||
dy=start_y,
|
||||
dz=5.0,
|
||||
item_dx=bottle_spacing_x,
|
||||
item_dy=bottle_spacing_y,
|
||||
|
||||
size_x=bottle_diameter,
|
||||
size_y=bottle_diameter,
|
||||
size_z=carrier_size_z,
|
||||
)
|
||||
for k, v in sites.items():
|
||||
v.name = f"{name}_{v.name}"
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=sites,
|
||||
model="6VialCarrier",
|
||||
)
|
||||
carrier.num_items_x = 3
|
||||
carrier.num_items_y = 2
|
||||
carrier.num_items_z = 1
|
||||
ordering = ["A1", "A2", "A3", "B1", "B2", "B3"] # 自定义顺序
|
||||
# for i in range(3):
|
||||
# carrier[i] = YB_Solid_Vial(f"{name}_solidvial_{ordering[i]}")
|
||||
# for i in range(3, 6):
|
||||
# carrier[i] = YB_Liquid_Vial(f"{name}_liquidvial_{ordering[i]}")
|
||||
return carrier
|
||||
|
||||
# 1瓶载架 - 单个中央位置
|
||||
def YB_ye(name: str) -> BottleCarrier:
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 20.0
|
||||
|
||||
# 烧杯尺寸
|
||||
beaker_diameter = 60.0
|
||||
|
||||
# 计算中央位置
|
||||
center_x = (carrier_size_x - beaker_diameter) / 2
|
||||
center_y = (carrier_size_y - beaker_diameter) / 2
|
||||
center_z = 5.0
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=create_homogeneous_resources(
|
||||
klass=ResourceHolder,
|
||||
locations=[Coordinate(center_x, center_y, center_z)],
|
||||
resource_size_x=beaker_diameter,
|
||||
resource_size_y=beaker_diameter,
|
||||
name_prefix=name,
|
||||
),
|
||||
model="YB_ye",
|
||||
)
|
||||
carrier.num_items_x = 1
|
||||
carrier.num_items_y = 1
|
||||
carrier.num_items_z = 1
|
||||
carrier[0] = YB_ye_Bottle(f"{name}_flask_1")
|
||||
return carrier
|
||||
|
||||
|
||||
# 高粘液瓶载架 - 单个中央位置
|
||||
def YB_gaonianye(name: str) -> BottleCarrier:
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 20.0
|
||||
|
||||
# 烧杯尺寸
|
||||
beaker_diameter = 60.0
|
||||
|
||||
# 计算中央位置
|
||||
center_x = (carrier_size_x - beaker_diameter) / 2
|
||||
center_y = (carrier_size_y - beaker_diameter) / 2
|
||||
center_z = 5.0
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=create_homogeneous_resources(
|
||||
klass=ResourceHolder,
|
||||
locations=[Coordinate(center_x, center_y, center_z)],
|
||||
resource_size_x=beaker_diameter,
|
||||
resource_size_y=beaker_diameter,
|
||||
name_prefix=name,
|
||||
),
|
||||
model="YB_gaonianye",
|
||||
)
|
||||
carrier.num_items_x = 1
|
||||
carrier.num_items_y = 1
|
||||
carrier.num_items_z = 1
|
||||
carrier[0] = YB_gao_nian_ye_Bottle(f"{name}_flask_1")
|
||||
return carrier
|
||||
|
||||
|
||||
# 100ml液体瓶载架 - 单个中央位置
|
||||
def YB_100ml_yeti(name: str) -> BottleCarrier:
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 20.0
|
||||
|
||||
# 烧杯尺寸
|
||||
beaker_diameter = 60.0
|
||||
|
||||
# 计算中央位置
|
||||
center_x = (carrier_size_x - beaker_diameter) / 2
|
||||
center_y = (carrier_size_y - beaker_diameter) / 2
|
||||
center_z = 5.0
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=create_homogeneous_resources(
|
||||
klass=ResourceHolder,
|
||||
locations=[Coordinate(center_x, center_y, center_z)],
|
||||
resource_size_x=beaker_diameter,
|
||||
resource_size_y=beaker_diameter,
|
||||
name_prefix=name,
|
||||
),
|
||||
model="YB_100ml_yeti",
|
||||
)
|
||||
carrier.num_items_x = 1
|
||||
carrier.num_items_y = 1
|
||||
carrier.num_items_z = 1
|
||||
carrier[0] = YB_ye_100ml_Bottle(f"{name}_flask_1")
|
||||
return carrier
|
||||
|
||||
# 5ml分液瓶板 - 4x2布局,8个位置
|
||||
def YB_5ml_fenyepingban(name: str) -> BottleCarrier:
|
||||
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 50.0
|
||||
|
||||
# 瓶位尺寸
|
||||
bottle_diameter = 15.0
|
||||
bottle_spacing_x = 42.0 # X方向间距
|
||||
bottle_spacing_y = 35.0 # Y方向间距
|
||||
|
||||
# 计算起始位置 (居中排列)
|
||||
start_x = (carrier_size_x - (4 - 1) * bottle_spacing_x - bottle_diameter) / 2
|
||||
start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2
|
||||
|
||||
sites = create_ordered_items_2d(
|
||||
klass=ResourceHolder,
|
||||
num_items_x=4,
|
||||
num_items_y=2,
|
||||
dx=start_x,
|
||||
dy=start_y,
|
||||
dz=5.0,
|
||||
item_dx=bottle_spacing_x,
|
||||
item_dy=bottle_spacing_y,
|
||||
size_x=bottle_diameter,
|
||||
size_y=bottle_diameter,
|
||||
size_z=carrier_size_z,
|
||||
)
|
||||
for k, v in sites.items():
|
||||
v.name = f"{name}_{v.name}"
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=sites,
|
||||
model="YB_5ml_fenyepingban",
|
||||
)
|
||||
carrier.num_items_x = 4
|
||||
carrier.num_items_y = 2
|
||||
carrier.num_items_z = 1
|
||||
ordering = ["A1", "A2", "A3", "A4", "B1", "B2", "B3", "B4"]
|
||||
for i in range(8):
|
||||
carrier[i] = YB_5ml_fenyeping(f"{name}_vial_{ordering[i]}")
|
||||
return carrier
|
||||
|
||||
# 20ml分液瓶板 - 4x2布局,8个位置
|
||||
def YB_20ml_fenyepingban(name: str) -> BottleCarrier:
|
||||
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 70.0
|
||||
|
||||
# 瓶位尺寸
|
||||
bottle_diameter = 20.0
|
||||
bottle_spacing_x = 42.0 # X方向间距
|
||||
bottle_spacing_y = 35.0 # Y方向间距
|
||||
|
||||
# 计算起始位置 (居中排列)
|
||||
start_x = (carrier_size_x - (4 - 1) * bottle_spacing_x - bottle_diameter) / 2
|
||||
start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2
|
||||
|
||||
sites = create_ordered_items_2d(
|
||||
klass=ResourceHolder,
|
||||
num_items_x=4,
|
||||
num_items_y=2,
|
||||
dx=start_x,
|
||||
dy=start_y,
|
||||
dz=5.0,
|
||||
item_dx=bottle_spacing_x,
|
||||
item_dy=bottle_spacing_y,
|
||||
size_x=bottle_diameter,
|
||||
size_y=bottle_diameter,
|
||||
size_z=carrier_size_z,
|
||||
)
|
||||
for k, v in sites.items():
|
||||
v.name = f"{name}_{v.name}"
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=sites,
|
||||
model="YB_20ml_fenyepingban",
|
||||
)
|
||||
carrier.num_items_x = 4
|
||||
carrier.num_items_y = 2
|
||||
carrier.num_items_z = 1
|
||||
ordering = ["A1", "A2", "A3", "A4", "B1", "B2", "B3", "B4"]
|
||||
for i in range(8):
|
||||
carrier[i] = YB_20ml_fenyeping(f"{name}_vial_{ordering[i]}")
|
||||
return carrier
|
||||
|
||||
# 配液瓶(小)板 - 4x2布局,8个位置
|
||||
def YB_peiyepingxiaoban(name: str) -> BottleCarrier:
|
||||
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 65.0
|
||||
|
||||
# 瓶位尺寸
|
||||
bottle_diameter = 35.0
|
||||
bottle_spacing_x = 42.0 # X方向间距
|
||||
bottle_spacing_y = 35.0 # Y方向间距
|
||||
|
||||
# 计算起始位置 (居中排列)
|
||||
start_x = (carrier_size_x - (4 - 1) * bottle_spacing_x - bottle_diameter) / 2
|
||||
start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2
|
||||
|
||||
sites = create_ordered_items_2d(
|
||||
klass=ResourceHolder,
|
||||
num_items_x=4,
|
||||
num_items_y=2,
|
||||
dx=start_x,
|
||||
dy=start_y,
|
||||
dz=5.0,
|
||||
item_dx=bottle_spacing_x,
|
||||
item_dy=bottle_spacing_y,
|
||||
size_x=bottle_diameter,
|
||||
size_y=bottle_diameter,
|
||||
size_z=carrier_size_z,
|
||||
)
|
||||
for k, v in sites.items():
|
||||
v.name = f"{name}_{v.name}"
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=sites,
|
||||
model="YB_peiyepingxiaoban",
|
||||
)
|
||||
carrier.num_items_x = 4
|
||||
carrier.num_items_y = 2
|
||||
carrier.num_items_z = 1
|
||||
ordering = ["A1", "A2", "A3", "A4", "B1", "B2", "B3", "B4"]
|
||||
for i in range(8):
|
||||
carrier[i] = YB_pei_ye_xiao_Bottle(f"{name}_bottle_{ordering[i]}")
|
||||
return carrier
|
||||
|
||||
|
||||
# 配液瓶(大)板 - 2x2布局,4个位置
|
||||
def YB_peiyepingdaban(name: str) -> BottleCarrier:
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 95.0
|
||||
|
||||
# 瓶位尺寸
|
||||
bottle_diameter = 55.0
|
||||
bottle_spacing_x = 60.0 # X方向间距
|
||||
bottle_spacing_y = 60.0 # Y方向间距
|
||||
|
||||
# 计算起始位置 (居中排列)
|
||||
start_x = (carrier_size_x - (2 - 1) * bottle_spacing_x - bottle_diameter) / 2
|
||||
start_y = (carrier_size_y - (2 - 1) * bottle_spacing_y - bottle_diameter) / 2
|
||||
|
||||
sites = create_ordered_items_2d(
|
||||
klass=ResourceHolder,
|
||||
num_items_x=2,
|
||||
num_items_y=2,
|
||||
dx=start_x,
|
||||
dy=start_y,
|
||||
dz=5.0,
|
||||
item_dx=bottle_spacing_x,
|
||||
item_dy=bottle_spacing_y,
|
||||
size_x=bottle_diameter,
|
||||
size_y=bottle_diameter,
|
||||
size_z=carrier_size_z,
|
||||
)
|
||||
for k, v in sites.items():
|
||||
v.name = f"{name}_{v.name}"
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=sites,
|
||||
model="YB_peiyepingdaban",
|
||||
)
|
||||
carrier.num_items_x = 2
|
||||
carrier.num_items_y = 2
|
||||
carrier.num_items_z = 1
|
||||
ordering = ["A1", "A2", "B1", "B2"]
|
||||
for i in range(4):
|
||||
carrier[i] = YB_pei_ye_da_Bottle(f"{name}_bottle_{ordering[i]}")
|
||||
return carrier
|
||||
|
||||
# 加样头(大)板 - 1x1布局,1个位置
|
||||
def YB_jia_yang_tou_da_Carrier(name: str) -> BottleCarrier:
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 95.0
|
||||
|
||||
# 瓶位尺寸
|
||||
bottle_diameter = 35.0
|
||||
bottle_spacing_x = 42.0 # X方向间距
|
||||
bottle_spacing_y = 35.0 # Y方向间距
|
||||
|
||||
# 计算起始位置 (居中排列)
|
||||
start_x = (carrier_size_x - (1 - 1) * bottle_spacing_x - bottle_diameter) / 2
|
||||
start_y = (carrier_size_y - (1 - 1) * bottle_spacing_y - bottle_diameter) / 2
|
||||
|
||||
sites = create_ordered_items_2d(
|
||||
klass=ResourceHolder,
|
||||
num_items_x=1,
|
||||
num_items_y=1,
|
||||
dx=start_x,
|
||||
dy=start_y,
|
||||
dz=5.0,
|
||||
item_dx=bottle_spacing_x,
|
||||
item_dy=bottle_spacing_y,
|
||||
size_x=bottle_diameter,
|
||||
size_y=bottle_diameter,
|
||||
size_z=carrier_size_z,
|
||||
)
|
||||
for k, v in sites.items():
|
||||
v.name = f"{name}_{v.name}"
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=sites,
|
||||
model="YB_jia_yang_tou_da_Carrier",
|
||||
)
|
||||
carrier.num_items_x = 1
|
||||
carrier.num_items_y = 1
|
||||
carrier.num_items_z = 1
|
||||
carrier[0] = YB_jia_yang_tou_da(f"{name}_head_1")
|
||||
return carrier
|
||||
|
||||
|
||||
def YB_shi_pei_qi_kuai(name: str) -> BottleCarrier:
|
||||
"""适配器块 - 单个中央位置"""
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 30.0
|
||||
|
||||
# 适配器尺寸
|
||||
adapter_diameter = 80.0
|
||||
|
||||
# 计算中央位置
|
||||
center_x = (carrier_size_x - adapter_diameter) / 2
|
||||
center_y = (carrier_size_y - adapter_diameter) / 2
|
||||
center_z = 0.0
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=create_homogeneous_resources(
|
||||
klass=ResourceHolder,
|
||||
locations=[Coordinate(center_x, center_y, center_z)],
|
||||
resource_size_x=adapter_diameter,
|
||||
resource_size_y=adapter_diameter,
|
||||
name_prefix=name,
|
||||
),
|
||||
model="YB_shi_pei_qi_kuai",
|
||||
)
|
||||
carrier.num_items_x = 1
|
||||
carrier.num_items_y = 1
|
||||
carrier.num_items_z = 1
|
||||
# 适配器块本身不包含瓶子,只是一个支撑结构
|
||||
return carrier
|
||||
|
||||
|
||||
def YB_qiang_tou_he(name: str) -> BottleCarrier:
|
||||
"""枪头盒 - 8x12布局,96个位置"""
|
||||
|
||||
# 载架尺寸 (mm)
|
||||
carrier_size_x = 127.8
|
||||
carrier_size_y = 85.5
|
||||
carrier_size_z = 55.0
|
||||
|
||||
# 枪头尺寸
|
||||
tip_diameter = 10.0
|
||||
tip_spacing_x = 9.0 # X方向间距
|
||||
tip_spacing_y = 9.0 # Y方向间距
|
||||
|
||||
# 计算起始位置 (居中排列)
|
||||
start_x = (carrier_size_x - (12 - 1) * tip_spacing_x - tip_diameter) / 2
|
||||
start_y = (carrier_size_y - (8 - 1) * tip_spacing_y - tip_diameter) / 2
|
||||
|
||||
sites = create_ordered_items_2d(
|
||||
klass=ResourceHolder,
|
||||
num_items_x=12,
|
||||
num_items_y=8,
|
||||
dx=start_x,
|
||||
dy=start_y,
|
||||
dz=5.0,
|
||||
item_dx=tip_spacing_x,
|
||||
item_dy=tip_spacing_y,
|
||||
size_x=tip_diameter,
|
||||
size_y=tip_diameter,
|
||||
size_z=carrier_size_z,
|
||||
)
|
||||
for k, v in sites.items():
|
||||
v.name = f"{name}_{v.name}"
|
||||
|
||||
carrier = BottleCarrier(
|
||||
name=name,
|
||||
size_x=carrier_size_x,
|
||||
size_y=carrier_size_y,
|
||||
size_z=carrier_size_z,
|
||||
sites=sites,
|
||||
model="YB_qiang_tou_he",
|
||||
)
|
||||
carrier.num_items_x = 12
|
||||
carrier.num_items_y = 8
|
||||
carrier.num_items_z = 1
|
||||
# 创建96个枪头
|
||||
for i in range(96):
|
||||
row = chr(65 + i // 12) # A-H
|
||||
col = (i % 12) + 1 # 1-12
|
||||
carrier[i] = YB_qiang_tou(f"{name}_tip_{row}{col}")
|
||||
return carrier
|
||||
|
||||
163
unilabos/resources/bioyond/YB_bottles.py
Normal file
163
unilabos/resources/bioyond/YB_bottles.py
Normal file
@@ -0,0 +1,163 @@
|
||||
from unilabos.resources.itemized_carrier import Bottle, BottleCarrier
|
||||
# 工厂函数
|
||||
"""加样头(大)"""
|
||||
def YB_jia_yang_tou_da(
|
||||
name: str,
|
||||
diameter: float = 20.0,
|
||||
height: float = 100.0,
|
||||
max_volume: float = 30000.0, # 30mL
|
||||
barcode: str = None,
|
||||
) -> Bottle:
|
||||
"""创建粉末瓶"""
|
||||
return Bottle(
|
||||
name=name,
|
||||
diameter=diameter,# 未知
|
||||
height=height,
|
||||
max_volume=max_volume,
|
||||
barcode=barcode,
|
||||
model="YB_jia_yang_tou_da",
|
||||
)
|
||||
|
||||
"""液1x1"""
|
||||
def YB_ye_Bottle(
|
||||
name: str,
|
||||
diameter: float = 40.0,
|
||||
height: float = 70.0,
|
||||
max_volume: float = 50000.0, # 50mL
|
||||
barcode: str = None,
|
||||
) -> Bottle:
|
||||
"""创建液体瓶"""
|
||||
return Bottle(
|
||||
name=name,
|
||||
diameter=diameter,
|
||||
height=height,
|
||||
max_volume=max_volume,
|
||||
barcode=barcode,
|
||||
model="YB_ye_Bottle",
|
||||
)
|
||||
|
||||
"""100ml液体"""
|
||||
def YB_ye_100ml_Bottle(
|
||||
name: str,
|
||||
diameter: float = 50.0,
|
||||
height: float = 90.0,
|
||||
max_volume: float = 100000.0, # 100mL
|
||||
barcode: str = None,
|
||||
) -> Bottle:
|
||||
"""创建100ml液体瓶"""
|
||||
return Bottle(
|
||||
name=name,
|
||||
diameter=diameter,
|
||||
height=height,
|
||||
max_volume=max_volume,
|
||||
barcode=barcode,
|
||||
model="YB_100ml_yeti",
|
||||
)
|
||||
|
||||
"""高粘液"""
|
||||
def YB_gao_nian_ye_Bottle(
|
||||
name: str,
|
||||
diameter: float = 40.0,
|
||||
height: float = 70.0,
|
||||
max_volume: float = 50000.0, # 50mL
|
||||
barcode: str = None,
|
||||
) -> Bottle:
|
||||
"""创建高粘液瓶"""
|
||||
return Bottle(
|
||||
name=name,
|
||||
diameter=diameter,
|
||||
height=height,
|
||||
max_volume=max_volume,
|
||||
barcode=barcode,
|
||||
model="High_Viscosity_Liquid",
|
||||
)
|
||||
|
||||
"""5ml分液瓶"""
|
||||
def YB_5ml_fenyeping(
|
||||
name: str,
|
||||
diameter: float = 20.0,
|
||||
height: float = 50.0,
|
||||
max_volume: float = 5000.0, # 5mL
|
||||
barcode: str = None,
|
||||
) -> Bottle:
|
||||
"""创建5ml分液瓶"""
|
||||
return Bottle(
|
||||
name=name,
|
||||
diameter=diameter,
|
||||
height=height,
|
||||
max_volume=max_volume,
|
||||
barcode=barcode,
|
||||
model="YB_5ml_fenyeping",
|
||||
)
|
||||
|
||||
"""20ml分液瓶"""
|
||||
def YB_20ml_fenyeping(
|
||||
name: str,
|
||||
diameter: float = 30.0,
|
||||
height: float = 65.0,
|
||||
max_volume: float = 20000.0, # 20mL
|
||||
barcode: str = None,
|
||||
) -> Bottle:
|
||||
"""创建20ml分液瓶"""
|
||||
return Bottle(
|
||||
name=name,
|
||||
diameter=diameter,
|
||||
height=height,
|
||||
max_volume=max_volume,
|
||||
barcode=barcode,
|
||||
model="YB_20ml_fenyeping",
|
||||
)
|
||||
|
||||
"""配液瓶(小)"""
|
||||
def YB_pei_ye_xiao_Bottle(
|
||||
name: str,
|
||||
diameter: float = 35.0,
|
||||
height: float = 60.0,
|
||||
max_volume: float = 30000.0, # 30mL
|
||||
barcode: str = None,
|
||||
) -> Bottle:
|
||||
"""创建配液瓶(小)"""
|
||||
return Bottle(
|
||||
name=name,
|
||||
diameter=diameter,
|
||||
height=height,
|
||||
max_volume=max_volume,
|
||||
barcode=barcode,
|
||||
model="YB_pei_ye_xiao_Bottle",
|
||||
)
|
||||
|
||||
"""配液瓶(大)"""
|
||||
def YB_pei_ye_da_Bottle(
|
||||
name: str,
|
||||
diameter: float = 55.0,
|
||||
height: float = 100.0,
|
||||
max_volume: float = 150000.0, # 150mL
|
||||
barcode: str = None,
|
||||
) -> Bottle:
|
||||
"""创建配液瓶(大)"""
|
||||
return Bottle(
|
||||
name=name,
|
||||
diameter=diameter,
|
||||
height=height,
|
||||
max_volume=max_volume,
|
||||
barcode=barcode,
|
||||
model="YB_pei_ye_da_Bottle",
|
||||
)
|
||||
|
||||
"""枪头"""
|
||||
def YB_qiang_tou(
|
||||
name: str,
|
||||
diameter: float = 10.0,
|
||||
height: float = 50.0,
|
||||
max_volume: float = 1000.0, # 1mL
|
||||
barcode: str = None,
|
||||
) -> Bottle:
|
||||
"""创建枪头"""
|
||||
return Bottle(
|
||||
name=name,
|
||||
diameter=diameter,
|
||||
height=height,
|
||||
max_volume=max_volume,
|
||||
barcode=barcode,
|
||||
model="YB_qiang_tou",
|
||||
)
|
||||
@@ -29,7 +29,7 @@ class Bottle(Well):
|
||||
size_x: float = 0.0,
|
||||
size_y: float = 0.0,
|
||||
size_z: float = 0.0,
|
||||
barcode: Optional[str] = "",
|
||||
barcode: Optional[str] = None,
|
||||
category: str = "container",
|
||||
model: Optional[str] = None,
|
||||
**kwargs,
|
||||
|
||||
@@ -664,7 +664,7 @@ class HostNode(BaseROS2DeviceNode):
|
||||
if bCreate:
|
||||
self.lab_logger().trace(f"Status created: {device_id}.{property_name} = {msg.data}")
|
||||
else:
|
||||
self.lab_logger().debug(f"Status updated: {device_id}.{property_name} = {msg.data}")
|
||||
self.lab_logger().trace(f"Status updated: {device_id}.{property_name} = {msg.data}")
|
||||
|
||||
def send_goal(
|
||||
self,
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
"Drip_back": "3a162cf9-6aac-565a-ddd7-682ba1796a4a"
|
||||
},
|
||||
"material_type_mappings": {
|
||||
"烧杯": "BIOYOND_PolymerStation_1FlaskCarrier",
|
||||
"试剂瓶": "BIOYOND_PolymerStation_1BottleCarrier",
|
||||
"样品板": "BIOYOND_PolymerStation_6VialCarrier"
|
||||
"烧杯": "YB_1FlaskCarrier",
|
||||
"试剂瓶": "YB_1BottleCarrier",
|
||||
"样品板": "YB_6VialCarrier"
|
||||
}
|
||||
},
|
||||
"deck": {
|
||||
|
||||
@@ -191,6 +191,18 @@ def configure_logger(loglevel=None, working_dir=None):
|
||||
|
||||
# 添加处理器到根日志记录器
|
||||
root_logger.addHandler(console_handler)
|
||||
|
||||
# 降低第三方库的日志级别,避免过多输出
|
||||
# pymodbus 库的日志太详细,设置为 WARNING
|
||||
logging.getLogger('pymodbus').setLevel(logging.WARNING)
|
||||
logging.getLogger('pymodbus.logging').setLevel(logging.WARNING)
|
||||
logging.getLogger('pymodbus.logging.base').setLevel(logging.WARNING)
|
||||
logging.getLogger('pymodbus.logging.decoders').setLevel(logging.WARNING)
|
||||
|
||||
# websockets 库的日志输出较多,设置为 WARNING
|
||||
logging.getLogger('websockets').setLevel(logging.WARNING)
|
||||
logging.getLogger('websockets.client').setLevel(logging.WARNING)
|
||||
logging.getLogger('websockets.server').setLevel(logging.WARNING)
|
||||
|
||||
# 如果指定了工作目录,添加文件处理器
|
||||
if working_dir is not None:
|
||||
|
||||
Reference in New Issue
Block a user