mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2025-12-17 13:01:12 +00:00
rename and fix all Yihua Materials: ClipMagazineHole→Magazine(ResourceStack), and use factory functions
This commit is contained in:
@@ -99,7 +99,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine_four",
|
"type": "MagazineHolder_4",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -235,7 +235,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -330,7 +330,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -425,7 +425,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -523,7 +523,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine_four",
|
"type": "MagazineHolder_4",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -564,7 +564,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -659,7 +659,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -754,7 +754,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -849,7 +849,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -949,7 +949,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -992,7 +992,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1087,7 +1087,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1182,7 +1182,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1277,7 +1277,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1372,7 +1372,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1467,7 +1467,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1567,7 +1567,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -1610,7 +1610,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1705,7 +1705,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1800,7 +1800,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1895,7 +1895,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1990,7 +1990,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2085,7 +2085,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2185,7 +2185,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -2228,7 +2228,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2323,7 +2323,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2418,7 +2418,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2513,7 +2513,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2608,7 +2608,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2703,7 +2703,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2803,7 +2803,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -2846,7 +2846,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2941,7 +2941,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3036,7 +3036,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3131,7 +3131,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3226,7 +3226,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3321,7 +3321,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3421,7 +3421,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -3464,7 +3464,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3559,7 +3559,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3654,7 +3654,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3749,7 +3749,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3844,7 +3844,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3939,7 +3939,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4039,7 +4039,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -4082,7 +4082,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4177,7 +4177,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4272,7 +4272,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4367,7 +4367,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4462,7 +4462,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4557,7 +4557,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
|
|||||||
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": []
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ from unilabos.devices.workstation.bioyond_studio.config import (
|
|||||||
API_CONFIG, MATERIAL_TYPE_MAPPINGS, WAREHOUSE_MAPPING, SOLID_LIQUID_MAPPINGS
|
API_CONFIG, MATERIAL_TYPE_MAPPINGS, WAREHOUSE_MAPPING, SOLID_LIQUID_MAPPINGS
|
||||||
)
|
)
|
||||||
from unilabos.devices.workstation.workstation_http_service import WorkstationHTTPService
|
from unilabos.devices.workstation.workstation_http_service import WorkstationHTTPService
|
||||||
|
from unilabos.resources.bioyond.decks import BIOYOND_YB_Deck
|
||||||
from unilabos.utils.log import logger
|
from unilabos.utils.log import logger
|
||||||
from unilabos.registry.registry import lab_registry
|
from unilabos.registry.registry import lab_registry
|
||||||
|
|
||||||
@@ -1074,17 +1075,12 @@ class BioyondCellWorkstation(BioyondWorkstation):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
lab_registry.setup()
|
lab_registry.setup()
|
||||||
ws = BioyondCellWorkstation()
|
deck = BIOYOND_YB_Deck(setup=True)
|
||||||
|
ws = BioyondCellWorkstation(deck=deck)
|
||||||
# ws.create_sample(name="test", board_type="配液瓶(小)板", bottle_type="配液瓶(小)", location_code="B01")
|
# ws.create_sample(name="test", board_type="配液瓶(小)板", bottle_type="配液瓶(小)", location_code="B01")
|
||||||
# logger.info(ws.scheduler_stop())
|
# logger.info(ws.scheduler_stop())
|
||||||
# logger.info(ws.scheduler_start())
|
# logger.info(ws.scheduler_start())
|
||||||
|
|
||||||
# results = ws.create_materials(SOLID_LIQUID_MAPPINGS)
|
|
||||||
# for r in results:
|
|
||||||
# logger.info(r)
|
|
||||||
# 从CSV文件读取物料列表并批量创建入库
|
|
||||||
# result = ws.create_and_inbound_materials()
|
|
||||||
|
|
||||||
# 继续后续流程
|
# 继续后续流程
|
||||||
# logger.info(ws.auto_feeding4to3()) #搬运物料到3号箱
|
# logger.info(ws.auto_feeding4to3()) #搬运物料到3号箱
|
||||||
# # # 使用正斜杠或 Path 对象来指定文件路径
|
# # # 使用正斜杠或 Path 对象来指定文件路径
|
||||||
|
|||||||
@@ -113,7 +113,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine_four",
|
"type": "MagazineHolder_4",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -249,7 +249,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -344,7 +344,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -439,7 +439,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -537,7 +537,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine_four",
|
"type": "MagazineHolder_4",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -578,7 +578,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -673,7 +673,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -768,7 +768,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -863,7 +863,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -963,7 +963,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -1006,7 +1006,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1101,7 +1101,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1196,7 +1196,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1291,7 +1291,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1386,7 +1386,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1481,7 +1481,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1581,7 +1581,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -1624,7 +1624,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1719,7 +1719,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1814,7 +1814,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -1909,7 +1909,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2004,7 +2004,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2099,7 +2099,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2199,7 +2199,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -2242,7 +2242,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2337,7 +2337,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2432,7 +2432,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2527,7 +2527,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2622,7 +2622,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2717,7 +2717,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2817,7 +2817,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -2860,7 +2860,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -2955,7 +2955,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3050,7 +3050,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3145,7 +3145,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3240,7 +3240,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3335,7 +3335,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3435,7 +3435,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -3478,7 +3478,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3573,7 +3573,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3668,7 +3668,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3763,7 +3763,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3858,7 +3858,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -3953,7 +3953,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4053,7 +4053,7 @@
|
|||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazine",
|
"type": "MagazineHolder_6",
|
||||||
"size_x": 80,
|
"size_x": 80,
|
||||||
"size_y": 80,
|
"size_y": 80,
|
||||||
"size_z": 10,
|
"size_z": 10,
|
||||||
@@ -4096,7 +4096,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4191,7 +4191,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4286,7 +4286,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4381,7 +4381,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4476,7 +4476,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
@@ -4571,7 +4571,7 @@
|
|||||||
"z": 10
|
"z": 10
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"type": "ClipMagazineHole",
|
"type": "Magazine",
|
||||||
"size_x": 14.0,
|
"size_x": 14.0,
|
||||||
"size_y": 14.0,
|
"size_y": 14.0,
|
||||||
"size_z": 10.0,
|
"size_z": 10.0,
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ from pylabrobot.resources.tip_rack import TipRack, TipSpot
|
|||||||
from pylabrobot.resources.trash import Trash
|
from pylabrobot.resources.trash import Trash
|
||||||
from pylabrobot.resources.utils import create_ordered_items_2d
|
from pylabrobot.resources.utils import create_ordered_items_2d
|
||||||
|
|
||||||
|
from unilabos.resources.battery.magazine import MagazineHolder_1, MagazineHolder_2, MagazineHolder_4, MagazineHolder_6
|
||||||
|
from unilabos.resources.battery.bottle_carriers import YIHUA_Electrolyte_12VialCarrier
|
||||||
|
|
||||||
|
|
||||||
class ElectrodeSheetState(TypedDict):
|
class ElectrodeSheetState(TypedDict):
|
||||||
diameter: float # 直径 (mm)
|
diameter: float # 直径 (mm)
|
||||||
@@ -165,7 +168,6 @@ class MaterialHole(Resource):
|
|||||||
return self.children[index]
|
return self.children[index]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MaterialPlateState(TypedDict):
|
class MaterialPlateState(TypedDict):
|
||||||
hole_spacing_x: float
|
hole_spacing_x: float
|
||||||
hole_spacing_y: float
|
hole_spacing_y: float
|
||||||
@@ -327,132 +329,6 @@ class PlateSlot(ResourceStack):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ClipMagazineHole(Container):
|
|
||||||
"""子弹夹洞位类"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
diameter: float,
|
|
||||||
depth: float,
|
|
||||||
max_sheets: int = 100,
|
|
||||||
category: str = "clip_magazine_hole",
|
|
||||||
):
|
|
||||||
"""初始化子弹夹洞位
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name: 洞位名称
|
|
||||||
diameter: 洞直径 (mm)
|
|
||||||
depth: 洞深度 (mm)
|
|
||||||
max_sheets: 最大极片数量
|
|
||||||
category: 类别
|
|
||||||
"""
|
|
||||||
super().__init__(
|
|
||||||
name=name,
|
|
||||||
size_x=diameter,
|
|
||||||
size_y=diameter,
|
|
||||||
size_z=depth,
|
|
||||||
category=category,
|
|
||||||
)
|
|
||||||
self.diameter = diameter
|
|
||||||
self.depth = depth
|
|
||||||
self.max_sheets = max_sheets
|
|
||||||
self._sheets: List[ElectrodeSheet] = []
|
|
||||||
|
|
||||||
def can_add_sheet(self, sheet: ElectrodeSheet) -> bool:
|
|
||||||
"""检查是否可以添加极片"""
|
|
||||||
return (len(self._sheets) < self.max_sheets and
|
|
||||||
sheet.diameter <= self.diameter)
|
|
||||||
|
|
||||||
def add_sheet(self, sheet: ElectrodeSheet) -> None:
|
|
||||||
"""添加极片"""
|
|
||||||
if not self.can_add_sheet(sheet):
|
|
||||||
raise ValueError(f"无法向洞位 {self.name} 添加极片")
|
|
||||||
self._sheets.append(sheet)
|
|
||||||
|
|
||||||
def take_sheet(self) -> ElectrodeSheet:
|
|
||||||
"""取出极片"""
|
|
||||||
if len(self._sheets) == 0:
|
|
||||||
raise ValueError(f"洞位 {self.name} 没有极片")
|
|
||||||
return self._sheets.pop()
|
|
||||||
|
|
||||||
def get_sheet_count(self) -> int:
|
|
||||||
"""获取极片数量"""
|
|
||||||
return len(self._sheets)
|
|
||||||
|
|
||||||
def serialize_state(self) -> Dict[str, Any]:
|
|
||||||
return {
|
|
||||||
"sheet_count": len(self._sheets),
|
|
||||||
"sheets": [sheet.serialize() for sheet in self._sheets],
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO: 这个要改
|
|
||||||
class ClipMagazine(ItemizedResource[ClipMagazineHole]):
|
|
||||||
"""子弹夹类 - 有6个洞位,每个洞位放多个极片"""
|
|
||||||
children: List[ClipMagazineHole]
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
size_x: float,
|
|
||||||
size_y: float,
|
|
||||||
size_z: float,
|
|
||||||
hole_diameter: float = 14.0,
|
|
||||||
hole_depth: float = 10.0,
|
|
||||||
hole_spacing: float = 25.0,
|
|
||||||
max_sheets_per_hole: int = 100,
|
|
||||||
category: str = "clip_magazine",
|
|
||||||
model: Optional[str] = None,
|
|
||||||
):
|
|
||||||
"""初始化子弹夹
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name: 子弹夹名称
|
|
||||||
size_x: 长度 (mm)
|
|
||||||
size_y: 宽度 (mm)
|
|
||||||
size_z: 高度 (mm)
|
|
||||||
hole_diameter: 洞直径 (mm)
|
|
||||||
hole_depth: 洞深度 (mm)
|
|
||||||
hole_spacing: 洞位间距 (mm)
|
|
||||||
max_sheets_per_hole: 每个洞位最大极片数量
|
|
||||||
category: 类别
|
|
||||||
model: 型号
|
|
||||||
"""
|
|
||||||
# 创建6个洞位,排成2x3布局
|
|
||||||
holes = create_ordered_items_2d(
|
|
||||||
klass=ClipMagazineHole,
|
|
||||||
num_items_x=3,
|
|
||||||
num_items_y=2,
|
|
||||||
dx=(size_x - 2 * hole_spacing) / 2, # 居中
|
|
||||||
dy=(size_y - hole_spacing) / 2, # 居中
|
|
||||||
dz=size_z - 0,
|
|
||||||
item_dx=hole_spacing,
|
|
||||||
item_dy=hole_spacing,
|
|
||||||
diameter=hole_diameter,
|
|
||||||
depth=hole_depth,
|
|
||||||
)
|
|
||||||
|
|
||||||
super().__init__(
|
|
||||||
name=name,
|
|
||||||
size_x=size_x,
|
|
||||||
size_y=size_y,
|
|
||||||
size_z=size_z,
|
|
||||||
ordered_items=holes,
|
|
||||||
category=category,
|
|
||||||
model=model,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 保存洞位的直径和深度
|
|
||||||
self.hole_diameter = hole_diameter
|
|
||||||
self.hole_depth = hole_depth
|
|
||||||
self.max_sheets_per_hole = max_sheets_per_hole
|
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
#是一种类型注解,不用self
|
#是一种类型注解,不用self
|
||||||
class BatteryState(TypedDict):
|
class BatteryState(TypedDict):
|
||||||
"""电池状态字典"""
|
"""电池状态字典"""
|
||||||
@@ -595,76 +471,54 @@ class BatteryPressSlot(Resource):
|
|||||||
def get_battery_info(self, index: int) -> Battery:
|
def get_battery_info(self, index: int) -> Battery:
|
||||||
return self.children[0]
|
return self.children[0]
|
||||||
|
|
||||||
# TODO:这个移液枪架子看一下从哪继承
|
|
||||||
class TipBox64State(TypedDict):
|
|
||||||
"""电池状态字典"""
|
|
||||||
tip_diameter: float = 5.0
|
|
||||||
tip_length: float = 50.0
|
|
||||||
with_tips: bool = True
|
|
||||||
|
|
||||||
class TipBox64(TipRack):
|
def TipBox64(
|
||||||
"""64孔枪头盒类"""
|
|
||||||
|
|
||||||
children: List[TipSpot] = []
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: str,
|
name: str,
|
||||||
size_x: float = 127.8,
|
size_x: float = 127.8,
|
||||||
size_y: float = 85.5,
|
size_y: float = 85.5,
|
||||||
size_z: float = 60.0,
|
size_z: float = 60.0,
|
||||||
category: str = "tip_box_64",
|
category: str = "tip_box_64",
|
||||||
model: Optional[str] = None,
|
model: Optional[str] = None,
|
||||||
):
|
):
|
||||||
"""初始化64孔枪头盒
|
"""64孔枪头盒类"""
|
||||||
|
from pylabrobot.resources.tip import Tip
|
||||||
|
|
||||||
Args:
|
# 创建8x8=64个枪头位
|
||||||
name: 枪头盒名称
|
def make_tip():
|
||||||
size_x: 长度 (mm)
|
return Tip(
|
||||||
size_y: 宽度 (mm)
|
has_filter=False,
|
||||||
size_z: 高度 (mm)
|
total_tip_length=20.0,
|
||||||
tip_diameter: 枪头直径 (mm)
|
maximal_volume=1000, # 1mL
|
||||||
tip_length: 枪头长度 (mm)
|
fitting_depth=8.0,
|
||||||
category: 类别
|
|
||||||
model: 型号
|
|
||||||
with_tips: 是否带枪头
|
|
||||||
"""
|
|
||||||
from pylabrobot.resources.tip import Tip
|
|
||||||
|
|
||||||
# 创建8x8=64个枪头位
|
|
||||||
def make_tip():
|
|
||||||
return Tip(
|
|
||||||
has_filter=False,
|
|
||||||
total_tip_length=20.0,
|
|
||||||
maximal_volume=1000, # 1mL
|
|
||||||
fitting_depth=8.0,
|
|
||||||
)
|
|
||||||
|
|
||||||
tip_spots = create_ordered_items_2d(
|
|
||||||
klass=TipSpot,
|
|
||||||
num_items_x=8,
|
|
||||||
num_items_y=8,
|
|
||||||
dx=8.0,
|
|
||||||
dy=8.0,
|
|
||||||
dz=0.0,
|
|
||||||
item_dx=9.0,
|
|
||||||
item_dy=9.0,
|
|
||||||
size_x=10,
|
|
||||||
size_y=10,
|
|
||||||
size_z=0.0,
|
|
||||||
make_tip=make_tip,
|
|
||||||
)
|
|
||||||
self._unilabos_state: WasteTipBoxstate = WasteTipBoxstate()
|
|
||||||
super().__init__(
|
|
||||||
name=name,
|
|
||||||
size_x=size_x,
|
|
||||||
size_y=size_y,
|
|
||||||
size_z=size_z,
|
|
||||||
ordered_items=tip_spots,
|
|
||||||
category=category,
|
|
||||||
model=model,
|
|
||||||
with_tips=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tip_spots = create_ordered_items_2d(
|
||||||
|
klass=TipSpot,
|
||||||
|
num_items_x=12,
|
||||||
|
num_items_y=8,
|
||||||
|
dx=8.0,
|
||||||
|
dy=8.0,
|
||||||
|
dz=0.0,
|
||||||
|
item_dx=9.0,
|
||||||
|
item_dy=9.0,
|
||||||
|
size_x=10,
|
||||||
|
size_y=10,
|
||||||
|
size_z=0.0,
|
||||||
|
make_tip=make_tip,
|
||||||
|
)
|
||||||
|
idx_available = list(range(0, 32)) + list(range(64, 96))
|
||||||
|
tip_spots_available = {k: v for i, (k, v) in enumerate(tip_spots.items()) if i in idx_available}
|
||||||
|
return TipRack(
|
||||||
|
name=name,
|
||||||
|
size_x=size_x,
|
||||||
|
size_y=size_y,
|
||||||
|
size_z=size_z,
|
||||||
|
ordered_items=tip_spots_available,
|
||||||
|
category=category,
|
||||||
|
model=model,
|
||||||
|
with_tips=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WasteTipBoxstate(TypedDict):
|
class WasteTipBoxstate(TypedDict):
|
||||||
@@ -682,8 +536,12 @@ class WasteTipBox(Trash):
|
|||||||
size_x: float = 127.8,
|
size_x: float = 127.8,
|
||||||
size_y: float = 85.5,
|
size_y: float = 85.5,
|
||||||
size_z: float = 60.0,
|
size_z: float = 60.0,
|
||||||
category: str = "waste_tip_box",
|
material_z_thickness=0,
|
||||||
model: Optional[str] = None,
|
max_volume=float("inf"),
|
||||||
|
category="trash",
|
||||||
|
model=None,
|
||||||
|
compute_volume_from_height=None,
|
||||||
|
compute_height_from_volume=None,
|
||||||
):
|
):
|
||||||
"""初始化废枪头盒
|
"""初始化废枪头盒
|
||||||
|
|
||||||
@@ -733,389 +591,6 @@ class WasteTipBox(Trash):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
class BottleRackState(TypedDict):
|
|
||||||
""" bottle_diameter: 瓶子直径 (mm)
|
|
||||||
bottle_height: 瓶子高度 (mm)
|
|
||||||
position_spacing: 位置间距 (mm)"""
|
|
||||||
bottle_diameter: float
|
|
||||||
bottle_height: float
|
|
||||||
name_to_index: dict
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BottleRack(Resource):
|
|
||||||
"""瓶架类 - 12个待配位置+12个已配位置"""
|
|
||||||
children: List[Resource] = []
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
size_x: float,
|
|
||||||
size_y: float,
|
|
||||||
size_z: float,
|
|
||||||
category: str = "bottle_rack",
|
|
||||||
model: Optional[str] = None,
|
|
||||||
num_items_x: int = 2,
|
|
||||||
num_items_y: int = 4,
|
|
||||||
position_spacing: float = 35.0,
|
|
||||||
orientation: str = "horizontal",
|
|
||||||
padding_x: float = 20.0,
|
|
||||||
padding_y: float = 20.0,
|
|
||||||
):
|
|
||||||
"""初始化瓶架
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name: 瓶架名称
|
|
||||||
size_x: 长度 (mm)
|
|
||||||
size_y: 宽度 (mm)
|
|
||||||
size_z: 高度 (mm)
|
|
||||||
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: BottleRackState = BottleRackState(
|
|
||||||
bottle_diameter=30.0,
|
|
||||||
bottle_height=100.0,
|
|
||||||
position_spacing=position_spacing,
|
|
||||||
name_to_index={},
|
|
||||||
)
|
|
||||||
# 基于网格生成瓶位坐标映射(居中摆放)
|
|
||||||
# 使用内边距,避免点跑到容器外(前端渲染不按mm等比缩放时更稳妥)
|
|
||||||
origin_x = padding_x
|
|
||||||
origin_y = padding_y
|
|
||||||
self.index_to_pos = {}
|
|
||||||
for j in range(num_items_y):
|
|
||||||
for i in range(num_items_x):
|
|
||||||
idx = j * num_items_x + i
|
|
||||||
if orientation == "vertical":
|
|
||||||
# 纵向:沿 y 方向优先排列
|
|
||||||
self.index_to_pos[idx] = Coordinate(
|
|
||||||
x=origin_x + j * position_spacing,
|
|
||||||
y=origin_y + i * position_spacing,
|
|
||||||
z=0,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# 横向(默认):沿 x 方向优先排列
|
|
||||||
self.index_to_pos[idx] = Coordinate(
|
|
||||||
x=origin_x + i * position_spacing,
|
|
||||||
y=origin_y + j * position_spacing,
|
|
||||||
z=0,
|
|
||||||
)
|
|
||||||
self.name_to_index = {}
|
|
||||||
self.name_to_pos = {}
|
|
||||||
self.num_items_x = num_items_x
|
|
||||||
self.num_items_y = num_items_y
|
|
||||||
self.orientation = orientation
|
|
||||||
self.padding_x = padding_x
|
|
||||||
self.padding_y = padding_y
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# TODO: 这里有些问题要重新写一下
|
|
||||||
def assign_child_resource_old(self, resource: Resource, location=Coordinate.zero(), reassign=True):
|
|
||||||
capacity = self.num_items_x * self.num_items_y
|
|
||||||
assert len(self.children) < capacity, "瓶架已满,无法添加更多瓶子"
|
|
||||||
index = len(self.children)
|
|
||||||
location = self.index_to_pos.get(index, Coordinate.zero())
|
|
||||||
self.name_to_pos[resource.name] = location
|
|
||||||
self.name_to_index[resource.name] = index
|
|
||||||
return super().assign_child_resource(resource, location, reassign)
|
|
||||||
|
|
||||||
def assign_child_resource(self, resource: Resource, index: int):
|
|
||||||
capacity = self.num_items_x * self.num_items_y
|
|
||||||
assert 0 <= index < capacity, "无效的瓶子索引"
|
|
||||||
self.name_to_index[resource.name] = index
|
|
||||||
location = self.index_to_pos[index]
|
|
||||||
return super().assign_child_resource(resource, location)
|
|
||||||
|
|
||||||
def unassign_child_resource(self, resource: Bottle):
|
|
||||||
super().unassign_child_resource(resource)
|
|
||||||
self.index_to_pos.pop(self.name_to_index.pop(resource.name, None), None)
|
|
||||||
|
|
||||||
def serialize(self) -> dict:
|
|
||||||
return {
|
|
||||||
**super().serialize(),
|
|
||||||
"num_items_x": self.num_items_x,
|
|
||||||
"num_items_y": self.num_items_y,
|
|
||||||
"position_spacing": self._unilabos_state.get("position_spacing", 35.0),
|
|
||||||
"orientation": self.orientation,
|
|
||||||
"padding_x": self.padding_x,
|
|
||||||
"padding_y": self.padding_y,
|
|
||||||
}
|
|
||||||
|
|
||||||
class BottleState(TypedDict):
|
|
||||||
diameter: float
|
|
||||||
height: float
|
|
||||||
electrolyte_name: str
|
|
||||||
electrolyte_volume: float
|
|
||||||
max_volume: float
|
|
||||||
|
|
||||||
class Bottle(Resource):
|
|
||||||
"""瓶子类 - 容纳电解液"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
category: str = "bottle",
|
|
||||||
):
|
|
||||||
"""初始化瓶子
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name: 瓶子名称
|
|
||||||
diameter: 直径 (mm)
|
|
||||||
height: 高度 (mm)
|
|
||||||
max_volume: 最大体积 (μL)
|
|
||||||
barcode: 二维码
|
|
||||||
category: 类别
|
|
||||||
model: 型号
|
|
||||||
"""
|
|
||||||
super().__init__(
|
|
||||||
name=name,
|
|
||||||
size_x=1,
|
|
||||||
size_y=1,
|
|
||||||
size_z=1,
|
|
||||||
category=category,
|
|
||||||
)
|
|
||||||
self._unilabos_state: BottleState = BottleState()
|
|
||||||
|
|
||||||
def aspirate_electrolyte(self, volume: float) -> bool:
|
|
||||||
current_volume = self._unilabos_state["electrolyte_volume"]
|
|
||||||
assert current_volume > volume, f"Cannot aspirate {volume}μL, only {current_volume}μL available."
|
|
||||||
self._unilabos_state["electrolyte_volume"] -= volume
|
|
||||||
return True
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
class ClipMagazine_four(ItemizedResource[ClipMagazineHole]):
|
|
||||||
"""子弹夹类 - 有4个洞位,每个洞位放多个极片"""
|
|
||||||
children: List[ClipMagazineHole]
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
size_x: float,
|
|
||||||
size_y: float,
|
|
||||||
size_z: float,
|
|
||||||
hole_diameter: float = 14.0,
|
|
||||||
hole_depth: float = 10.0,
|
|
||||||
hole_spacing: float = 25.0,
|
|
||||||
max_sheets_per_hole: int = 100,
|
|
||||||
category: str = "clip_magazine_four",
|
|
||||||
model: Optional[str] = None,
|
|
||||||
):
|
|
||||||
"""初始化子弹夹
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name: 子弹夹名称
|
|
||||||
size_x: 长度 (mm)
|
|
||||||
size_y: 宽度 (mm)
|
|
||||||
size_z: 高度 (mm)
|
|
||||||
hole_diameter: 洞直径 (mm)
|
|
||||||
hole_depth: 洞深度 (mm)
|
|
||||||
hole_spacing: 洞位间距 (mm)
|
|
||||||
max_sheets_per_hole: 每个洞位最大极片数量
|
|
||||||
category: 类别
|
|
||||||
model: 型号
|
|
||||||
"""
|
|
||||||
# 创建4个洞位,排成2x2布局
|
|
||||||
holes = create_ordered_items_2d(
|
|
||||||
klass=ClipMagazineHole,
|
|
||||||
num_items_x=2,
|
|
||||||
num_items_y=2,
|
|
||||||
dx=(size_x - 2 * hole_spacing) / 2, # 居中
|
|
||||||
dy=(size_y - hole_spacing) / 2, # 居中
|
|
||||||
dz=size_z - 0,
|
|
||||||
item_dx=hole_spacing,
|
|
||||||
item_dy=hole_spacing,
|
|
||||||
diameter=hole_diameter,
|
|
||||||
depth=hole_depth,
|
|
||||||
)
|
|
||||||
|
|
||||||
super().__init__(
|
|
||||||
name=name,
|
|
||||||
size_x=size_x,
|
|
||||||
size_y=size_y,
|
|
||||||
size_z=size_z,
|
|
||||||
ordered_items=holes,
|
|
||||||
category=category,
|
|
||||||
model=model,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 保存洞位的直径和深度
|
|
||||||
self.hole_diameter = hole_diameter
|
|
||||||
self.hole_depth = hole_depth
|
|
||||||
self.max_sheets_per_hole = max_sheets_per_hole
|
|
||||||
|
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClipMagazine_two(ItemizedResource[ClipMagazineHole]):
|
|
||||||
"""子弹夹类 - 有2个洞位,每个洞位放多个极片"""
|
|
||||||
children: List[ClipMagazineHole]
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
size_x: float,
|
|
||||||
size_y: float,
|
|
||||||
size_z: float,
|
|
||||||
hole_diameter: float = 14.0,
|
|
||||||
hole_depth: float = 10.0,
|
|
||||||
hole_spacing: float = 25.0,
|
|
||||||
max_sheets_per_hole: int = 100,
|
|
||||||
category: str = "clip_magazine_four",
|
|
||||||
model: Optional[str] = None,
|
|
||||||
):
|
|
||||||
"""初始化子弹夹
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name: 子弹夹名称
|
|
||||||
size_x: 长度 (mm)
|
|
||||||
size_y: 宽度 (mm)
|
|
||||||
size_z: 高度 (mm)
|
|
||||||
hole_diameter: 洞直径 (mm)
|
|
||||||
hole_depth: 洞深度 (mm)
|
|
||||||
hole_spacing: 洞位间距 (mm)
|
|
||||||
max_sheets_per_hole: 每个洞位最大极片数量
|
|
||||||
category: 类别
|
|
||||||
model: 型号
|
|
||||||
"""
|
|
||||||
# 创建4个洞位,排成2x2布局
|
|
||||||
holes = create_ordered_items_2d(
|
|
||||||
klass=ClipMagazineHole,
|
|
||||||
num_items_x=1,
|
|
||||||
num_items_y=2,
|
|
||||||
dx=(size_x - 2 * hole_spacing) / 2, # 居中
|
|
||||||
dy=(size_y - hole_spacing) / 2, # 居中
|
|
||||||
dz=size_z - 0,
|
|
||||||
item_dx=hole_spacing,
|
|
||||||
item_dy=hole_spacing,
|
|
||||||
diameter=hole_diameter,
|
|
||||||
depth=hole_depth,
|
|
||||||
)
|
|
||||||
|
|
||||||
super().__init__(
|
|
||||||
name=name,
|
|
||||||
size_x=size_x,
|
|
||||||
size_y=size_y,
|
|
||||||
size_z=size_z,
|
|
||||||
ordered_items=holes,
|
|
||||||
category=category,
|
|
||||||
model=model,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 保存洞位的直径和深度
|
|
||||||
self.hole_diameter = hole_diameter
|
|
||||||
self.hole_depth = hole_depth
|
|
||||||
self.max_sheets_per_hole = max_sheets_per_hole
|
|
||||||
|
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
class ClipMagazine_one(ItemizedResource[ClipMagazineHole]):
|
|
||||||
"""子弹夹类 - 有1个洞位,每个洞位放多个极片"""
|
|
||||||
children: List[ClipMagazineHole]
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
size_x: float,
|
|
||||||
size_y: float,
|
|
||||||
size_z: float,
|
|
||||||
hole_diameter: float = 14.0,
|
|
||||||
hole_depth: float = 10.0,
|
|
||||||
hole_spacing: float = 25.0,
|
|
||||||
max_sheets_per_hole: int = 100,
|
|
||||||
category: str = "clip_magazine_four",
|
|
||||||
model: Optional[str] = None,
|
|
||||||
):
|
|
||||||
"""初始化子弹夹
|
|
||||||
|
|
||||||
Args:
|
|
||||||
name: 子弹夹名称
|
|
||||||
size_x: 长度 (mm)
|
|
||||||
size_y: 宽度 (mm)
|
|
||||||
size_z: 高度 (mm)
|
|
||||||
hole_diameter: 洞直径 (mm)
|
|
||||||
hole_depth: 洞深度 (mm)
|
|
||||||
hole_spacing: 洞位间距 (mm)
|
|
||||||
max_sheets_per_hole: 每个洞位最大极片数量
|
|
||||||
category: 类别
|
|
||||||
model: 型号
|
|
||||||
"""
|
|
||||||
# 创建4个洞位,排成2x2布局
|
|
||||||
holes = create_ordered_items_2d(
|
|
||||||
klass=ClipMagazineHole,
|
|
||||||
num_items_x=1,
|
|
||||||
num_items_y=1,
|
|
||||||
dx=(size_x - 2 * hole_spacing) / 2, # 居中
|
|
||||||
dy=(size_y - hole_spacing) / 2, # 居中
|
|
||||||
dz=size_z - 0,
|
|
||||||
item_dx=hole_spacing,
|
|
||||||
item_dy=hole_spacing,
|
|
||||||
diameter=hole_diameter,
|
|
||||||
depth=hole_depth,
|
|
||||||
)
|
|
||||||
|
|
||||||
super().__init__(
|
|
||||||
name=name,
|
|
||||||
size_x=size_x,
|
|
||||||
size_y=size_y,
|
|
||||||
size_z=size_z,
|
|
||||||
ordered_items=holes,
|
|
||||||
category=category,
|
|
||||||
model=model,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 保存洞位的直径和深度
|
|
||||||
self.hole_diameter = hole_diameter
|
|
||||||
self.hole_depth = hole_depth
|
|
||||||
self.max_sheets_per_hole = max_sheets_per_hole
|
|
||||||
|
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
class CoincellDeck(Deck):
|
class CoincellDeck(Deck):
|
||||||
"""纽扣电池组装工作站台面类"""
|
"""纽扣电池组装工作站台面类"""
|
||||||
|
|
||||||
@@ -1155,122 +630,96 @@ class CoincellDeck(Deck):
|
|||||||
"""设置工作站的标准布局 - 包含子弹夹、料盘、瓶架等完整配置"""
|
"""设置工作站的标准布局 - 包含子弹夹、料盘、瓶架等完整配置"""
|
||||||
# ====================================== 子弹夹 ============================================
|
# ====================================== 子弹夹 ============================================
|
||||||
# 铝箔(1个洞位)
|
# 铝箔(1个洞位)
|
||||||
lvbo_zip = ClipMagazine_one("lvbo_zip", 80, 80, 10)
|
lvbo_zip = MagazineHolder_1("铝箔弹夹", 80, 80, 10)
|
||||||
self.assign_child_resource(lvbo_zip, Coordinate(x=2737.0, y=301.0, z=0))
|
self.assign_child_resource(lvbo_zip, Coordinate(x=2737.0, y=301.0, z=0))
|
||||||
|
|
||||||
# 正极片(4个洞位,2x2布局)
|
# 正极片(4个洞位,2x2布局)
|
||||||
zhengji_zip = ClipMagazine_four("zhengji_zip", 80, 80, 10)
|
zhengji_zip = MagazineHolder_4("正极弹夹", 80, 80, 10)
|
||||||
self.assign_child_resource(zhengji_zip, Coordinate(x=2799.0, y=356.0, z=0))
|
self.assign_child_resource(zhengji_zip, Coordinate(x=2799.0, y=356.0, z=0))
|
||||||
|
|
||||||
# 正极壳(4个洞位,2x2布局)
|
# 正极壳(4个洞位,2x2布局)
|
||||||
zhengjike_zip = ClipMagazine_four("zhengjike_zip", 80, 80, 10)
|
zhengjike_zip = MagazineHolder_4("正极壳弹夹", 80, 80, 10)
|
||||||
self.assign_child_resource(zhengjike_zip, Coordinate(x=2586.0, y=1143.0, z=0))
|
self.assign_child_resource(zhengjike_zip, Coordinate(x=2586.0, y=1143.0, z=0))
|
||||||
|
|
||||||
# 垫片(2个洞位,1x2布局)
|
# 垫片(2个洞位,1x2布局)
|
||||||
danpian_zip = ClipMagazine_two("danpian_zip", 80, 80, 10)
|
danpian_zip = MagazineHolder_2("垫片弹夹", 80, 80, 10)
|
||||||
self.assign_child_resource(danpian_zip, Coordinate(x=2690.0, y=1141.0, z=0))
|
self.assign_child_resource(danpian_zip, Coordinate(x=2690.0, y=1141.0, z=0))
|
||||||
|
|
||||||
# 负极壳(4个洞位,2x2布局)
|
# 负极壳(4个洞位,2x2布局)
|
||||||
fujike_zip = ClipMagazine_four("fujike_zip", 80, 80, 10)
|
fujike_zip = MagazineHolder_4("负极壳弹夹", 80, 80, 10)
|
||||||
self.assign_child_resource(fujike_zip, Coordinate(x=2492.0, y=1144.0, z=0))
|
self.assign_child_resource(fujike_zip, Coordinate(x=2492.0, y=1144.0, z=0))
|
||||||
|
|
||||||
# 弹片(2个洞位,1x2布局)
|
# 弹片(2个洞位,1x2布局)
|
||||||
tanpian_zip = ClipMagazine_two("tanpian_zip", 80, 80, 10)
|
tanpian_zip = MagazineHolder_2("弹片弹夹", 80, 80, 10)
|
||||||
self.assign_child_resource(tanpian_zip, Coordinate(x=2492.0, y=1139.0, z=0))
|
self.assign_child_resource(tanpian_zip, Coordinate(x=2492.0, y=1139.0, z=0))
|
||||||
|
|
||||||
# 成品弹夹(6个洞位,3x2布局)
|
# 成品弹夹(6个洞位,3x2布局)
|
||||||
chengpindanjia_zip = ClipMagazine("chengpindanjia_zip", 80, 80, 10)
|
chengpindanjia_zip = MagazineHolder_6("成品弹夹", 80, 80, 10)
|
||||||
self.assign_child_resource(chengpindanjia_zip, Coordinate(x=3112.0, y=1295.0, z=0))
|
self.assign_child_resource(chengpindanjia_zip, Coordinate(x=3112.0, y=1295.0, z=0))
|
||||||
|
|
||||||
# 为子弹夹添加极片
|
# 为子弹夹添加极片
|
||||||
for i in range(1): # ClipMagazine_one 有1个洞位
|
for i in range(1): # MagazineHolder_1 有1个洞位
|
||||||
lvbo = ElectrodeSheet(name=f"lvbo_{i}", size_x=12, size_y=12, size_z=0.1)
|
lvbo = ElectrodeSheet(name=f"铝箔_{i}", size_x=12, size_y=12, size_z=0.1)
|
||||||
lvbo_zip.children[i].assign_child_resource(lvbo, location=None)
|
lvbo_zip.children[i].assign_child_resource(lvbo, location=None)
|
||||||
for i in range(4): # ClipMagazine_four 有4个洞位
|
for i in range(4): # MagazineHolder_4 有4个洞位
|
||||||
zhengji = ElectrodeSheet(name=f"zhengji_{i}", size_x=12, size_y=12, size_z=0.1)
|
zhengji = ElectrodeSheet(name=f"正极_{i}", size_x=12, size_y=12, size_z=0.1)
|
||||||
zhengji_zip.children[i].assign_child_resource(zhengji, location=None)
|
zhengji_zip.children[i].assign_child_resource(zhengji, location=None)
|
||||||
for i in range(4): # ClipMagazine_four 有4个洞位
|
for i in range(4): # MagazineHolder_4 有4个洞位
|
||||||
zhengjike = ElectrodeSheet(name=f"zhengjike_{i}", size_x=12, size_y=12, size_z=0.1)
|
zhengjike = ElectrodeSheet(name=f"正极壳_{i}", size_x=12, size_y=12, size_z=0.1)
|
||||||
zhengjike_zip.children[i].assign_child_resource(zhengjike, location=None)
|
zhengjike_zip.children[i].assign_child_resource(zhengjike, location=None)
|
||||||
for i in range(2): # ClipMagazine_two 有2个洞位
|
for i in range(2): # MagazineHolder_2 有2个洞位
|
||||||
danpian = ElectrodeSheet(name=f"danpian_{i}", size_x=12, size_y=12, size_z=0.1)
|
danpian = ElectrodeSheet(name=f"垫片_{i}", size_x=12, size_y=12, size_z=0.1)
|
||||||
danpian_zip.children[i].assign_child_resource(danpian, location=None)
|
danpian_zip.children[i].assign_child_resource(danpian, location=None)
|
||||||
for i in range(4): # ClipMagazine_four 有4个洞位
|
for i in range(4): # MagazineHolder_4 有4个洞位
|
||||||
fujike = ElectrodeSheet(name=f"fujike_{i}", size_x=12, size_y=12, size_z=0.1)
|
fujike = ElectrodeSheet(name=f"负极壳_{i}", size_x=12, size_y=12, size_z=0.1)
|
||||||
fujike_zip.children[i].assign_child_resource(fujike, location=None)
|
fujike_zip.children[i].assign_child_resource(fujike, location=None)
|
||||||
for i in range(2): # ClipMagazine_two 有2个洞位
|
for i in range(2): # MagazineHolder_2 有2个洞位
|
||||||
tanpian = ElectrodeSheet(name=f"tanpian_{i}", size_x=12, size_y=12, size_z=0.1)
|
tanpian = ElectrodeSheet(name=f"弹片_{i}", size_x=12, size_y=12, size_z=0.1)
|
||||||
tanpian_zip.children[i].assign_child_resource(tanpian, location=None)
|
tanpian_zip.children[i].assign_child_resource(tanpian, location=None)
|
||||||
for i in range(6): # ClipMagazine 有6个洞位
|
# for i in range(6): # MagazineHolder_6 有6个洞位
|
||||||
chengpindanjia = ElectrodeSheet(name=f"chengpindanjia_{i}", size_x=12, size_y=12, size_z=0.1)
|
# chengpindanjia = ElectrodeSheet(name=f"成品弹夹_{i}", size_x=12, size_y=12, size_z=0.1)
|
||||||
chengpindanjia_zip.children[i].assign_child_resource(chengpindanjia, location=None)
|
# chengpindanjia_zip.children[i].assign_child_resource(chengpindanjia, location=None)
|
||||||
|
|
||||||
|
|
||||||
# ====================================== 物料板 ============================================
|
# ====================================== 物料板 ============================================
|
||||||
# 创建物料板(料盘carrier)- 4x4布局
|
# 创建物料板(料盘carrier)- 4x4布局
|
||||||
# 负极料盘
|
# 负极料盘
|
||||||
fujiliaopan = MaterialPlate(name="fujiliaopan", size_x=120, size_y=100, size_z=10.0, fill=True)
|
fujiliaopan = MaterialPlate(name="负极料盘", size_x=120, size_y=100, size_z=10.0, fill=True)
|
||||||
self.assign_child_resource(fujiliaopan, Coordinate(x=2107.0, y=304.0, z=0))
|
self.assign_child_resource(fujiliaopan, Coordinate(x=2107.0, y=304.0, z=0))
|
||||||
for i in range(16):
|
# for i in range(16):
|
||||||
fujipian = ElectrodeSheet(name=f"{fujiliaopan.name}_jipian_{i}", size_x=12, size_y=12, size_z=0.1)
|
# fujipian = ElectrodeSheet(name=f"{fujiliaopan.name}_jipian_{i}", size_x=12, size_y=12, size_z=0.1)
|
||||||
fujiliaopan.children[i].assign_child_resource(fujipian, location=None)
|
# fujiliaopan.children[i].assign_child_resource(fujipian, location=None)
|
||||||
|
|
||||||
# 隔膜料盘
|
# 隔膜料盘
|
||||||
gemoliaopan = MaterialPlate(name="gemoliaopan", size_x=120, size_y=100, size_z=10.0, fill=True)
|
gemoliaopan = MaterialPlate(name="隔膜料盘", size_x=120, size_y=100, size_z=10.0, fill=True)
|
||||||
self.assign_child_resource(gemoliaopan, Coordinate(x=2107.0, y=146.0, z=0))
|
self.assign_child_resource(gemoliaopan, Coordinate(x=2107.0, y=146.0, z=0))
|
||||||
for i in range(16):
|
# for i in range(16):
|
||||||
gemopian = ElectrodeSheet(name=f"{gemoliaopan.name}_jipian_{i}", size_x=12, size_y=12, size_z=0.1)
|
# gemopian = ElectrodeSheet(name=f"{gemoliaopan.name}_jipian_{i}", size_x=12, size_y=12, size_z=0.1)
|
||||||
gemoliaopan.children[i].assign_child_resource(gemopian, location=None)
|
# gemoliaopan.children[i].assign_child_resource(gemopian, location=None)
|
||||||
|
|
||||||
# ====================================== 瓶架、移液枪 ============================================
|
# ====================================== 瓶架、移液枪 ============================================
|
||||||
# 在台面上放置 3x4 瓶架、6x2 瓶架 与 64孔移液枪头盒
|
# 在台面上放置 3x4 瓶架、6x2 瓶架 与 64孔移液枪头盒
|
||||||
# 奔耀上料5ml分液瓶小板 - 2x4布局
|
# 奔耀上料5ml分液瓶小板 - 由奔曜跨站转运而来,不单独写
|
||||||
bottle_rack_2x4 = BottleRack(
|
|
||||||
name="bottle_rack_3x4",
|
# bottle_rack_3x4 = BottleRack(
|
||||||
size_x=210.0,
|
# name="bottle_rack_3x4",
|
||||||
size_y=140.0,
|
# size_x=210.0,
|
||||||
size_z=100.0,
|
# size_y=140.0,
|
||||||
num_items_x=2,
|
# size_z=100.0,
|
||||||
num_items_y=4,
|
# num_items_x=2,
|
||||||
position_spacing=35.0,
|
# num_items_y=4,
|
||||||
orientation="vertical",
|
# position_spacing=35.0,
|
||||||
)
|
# orientation="vertical",
|
||||||
self.assign_child_resource(bottle_rack_2x4, Coordinate(x=1542.0, y=717.0, z=0))
|
# )
|
||||||
|
# self.assign_child_resource(bottle_rack_3x4, Coordinate(x=1542.0, y=717.0, z=0))
|
||||||
|
|
||||||
# 电解液缓存位 - 6x2布局
|
# 电解液缓存位 - 6x2布局
|
||||||
bottle_rack_6x2 = BottleRack(
|
bottle_rack_6x2 = YIHUA_Electrolyte_12VialCarrier(name="bottle_rack_6x2")
|
||||||
name="bottle_rack_6x2",
|
|
||||||
size_x=120.0,
|
|
||||||
size_y=250.0,
|
|
||||||
size_z=100.0,
|
|
||||||
num_items_x=6,
|
|
||||||
num_items_y=2,
|
|
||||||
position_spacing=35.0,
|
|
||||||
orientation="vertical",
|
|
||||||
)
|
|
||||||
self.assign_child_resource(bottle_rack_6x2, Coordinate(x=300, y=300, z=0))
|
self.assign_child_resource(bottle_rack_6x2, Coordinate(x=300, y=300, z=0))
|
||||||
# 电解液回收位6x2
|
# 电解液回收位6x2
|
||||||
bottle_rack_2x6_2 = BottleRack(
|
bottle_rack_6x2_2 = YIHUA_Electrolyte_12VialCarrier(name="bottle_rack_6x2_2")
|
||||||
name="bottle_rack_6x2_2",
|
|
||||||
size_x=120.0,
|
|
||||||
size_y=250.0,
|
|
||||||
size_z=100.0,
|
|
||||||
num_items_x=6,
|
|
||||||
num_items_y=2,
|
|
||||||
position_spacing=35.0,
|
|
||||||
orientation="vertical",
|
|
||||||
)
|
|
||||||
self.assign_child_resource(bottle_rack_6x2_2, Coordinate(x=1765.0, y=869.0, z=0))
|
self.assign_child_resource(bottle_rack_6x2_2, Coordinate(x=1765.0, y=869.0, z=0))
|
||||||
|
|
||||||
# 将 ElectrodeSheet 放满 3x4 与 6x2 的所有孔位
|
|
||||||
for idx in range(bottle_rack_2x4.num_items_x * bottle_rack_2x4.num_items_y):
|
|
||||||
sheet = ElectrodeSheet(name=f"sheet_3x4_{idx}", size_x=12, size_y=12, size_z=0.1)
|
|
||||||
bottle_rack_2x4.assign_child_resource(sheet, index=idx)
|
|
||||||
|
|
||||||
for idx in range(bottle_rack_6x2.num_items_x * bottle_rack_6x2.num_items_y):
|
|
||||||
sheet = ElectrodeSheet(name=f"sheet_6x2_{idx}", size_x=12, size_y=12, size_z=0.1)
|
|
||||||
bottle_rack_6x2.assign_child_resource(sheet, index=idx)
|
|
||||||
|
|
||||||
tip_box = TipBox64(name="tip_box_64")
|
tip_box = TipBox64(name="tip_box_64")
|
||||||
self.assign_child_resource(tip_box, Coordinate(x=1938.0, y=743.0, z=0))
|
self.assign_child_resource(tip_box, Coordinate(x=1938.0, y=743.0, z=0))
|
||||||
|
|
||||||
@@ -1278,7 +727,6 @@ class CoincellDeck(Deck):
|
|||||||
self.assign_child_resource(waste_tip_box, Coordinate(x=1960.0, y=639.0, z=0))
|
self.assign_child_resource(waste_tip_box, Coordinate(x=1960.0, y=639.0, z=0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
deck = CoincellDeck(setup=True)
|
deck = CoincellDeck(setup=True)
|
||||||
print(deck)
|
print(deck)
|
||||||
@@ -112,20 +112,19 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
|||||||
def __init__(self,
|
def __init__(self,
|
||||||
config: dict = None,
|
config: dict = None,
|
||||||
deck=None,
|
deck=None,
|
||||||
address: str = "172.21.33.176",
|
address: str = "172.21.33.176",
|
||||||
port: str = "502",
|
port: str = "502",
|
||||||
debug_mode: bool = False,
|
debug_mode: bool = False,
|
||||||
*args,
|
*args,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|
||||||
if deck is None and config:
|
if deck is None and config:
|
||||||
deck = config.get('deck')
|
deck = config.get('deck')
|
||||||
else :
|
if deck is None:
|
||||||
logger.info("没有传入依华deck,检查启动json文件")
|
logger.info("没有传入依华deck,检查启动json文件")
|
||||||
super().__init__(deck=deck, *args, **kwargs,)
|
super().__init__(deck=deck, *args, **kwargs,)
|
||||||
self.debug_mode = debug_mode
|
self.debug_mode = debug_mode
|
||||||
|
|
||||||
|
|
||||||
""" 连接初始化 """
|
""" 连接初始化 """
|
||||||
modbus_client = TCPClient(addr=address, port=port)
|
modbus_client = TCPClient(addr=address, port=port)
|
||||||
logger.debug(f"创建 Modbus 客户端: {modbus_client}")
|
logger.debug(f"创建 Modbus 客户端: {modbus_client}")
|
||||||
@@ -140,12 +139,14 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
|||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
if not modbus_client.client.is_socket_open():
|
if not modbus_client.client.is_socket_open():
|
||||||
raise ValueError('modbus tcp connection failed')
|
raise ValueError('modbus tcp connection failed')
|
||||||
|
self.nodes = BaseClient.load_csv(os.path.join(os.path.dirname(__file__), 'coin_cell_assembly_a.csv'))
|
||||||
|
self.client = modbus_client.register_node_list(self.nodes)
|
||||||
else:
|
else:
|
||||||
print("测试模式,跳过连接")
|
print("测试模式,跳过连接")
|
||||||
|
self.nodes, self.client = None, None
|
||||||
|
|
||||||
""" 工站的配置 """
|
""" 工站的配置 """
|
||||||
self.nodes = BaseClient.load_csv(os.path.join(os.path.dirname(__file__), 'coin_cell_assembly_a.csv'))
|
|
||||||
self.client = modbus_client.register_node_list(self.nodes)
|
|
||||||
self.success = False
|
self.success = False
|
||||||
self.allow_data_read = False #允许读取函数运行标志位
|
self.allow_data_read = False #允许读取函数运行标志位
|
||||||
self.csv_export_thread = None
|
self.csv_export_thread = None
|
||||||
@@ -153,8 +154,6 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
|||||||
self.csv_export_file = None
|
self.csv_export_file = None
|
||||||
self.coin_num_N = 0 #已组装电池数量
|
self.coin_num_N = 0 #已组装电池数量
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def post_init(self, ros_node: ROS2WorkstationNode):
|
def post_init(self, ros_node: ROS2WorkstationNode):
|
||||||
self._ros_node = ros_node
|
self._ros_node = ros_node
|
||||||
#self.deck = create_a_coin_cell_deck()
|
#self.deck = create_a_coin_cell_deck()
|
||||||
|
|||||||
@@ -1,583 +0,0 @@
|
|||||||
"""
|
|
||||||
工作站物料管理基类
|
|
||||||
Workstation Material Management Base Class
|
|
||||||
|
|
||||||
基于PyLabRobot的物料管理系统
|
|
||||||
"""
|
|
||||||
from typing import Dict, Any, List, Optional, Union, Type
|
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
import json
|
|
||||||
|
|
||||||
from pylabrobot.resources import (
|
|
||||||
Resource as PLRResource,
|
|
||||||
Container,
|
|
||||||
Deck,
|
|
||||||
Coordinate as PLRCoordinate,
|
|
||||||
)
|
|
||||||
|
|
||||||
from unilabos.ros.nodes.resource_tracker import DeviceNodeResourceTracker
|
|
||||||
from unilabos.utils.log import logger
|
|
||||||
from unilabos.resources.graphio import resource_plr_to_ulab, resource_ulab_to_plr
|
|
||||||
|
|
||||||
|
|
||||||
class MaterialManagementBase(ABC):
|
|
||||||
"""物料管理基类
|
|
||||||
|
|
||||||
定义工作站物料管理的标准接口:
|
|
||||||
1. 物料初始化 - 根据配置创建物料资源
|
|
||||||
2. 物料追踪 - 实时跟踪物料位置和状态
|
|
||||||
3. 物料查找 - 按类型、位置、状态查找物料
|
|
||||||
4. 物料转换 - PyLabRobot与UniLab资源格式转换
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
device_id: str,
|
|
||||||
deck_config: Dict[str, Any],
|
|
||||||
resource_tracker: DeviceNodeResourceTracker,
|
|
||||||
children_config: Dict[str, Dict[str, Any]] = None
|
|
||||||
):
|
|
||||||
self.device_id = device_id
|
|
||||||
self.deck_config = deck_config
|
|
||||||
self.resource_tracker = resource_tracker
|
|
||||||
self.children_config = children_config or {}
|
|
||||||
|
|
||||||
# 创建主台面
|
|
||||||
self.plr_deck = self._create_deck()
|
|
||||||
|
|
||||||
# 扩展ResourceTracker
|
|
||||||
self._extend_resource_tracker()
|
|
||||||
|
|
||||||
# 注册deck到resource tracker
|
|
||||||
self.resource_tracker.add_resource(self.plr_deck)
|
|
||||||
|
|
||||||
# 初始化子资源
|
|
||||||
self.plr_resources = {}
|
|
||||||
self._initialize_materials()
|
|
||||||
|
|
||||||
def _create_deck(self) -> Deck:
|
|
||||||
"""创建主台面"""
|
|
||||||
return Deck(
|
|
||||||
name=f"{self.device_id}_deck",
|
|
||||||
size_x=self.deck_config.get("size_x", 1000.0),
|
|
||||||
size_y=self.deck_config.get("size_y", 1000.0),
|
|
||||||
size_z=self.deck_config.get("size_z", 500.0),
|
|
||||||
origin=PLRCoordinate(0, 0, 0)
|
|
||||||
)
|
|
||||||
|
|
||||||
def _extend_resource_tracker(self):
|
|
||||||
"""扩展ResourceTracker以支持PyLabRobot特定功能"""
|
|
||||||
|
|
||||||
def find_by_type(resource_type):
|
|
||||||
"""按类型查找资源"""
|
|
||||||
return self._find_resources_by_type_recursive(self.plr_deck, resource_type)
|
|
||||||
|
|
||||||
def find_by_category(category: str):
|
|
||||||
"""按类别查找资源"""
|
|
||||||
found = []
|
|
||||||
for resource in self._get_all_resources():
|
|
||||||
if hasattr(resource, 'category') and resource.category == category:
|
|
||||||
found.append(resource)
|
|
||||||
return found
|
|
||||||
|
|
||||||
def find_by_name_pattern(pattern: str):
|
|
||||||
"""按名称模式查找资源"""
|
|
||||||
import re
|
|
||||||
found = []
|
|
||||||
for resource in self._get_all_resources():
|
|
||||||
if re.search(pattern, resource.name):
|
|
||||||
found.append(resource)
|
|
||||||
return found
|
|
||||||
|
|
||||||
# 动态添加方法到resource_tracker
|
|
||||||
self.resource_tracker.find_by_type = find_by_type
|
|
||||||
self.resource_tracker.find_by_category = find_by_category
|
|
||||||
self.resource_tracker.find_by_name_pattern = find_by_name_pattern
|
|
||||||
|
|
||||||
def _find_resources_by_type_recursive(self, resource, target_type):
|
|
||||||
"""递归查找指定类型的资源"""
|
|
||||||
found = []
|
|
||||||
if isinstance(resource, target_type):
|
|
||||||
found.append(resource)
|
|
||||||
|
|
||||||
# 递归查找子资源
|
|
||||||
children = getattr(resource, "children", [])
|
|
||||||
for child in children:
|
|
||||||
found.extend(self._find_resources_by_type_recursive(child, target_type))
|
|
||||||
|
|
||||||
return found
|
|
||||||
|
|
||||||
def _get_all_resources(self) -> List[PLRResource]:
|
|
||||||
"""获取所有资源"""
|
|
||||||
all_resources = []
|
|
||||||
|
|
||||||
def collect_resources(resource):
|
|
||||||
all_resources.append(resource)
|
|
||||||
children = getattr(resource, "children", [])
|
|
||||||
for child in children:
|
|
||||||
collect_resources(child)
|
|
||||||
|
|
||||||
collect_resources(self.plr_deck)
|
|
||||||
return all_resources
|
|
||||||
|
|
||||||
def _initialize_materials(self):
|
|
||||||
"""初始化物料"""
|
|
||||||
try:
|
|
||||||
# 确定创建顺序,确保父资源先于子资源创建
|
|
||||||
creation_order = self._determine_creation_order()
|
|
||||||
|
|
||||||
# 按顺序创建资源
|
|
||||||
for resource_id in creation_order:
|
|
||||||
config = self.children_config[resource_id]
|
|
||||||
self._create_plr_resource(resource_id, config)
|
|
||||||
|
|
||||||
logger.info(f"物料管理系统初始化完成,共创建 {len(self.plr_resources)} 个资源")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"物料初始化失败: {e}")
|
|
||||||
|
|
||||||
def _determine_creation_order(self) -> List[str]:
|
|
||||||
"""确定资源创建顺序"""
|
|
||||||
order = []
|
|
||||||
visited = set()
|
|
||||||
|
|
||||||
def visit(resource_id: str):
|
|
||||||
if resource_id in visited:
|
|
||||||
return
|
|
||||||
visited.add(resource_id)
|
|
||||||
|
|
||||||
config = self.children_config.get(resource_id, {})
|
|
||||||
parent_id = config.get("parent")
|
|
||||||
|
|
||||||
# 如果有父资源,先访问父资源
|
|
||||||
if parent_id and parent_id in self.children_config:
|
|
||||||
visit(parent_id)
|
|
||||||
|
|
||||||
order.append(resource_id)
|
|
||||||
|
|
||||||
for resource_id in self.children_config:
|
|
||||||
visit(resource_id)
|
|
||||||
|
|
||||||
return order
|
|
||||||
|
|
||||||
def _create_plr_resource(self, resource_id: str, config: Dict[str, Any]):
|
|
||||||
"""创建PyLabRobot资源"""
|
|
||||||
try:
|
|
||||||
resource_type = config.get("type", "unknown")
|
|
||||||
data = config.get("data", {})
|
|
||||||
location_config = config.get("location", {})
|
|
||||||
|
|
||||||
# 创建位置坐标
|
|
||||||
location = PLRCoordinate(
|
|
||||||
x=location_config.get("x", 0.0),
|
|
||||||
y=location_config.get("y", 0.0),
|
|
||||||
z=location_config.get("z", 0.0)
|
|
||||||
)
|
|
||||||
|
|
||||||
# 根据类型创建资源
|
|
||||||
resource = self._create_resource_by_type(resource_id, resource_type, config, data, location)
|
|
||||||
|
|
||||||
if resource:
|
|
||||||
# 设置父子关系
|
|
||||||
parent_id = config.get("parent")
|
|
||||||
if parent_id and parent_id in self.plr_resources:
|
|
||||||
parent_resource = self.plr_resources[parent_id]
|
|
||||||
parent_resource.assign_child_resource(resource, location)
|
|
||||||
else:
|
|
||||||
# 直接放在deck上
|
|
||||||
self.plr_deck.assign_child_resource(resource, location)
|
|
||||||
|
|
||||||
# 保存资源引用
|
|
||||||
self.plr_resources[resource_id] = resource
|
|
||||||
|
|
||||||
# 注册到resource tracker
|
|
||||||
self.resource_tracker.add_resource(resource)
|
|
||||||
|
|
||||||
logger.debug(f"创建资源成功: {resource_id} ({resource_type})")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"创建资源失败 {resource_id}: {e}")
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def _create_resource_by_type(
|
|
||||||
self,
|
|
||||||
resource_id: str,
|
|
||||||
resource_type: str,
|
|
||||||
config: Dict[str, Any],
|
|
||||||
data: Dict[str, Any],
|
|
||||||
location: PLRCoordinate
|
|
||||||
) -> Optional[PLRResource]:
|
|
||||||
"""根据类型创建资源 - 子类必须实现"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
# ============ 物料查找接口 ============
|
|
||||||
|
|
||||||
def find_materials_by_type(self, material_type: str) -> List[PLRResource]:
|
|
||||||
"""按材料类型查找物料"""
|
|
||||||
return self.resource_tracker.find_by_category(material_type)
|
|
||||||
|
|
||||||
def find_material_by_id(self, resource_id: str) -> Optional[PLRResource]:
|
|
||||||
"""按ID查找物料"""
|
|
||||||
return self.plr_resources.get(resource_id)
|
|
||||||
|
|
||||||
def find_available_positions(self, position_type: str) -> List[PLRResource]:
|
|
||||||
"""查找可用位置"""
|
|
||||||
positions = self.resource_tracker.find_by_category(position_type)
|
|
||||||
available = []
|
|
||||||
|
|
||||||
for pos in positions:
|
|
||||||
if hasattr(pos, 'is_available') and pos.is_available():
|
|
||||||
available.append(pos)
|
|
||||||
elif hasattr(pos, 'children') and len(pos.children) == 0:
|
|
||||||
available.append(pos)
|
|
||||||
|
|
||||||
return available
|
|
||||||
|
|
||||||
def get_material_inventory(self) -> Dict[str, int]:
|
|
||||||
"""获取物料库存统计"""
|
|
||||||
inventory = {}
|
|
||||||
|
|
||||||
for resource in self._get_all_resources():
|
|
||||||
if hasattr(resource, 'category'):
|
|
||||||
category = resource.category
|
|
||||||
inventory[category] = inventory.get(category, 0) + 1
|
|
||||||
|
|
||||||
return inventory
|
|
||||||
|
|
||||||
# ============ 物料状态更新接口 ============
|
|
||||||
|
|
||||||
def update_material_location(self, material_id: str, new_location: PLRCoordinate) -> bool:
|
|
||||||
"""更新物料位置"""
|
|
||||||
try:
|
|
||||||
material = self.find_material_by_id(material_id)
|
|
||||||
if material:
|
|
||||||
material.location = new_location
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"更新物料位置失败: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def move_material(self, material_id: str, target_container_id: str) -> bool:
|
|
||||||
"""移动物料到目标容器"""
|
|
||||||
try:
|
|
||||||
material = self.find_material_by_id(material_id)
|
|
||||||
target = self.find_material_by_id(target_container_id)
|
|
||||||
|
|
||||||
if material and target:
|
|
||||||
# 从原位置移除
|
|
||||||
if material.parent:
|
|
||||||
material.parent.unassign_child_resource(material)
|
|
||||||
|
|
||||||
# 添加到新位置
|
|
||||||
target.assign_child_resource(material)
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"移动物料失败: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# ============ 资源转换接口 ============
|
|
||||||
|
|
||||||
def convert_to_unilab_format(self, plr_resource: PLRResource) -> Dict[str, Any]:
|
|
||||||
"""将PyLabRobot资源转换为UniLab格式"""
|
|
||||||
return resource_plr_to_ulab(plr_resource)
|
|
||||||
|
|
||||||
def convert_from_unilab_format(self, unilab_resource: Dict[str, Any]) -> PLRResource:
|
|
||||||
"""将UniLab格式转换为PyLabRobot资源"""
|
|
||||||
return resource_ulab_to_plr(unilab_resource)
|
|
||||||
|
|
||||||
def get_deck_state(self) -> Dict[str, Any]:
|
|
||||||
"""获取Deck状态"""
|
|
||||||
try:
|
|
||||||
return {
|
|
||||||
"deck_info": {
|
|
||||||
"name": self.plr_deck.name,
|
|
||||||
"size": {
|
|
||||||
"x": self.plr_deck.size_x,
|
|
||||||
"y": self.plr_deck.size_y,
|
|
||||||
"z": self.plr_deck.size_z
|
|
||||||
},
|
|
||||||
"children_count": len(self.plr_deck.children)
|
|
||||||
},
|
|
||||||
"resources": {
|
|
||||||
resource_id: self.convert_to_unilab_format(resource)
|
|
||||||
for resource_id, resource in self.plr_resources.items()
|
|
||||||
},
|
|
||||||
"inventory": self.get_material_inventory()
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"获取Deck状态失败: {e}")
|
|
||||||
return {"error": str(e)}
|
|
||||||
|
|
||||||
# ============ 数据持久化接口 ============
|
|
||||||
|
|
||||||
def save_state_to_file(self, file_path: str) -> bool:
|
|
||||||
"""保存状态到文件"""
|
|
||||||
try:
|
|
||||||
state = self.get_deck_state()
|
|
||||||
with open(file_path, 'w', encoding='utf-8') as f:
|
|
||||||
json.dump(state, f, indent=2, ensure_ascii=False)
|
|
||||||
logger.info(f"状态已保存到: {file_path}")
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"保存状态失败: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def load_state_from_file(self, file_path: str) -> bool:
|
|
||||||
"""从文件加载状态"""
|
|
||||||
try:
|
|
||||||
with open(file_path, 'r', encoding='utf-8') as f:
|
|
||||||
state = json.load(f)
|
|
||||||
|
|
||||||
# 重新创建资源
|
|
||||||
self._recreate_resources_from_state(state)
|
|
||||||
logger.info(f"状态已从文件加载: {file_path}")
|
|
||||||
return True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"加载状态失败: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _recreate_resources_from_state(self, state: Dict[str, Any]):
|
|
||||||
"""从状态重新创建资源"""
|
|
||||||
# 清除现有资源
|
|
||||||
self.plr_resources.clear()
|
|
||||||
self.plr_deck.children.clear()
|
|
||||||
|
|
||||||
# 从状态重新创建
|
|
||||||
resources_data = state.get("resources", {})
|
|
||||||
for resource_id, resource_data in resources_data.items():
|
|
||||||
try:
|
|
||||||
plr_resource = self.convert_from_unilab_format(resource_data)
|
|
||||||
self.plr_resources[resource_id] = plr_resource
|
|
||||||
self.plr_deck.assign_child_resource(plr_resource)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"重新创建资源失败 {resource_id}: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
class CoinCellMaterialManagement(MaterialManagementBase):
|
|
||||||
"""纽扣电池物料管理类
|
|
||||||
|
|
||||||
从 button_battery_station 抽取的物料管理功能
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _create_resource_by_type(
|
|
||||||
self,
|
|
||||||
resource_id: str,
|
|
||||||
resource_type: str,
|
|
||||||
config: Dict[str, Any],
|
|
||||||
data: Dict[str, Any],
|
|
||||||
location: PLRCoordinate
|
|
||||||
) -> Optional[PLRResource]:
|
|
||||||
"""根据类型创建纽扣电池相关资源"""
|
|
||||||
|
|
||||||
# 导入纽扣电池资源类
|
|
||||||
from unilabos.device_comms.button_battery_station import (
|
|
||||||
MaterialPlate, PlateSlot, ClipMagazine, BatteryPressSlot,
|
|
||||||
TipBox64, WasteTipBox, BottleRack, Battery, ElectrodeSheet
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
if resource_type == "material_plate":
|
|
||||||
return self._create_material_plate(resource_id, config, data, location)
|
|
||||||
|
|
||||||
elif resource_type == "plate_slot":
|
|
||||||
return self._create_plate_slot(resource_id, config, data, location)
|
|
||||||
|
|
||||||
elif resource_type == "clip_magazine":
|
|
||||||
return self._create_clip_magazine(resource_id, config, data, location)
|
|
||||||
|
|
||||||
elif resource_type == "battery_press_slot":
|
|
||||||
return self._create_battery_press_slot(resource_id, config, data, location)
|
|
||||||
|
|
||||||
elif resource_type == "tip_box":
|
|
||||||
return self._create_tip_box(resource_id, config, data, location)
|
|
||||||
|
|
||||||
elif resource_type == "waste_tip_box":
|
|
||||||
return self._create_waste_tip_box(resource_id, config, data, location)
|
|
||||||
|
|
||||||
elif resource_type == "bottle_rack":
|
|
||||||
return self._create_bottle_rack(resource_id, config, data, location)
|
|
||||||
|
|
||||||
elif resource_type == "battery":
|
|
||||||
return self._create_battery(resource_id, config, data, location)
|
|
||||||
|
|
||||||
else:
|
|
||||||
logger.warning(f"未知的资源类型: {resource_type}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"创建资源失败 {resource_id} ({resource_type}): {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _create_material_plate(self, resource_id: str, config: Dict[str, Any], data: Dict[str, Any], location: PLRCoordinate):
|
|
||||||
"""创建料板"""
|
|
||||||
from unilabos.device_comms.button_battery_station import MaterialPlate, ElectrodeSheet
|
|
||||||
|
|
||||||
plate = MaterialPlate(
|
|
||||||
name=resource_id,
|
|
||||||
size_x=config.get("size_x", 80.0),
|
|
||||||
size_y=config.get("size_y", 80.0),
|
|
||||||
size_z=config.get("size_z", 10.0),
|
|
||||||
hole_diameter=config.get("hole_diameter", 15.0),
|
|
||||||
hole_depth=config.get("hole_depth", 8.0),
|
|
||||||
hole_spacing_x=config.get("hole_spacing_x", 20.0),
|
|
||||||
hole_spacing_y=config.get("hole_spacing_y", 20.0),
|
|
||||||
number=data.get("number", "")
|
|
||||||
)
|
|
||||||
plate.location = location
|
|
||||||
|
|
||||||
# 如果有预填充的极片数据,创建极片
|
|
||||||
electrode_sheets = data.get("electrode_sheets", [])
|
|
||||||
for i, sheet_data in enumerate(electrode_sheets):
|
|
||||||
if i < len(plate.children): # 确保不超过洞位数量
|
|
||||||
hole = plate.children[i]
|
|
||||||
sheet = ElectrodeSheet(
|
|
||||||
name=f"{resource_id}_sheet_{i}",
|
|
||||||
diameter=sheet_data.get("diameter", 14.0),
|
|
||||||
thickness=sheet_data.get("thickness", 0.1),
|
|
||||||
mass=sheet_data.get("mass", 0.01),
|
|
||||||
material_type=sheet_data.get("material_type", "cathode"),
|
|
||||||
info=sheet_data.get("info", "")
|
|
||||||
)
|
|
||||||
hole.place_electrode_sheet(sheet)
|
|
||||||
|
|
||||||
return plate
|
|
||||||
|
|
||||||
def _create_plate_slot(self, resource_id: str, config: Dict[str, Any], data: Dict[str, Any], location: PLRCoordinate):
|
|
||||||
"""创建板槽位"""
|
|
||||||
from unilabos.device_comms.button_battery_station import PlateSlot
|
|
||||||
|
|
||||||
slot = PlateSlot(
|
|
||||||
name=resource_id,
|
|
||||||
max_plates=config.get("max_plates", 8)
|
|
||||||
)
|
|
||||||
slot.location = location
|
|
||||||
return slot
|
|
||||||
|
|
||||||
def _create_clip_magazine(self, resource_id: str, config: Dict[str, Any], data: Dict[str, Any], location: PLRCoordinate):
|
|
||||||
"""创建子弹夹"""
|
|
||||||
from unilabos.device_comms.button_battery_station import ClipMagazine
|
|
||||||
|
|
||||||
magazine = ClipMagazine(
|
|
||||||
name=resource_id,
|
|
||||||
size_x=config.get("size_x", 150.0),
|
|
||||||
size_y=config.get("size_y", 100.0),
|
|
||||||
size_z=config.get("size_z", 50.0),
|
|
||||||
hole_diameter=config.get("hole_diameter", 15.0),
|
|
||||||
hole_depth=config.get("hole_depth", 40.0),
|
|
||||||
hole_spacing=config.get("hole_spacing", 25.0),
|
|
||||||
max_sheets_per_hole=config.get("max_sheets_per_hole", 100)
|
|
||||||
)
|
|
||||||
magazine.location = location
|
|
||||||
return magazine
|
|
||||||
|
|
||||||
def _create_battery_press_slot(self, resource_id: str, config: Dict[str, Any], data: Dict[str, Any], location: PLRCoordinate):
|
|
||||||
"""创建电池压制槽"""
|
|
||||||
from unilabos.device_comms.button_battery_station import BatteryPressSlot
|
|
||||||
|
|
||||||
slot = BatteryPressSlot(
|
|
||||||
name=resource_id,
|
|
||||||
diameter=config.get("diameter", 20.0),
|
|
||||||
depth=config.get("depth", 15.0)
|
|
||||||
)
|
|
||||||
slot.location = location
|
|
||||||
return slot
|
|
||||||
|
|
||||||
def _create_tip_box(self, resource_id: str, config: Dict[str, Any], data: Dict[str, Any], location: PLRCoordinate):
|
|
||||||
"""创建枪头盒"""
|
|
||||||
from unilabos.device_comms.button_battery_station import TipBox64
|
|
||||||
|
|
||||||
tip_box = TipBox64(
|
|
||||||
name=resource_id,
|
|
||||||
size_x=config.get("size_x", 127.8),
|
|
||||||
size_y=config.get("size_y", 85.5),
|
|
||||||
size_z=config.get("size_z", 60.0),
|
|
||||||
with_tips=data.get("with_tips", True)
|
|
||||||
)
|
|
||||||
tip_box.location = location
|
|
||||||
return tip_box
|
|
||||||
|
|
||||||
def _create_waste_tip_box(self, resource_id: str, config: Dict[str, Any], data: Dict[str, Any], location: PLRCoordinate):
|
|
||||||
"""创建废枪头盒"""
|
|
||||||
from unilabos.device_comms.button_battery_station import WasteTipBox
|
|
||||||
|
|
||||||
waste_box = WasteTipBox(
|
|
||||||
name=resource_id,
|
|
||||||
size_x=config.get("size_x", 127.8),
|
|
||||||
size_y=config.get("size_y", 85.5),
|
|
||||||
size_z=config.get("size_z", 60.0),
|
|
||||||
max_tips=config.get("max_tips", 100)
|
|
||||||
)
|
|
||||||
waste_box.location = location
|
|
||||||
return waste_box
|
|
||||||
|
|
||||||
def _create_bottle_rack(self, resource_id: str, config: Dict[str, Any], data: Dict[str, Any], location: PLRCoordinate):
|
|
||||||
"""创建瓶架"""
|
|
||||||
from unilabos.device_comms.button_battery_station import BottleRack
|
|
||||||
|
|
||||||
rack = BottleRack(
|
|
||||||
name=resource_id,
|
|
||||||
size_x=config.get("size_x", 210.0),
|
|
||||||
size_y=config.get("size_y", 140.0),
|
|
||||||
size_z=config.get("size_z", 100.0),
|
|
||||||
bottle_diameter=config.get("bottle_diameter", 30.0),
|
|
||||||
bottle_height=config.get("bottle_height", 100.0),
|
|
||||||
position_spacing=config.get("position_spacing", 35.0)
|
|
||||||
)
|
|
||||||
rack.location = location
|
|
||||||
return rack
|
|
||||||
|
|
||||||
def _create_battery(self, resource_id: str, config: Dict[str, Any], data: Dict[str, Any], location: PLRCoordinate):
|
|
||||||
"""创建电池"""
|
|
||||||
from unilabos.device_comms.button_battery_station import Battery
|
|
||||||
|
|
||||||
battery = Battery(
|
|
||||||
name=resource_id,
|
|
||||||
diameter=config.get("diameter", 20.0),
|
|
||||||
height=config.get("height", 3.2),
|
|
||||||
max_volume=config.get("max_volume", 100.0),
|
|
||||||
barcode=data.get("barcode", "")
|
|
||||||
)
|
|
||||||
battery.location = location
|
|
||||||
return battery
|
|
||||||
|
|
||||||
# ============ 纽扣电池特定查找方法 ============
|
|
||||||
|
|
||||||
def find_material_plates(self):
|
|
||||||
"""查找所有料板"""
|
|
||||||
from unilabos.device_comms.button_battery_station import MaterialPlate
|
|
||||||
return self.resource_tracker.find_by_type(MaterialPlate)
|
|
||||||
|
|
||||||
def find_batteries(self):
|
|
||||||
"""查找所有电池"""
|
|
||||||
from unilabos.device_comms.button_battery_station import Battery
|
|
||||||
return self.resource_tracker.find_by_type(Battery)
|
|
||||||
|
|
||||||
def find_electrode_sheets(self):
|
|
||||||
"""查找所有极片"""
|
|
||||||
found = []
|
|
||||||
plates = self.find_material_plates()
|
|
||||||
for plate in plates:
|
|
||||||
for hole in plate.children:
|
|
||||||
if hasattr(hole, 'has_electrode_sheet') and hole.has_electrode_sheet():
|
|
||||||
found.append(hole._electrode_sheet)
|
|
||||||
return found
|
|
||||||
|
|
||||||
def find_plate_slots(self):
|
|
||||||
"""查找所有板槽位"""
|
|
||||||
from unilabos.device_comms.button_battery_station import PlateSlot
|
|
||||||
return self.resource_tracker.find_by_type(PlateSlot)
|
|
||||||
|
|
||||||
def find_clip_magazines(self):
|
|
||||||
"""查找所有子弹夹"""
|
|
||||||
from unilabos.device_comms.button_battery_station import ClipMagazine
|
|
||||||
return self.resource_tracker.find_by_type(ClipMagazine)
|
|
||||||
|
|
||||||
def find_press_slots(self):
|
|
||||||
"""查找所有压制槽"""
|
|
||||||
from unilabos.device_comms.button_battery_station import BatteryPressSlot
|
|
||||||
return self.resource_tracker.find_by_type(BatteryPressSlot)
|
|
||||||
@@ -46,6 +46,3 @@ CoincellDeck:
|
|||||||
init_param_schema: {}
|
init_param_schema: {}
|
||||||
registry_type: resource
|
registry_type: resource
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
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
|
||||||
284
unilabos/resources/battery/magazine.py
Normal file
284
unilabos/resources/battery/magazine.py
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
from typing import Dict, List, Optional, OrderedDict, Union
|
||||||
|
import math
|
||||||
|
|
||||||
|
from pylabrobot.resources.coordinate import Coordinate
|
||||||
|
from pylabrobot.resources import Resource, ResourceStack, ItemizedResource
|
||||||
|
from pylabrobot.resources.carrier import create_homogeneous_resources
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
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],
|
||||||
|
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: 洞位坐标列表
|
||||||
|
hole_diameter: 洞直径 (mm)
|
||||||
|
hole_depth: 洞深度 (mm)
|
||||||
|
max_sheets_per_hole: 每个洞位最大极片数量
|
||||||
|
category: 类别
|
||||||
|
model: 型号
|
||||||
|
"""
|
||||||
|
# 创建洞位
|
||||||
|
_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()))
|
||||||
|
|
||||||
|
return 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,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def MagazineHolder_4(
|
||||||
|
name: str,
|
||||||
|
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,
|
||||||
|
) -> MagazineHolder:
|
||||||
|
"""创建4孔子弹夹 - 正方形四角排布"""
|
||||||
|
# 计算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,
|
||||||
|
hole_diameter=hole_diameter,
|
||||||
|
hole_depth=hole_depth,
|
||||||
|
max_sheets_per_hole=max_sheets_per_hole,
|
||||||
|
category="clip_magazine_four",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def MagazineHolder_2(
|
||||||
|
name: str,
|
||||||
|
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,
|
||||||
|
) -> MagazineHolder:
|
||||||
|
"""创建2孔子弹夹 - 竖向排布"""
|
||||||
|
# 计算2个洞位的坐标(竖向排布)
|
||||||
|
center_x = size_x / 2
|
||||||
|
center_y = size_y / 2
|
||||||
|
offset = hole_spacing / 2
|
||||||
|
|
||||||
|
locations = [
|
||||||
|
Coordinate(center_x, center_y - offset, size_z - hole_depth), # 下方
|
||||||
|
Coordinate(center_x, 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,
|
||||||
|
hole_diameter=hole_diameter,
|
||||||
|
hole_depth=hole_depth,
|
||||||
|
max_sheets_per_hole=max_sheets_per_hole,
|
||||||
|
category="clip_magazine_two",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def MagazineHolder_1(
|
||||||
|
name: str,
|
||||||
|
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,
|
||||||
|
max_sheets_per_hole: int = 100,
|
||||||
|
) -> MagazineHolder:
|
||||||
|
"""创建1孔子弹夹 - 中心单孔"""
|
||||||
|
# 计算1个洞位的坐标(中心位置)
|
||||||
|
center_x = size_x / 2
|
||||||
|
center_y = size_y / 2
|
||||||
|
|
||||||
|
locations = [
|
||||||
|
Coordinate(center_x, center_y, size_z - hole_depth), # 中心
|
||||||
|
]
|
||||||
|
|
||||||
|
return magazine_factory(
|
||||||
|
name=name,
|
||||||
|
size_x=size_x,
|
||||||
|
size_y=size_y,
|
||||||
|
size_z=size_z,
|
||||||
|
locations=locations,
|
||||||
|
hole_diameter=hole_diameter,
|
||||||
|
hole_depth=hole_depth,
|
||||||
|
max_sheets_per_hole=max_sheets_per_hole,
|
||||||
|
category="clip_magazine_one",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def MagazineHolder_6(
|
||||||
|
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孔子弹夹 - 六边形排布"""
|
||||||
|
# 计算6个洞位的坐标(六边形排布:中心1个,周围5个)
|
||||||
|
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,
|
||||||
|
hole_diameter=hole_diameter,
|
||||||
|
hole_depth=hole_depth,
|
||||||
|
max_sheets_per_hole=max_sheets_per_hole,
|
||||||
|
category="clip_magazine_six",
|
||||||
|
)
|
||||||
@@ -29,7 +29,7 @@ class Bottle(Well):
|
|||||||
size_x: float = 0.0,
|
size_x: float = 0.0,
|
||||||
size_y: float = 0.0,
|
size_y: float = 0.0,
|
||||||
size_z: float = 0.0,
|
size_z: float = 0.0,
|
||||||
barcode: Optional[str] = "",
|
barcode: Optional[str] = None,
|
||||||
category: str = "container",
|
category: str = "container",
|
||||||
model: Optional[str] = None,
|
model: Optional[str] = None,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
|
|||||||
Reference in New Issue
Block a user