Compare commits

...

2 Commits

Author SHA1 Message Date
h840473807
42f7010134 提交扣电工站最新代码到YB3分支
提交扣电工站最新代码到YB3分支,更新注册表
2025-10-27 11:57:57 +08:00
calvincao
190b2d2518 清理扣电不必要代码 2025-10-27 11:43:03 +08:00
22 changed files with 1163 additions and 38717 deletions

View File

@@ -1,114 +0,0 @@
#!/usr/bin/env python
#coding=utf-8
ENV = 'pro'#'test'
class MQConfig:
"""MQTT 配置类"""
lab_id: str = '9F05593C'
instance_id: str = 'mqtt-cn-dsr48m6jy02'
group_id: str = 'GID_prod'
broker_url: str = 'mqtt-cn-dsr48m6jy02.mqtt.aliyuncs.com'
port: int = 8883
ca_content: str = '''-----BEGIN CERTIFICATE-----
MIID3jCCAsagAwIBAgIUDyIgmg4qZtMPa8r2Vvn1b1fgJ+YwDQYJKoZIhvcNAQEL
BQAwSzELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkJKMQswCQYDVQQHDAJCSjEQMA4G
A1UECgwHZHAudGVjaDEQMA4GA1UECwwHdW5pLWxhYjAeFw0yNTA1MDYxNTE0Mjda
Fw0zNTA1MDQxNTE0MjdaMEsxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJCSjELMAkG
A1UEBwwCQkoxEDAOBgNVBAoMB2RwLnRlY2gxEDAOBgNVBAsMB3VuaS1sYWIwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnTBywX+6DJ2n+prNKvylBBJF6
NHQrCt2cztZfswHsW4QhAbDddp4PRzNVzKtIfHX5ZrXGbxNT1/TqQYXKiFjKbfPC
VHTrS6+95LP3MxNTlBWHP6d2uI45KwrGgQ7D1uPDG1wZsfuJxvOkfAIxZRCDUMJr
erYYK/p2/GVMAO5YKE7wENUMN+iLfVQRqQJRgte9z0B35DxUeOUblJDun0Dpl/6L
0km/YRrjUKA/5+u/h+Ko9+36L1DAi+9rm3eyp+BQHBy5aiVhAG6uAJeMjbZMxwxz
ixg9cWNxP1BW+aQQzixbEQ+YlO9+w/soJkLstiK7jF8uIg2QvmNUKNlqab0pAgMB
AAGjgbkwgbYwHQYDVR0OBBYEFAqg0r7f6ngWODyVxVWHWM06b8wDMIGGBgNVHSME
fzB9gBQKoNK+3+p4Fjg8lcVVh1jNOm/MA6FPpE0wSzELMAkGA1UEBhMCQ04xCzAJ
BgNVBAgMAkJKMQswCQYDVQQHDAJCSjEQMA4GA1UECgwHZHAudGVjaDEQMA4GA1UE
CwwHdW5pLWxhYoIUDyIgmg4qZtMPa8r2Vvn1b1fgJ+YwDAYDVR0TBAUwAwEB/zAN
BgkqhkiG9w0BAQsFAAOCAQEAMylGHHhRCI8JLTizxqk2HaOFkF/WfnYC3XyNx3bK
9KqwVcvaqES+C058lits5nCV1qjjSnKt6xU11S8C6E28Kazh+wMqnSw63fz4UOY5
4cekPCPy8XcWlOY6UW2N27GR0c9JDo9ovruOn1Y4KjATpAQI4W2tPAQ2gCVSNpu1
bw5uw35yJSRzdQIHlsVbslvj2wcugK3GZHmmxJK+q9ww7G6xXtE2Y0+vl6AZRj+I
lcTy5TNNDZiiboIlAt+K3m4hxzSgGPbmFPJX3Lw3i+YMR/0PrWfXqxZgicO/V6/d
SgGBqq/tH1caiaEjCFudSZcOiZvHIlb09O4qL7mCtWEiEQ==
-----END CERTIFICATE-----
'''
cert_content: str = '''-----BEGIN CERTIFICATE-----
MIIDlTCCAn2gAwIBAgIUa/ce6dpJ8K7XNvT0LknVmLgfJMIwDQYJKoZIhvcNAQEL
BQAwSzELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkJKMQswCQYDVQQHDAJCSjEQMA4G
A1UECgwHZHAudGVjaDEQMA4GA1UECwwHdW5pLWxhYjAeFw0yNTA4MTMwNDQ0MDVa
Fw0yNjEyMjYwNDQ0MDVaMHoxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJCSjELMAkG
A1UEBwwCQkoxDDAKBgNVBAoMA0RQVDENMAsGA1UECwwETVFUVDEhMB8GCSqGSIb3
DQEJARYSaHVhaGFpbWluZ0BkcC50ZWNoMREwDwYDVQQDDAg0NzJBMjZBQzCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPc4NHXcwaFX3jSN6DnDYoY7ON6c
AeVIlcQp3CMHnulh4t3I3Fnsyelpc809s7l5vEpAjMIuZ40DJKZQmV9ckmeylMiY
bAk851+i8YcRQPeYYY7Ggt0sfkY3TWIIqptZtlIhXtkTCWw6xpHAPkYxqNTiUN/0
vwQWwiBS7WqD8NVjNhhHootYLsMjnQYc162L8nUwzG2pjB3UYqOldC3FkHXvBkG2
Oeex8VM8Urblv0huCmoFRyuMmNol0QWqp+6nwAgdvf89Z38NJByPI9VHaBB/VV1F
HiAZe3H8Ph7wzgUSXBuVHJ4BaeJbg4+ax6BccpaQn26jgpJGUEj+YR+NwdMCAwEA
AaNCMEAwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCAvQwIAYDVR0lAQH/BBYw
FAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4IBAQAZaF8puP0/
OcRM7Gcd4LrF8H/WG0Q7WM0T9BWGvee6A+Fcd4ajBC0S0tIfdsfYat0+g4U57jrr
vaQeZGFKc4YKVui8vSuth82fcsFk5fpyhz4JJRggzeoby+0gNx9eYDJwLIvbVy4Y
2LKGq+rsO07QF54jtwB4WpDNFnEIadXyjPBsMy/0Ssbetp827WYZygXYyAcUlCfN
Wns7K0phfZJwIMQgPs3d4mGwCC+xaRIB3GGjUGFXV1sFItjkTUHCvm+phw/MTpRp
pauplyDcWYux7z1dKhbuHElzCEqxZNwyI0nGJlRFP13Oo+jnuDO7gQh2lyz/AFyX
KyTA3xFZduHO
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID3jCCAsagAwIBAgIUDyIgmg4qZtMPa8r2Vvn1b1fgJ+YwDQYJKoZIhvcNAQEL
BQAwSzELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkJKMQswCQYDVQQHDAJCSjEQMA4G
A1UECgwHZHAudGVjaDEQMA4GA1UECwwHdW5pLWxhYjAeFw0yNTA1MDYxNTE0Mjda
Fw0zNTA1MDQxNTE0MjdaMEsxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJCSjELMAkG
A1UEBwwCQkoxEDAOBgNVBAoMB2RwLnRlY2gxEDAOBgNVBAsMB3VuaS1sYWIwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnTBywX+6DJ2n+prNKvylBBJF6
NHQrCt2cztZfswHsW4QhAbDddp4PRzNVzKtIfHX5ZrXGbxNT1/TqQYXKiFjKbfPC
VHTrS6+95LP3MxNTlBWHP6d2uI45KwrGgQ7D1uPDG1wZsfuJxvOkfAIxZRCDUMJr
erYYK/p2/GVMAO5YKE7wENUMN+iLfVQRqQJRgte9z0B35DxUeOUblJDun0Dpl/6L
0km/YRrjUKA/5+u/h+Ko9+36L1DAi+9rm3eyp+BQHBy5aiVhAG6uAJeMjbZMxwxz
ixg9cWNxP1BW+aQQzixbEQ+YlO9+w/soJkLstiK7jF8uIg2QvmNUKNlqab0pAgMB
AAGjgbkwgbYwHQYDVR0OBBYEFAqg0r7f6ngWODyVxVWHWM06b8wDMIGGBgNVHSME
fzB9gBQKoNK+3+p4Fjg8lcVVh1jNOm/MA6FPpE0wSzELMAkGA1UEBhMCQ04xCzAJ
BgNVBAgMAkJKMQswCQYDVQQHDAJCSjEQMA4GA1UECgwHZHAudGVjaDEQMA4GA1UE
CwwHdW5pLWxhYoIUDyIgmg4qZtMPa8r2Vvn1b1fgJ+YwDAYDVR0TBAUwAwEB/zAN
BgkqhkiG9w0BAQsFAAOCAQEAMylGHHhRCI8JLTizxqk2HaOFkF/WfnYC3XyNx3bK
9KqwVcvaqES+C058lits5nCV1qjjSnKt6xU11S8C6E28Kazh+wMqnSw63fz4UOY5
4cekPCPy8XcWlOY6UW2N27GR0c9JDo9ovruOn1Y4KjATpAQI4W2tPAQ2gCVSNpu1
bw5uw35yJSRzdQIHlsVbslvj2wcugK3GZHmmxJK+q9ww7G6xXtE2Y0+vl6AZRj+I
lcTy5TNNDZiiboIlAt+K3m4hxzSgGPbmFPJX3Lw3i+YMR/0PrWfXqxZgicO/V6/d
SgGBqq/tH1caiaEjCFudSZcOiZvHIlb09O4qL7mCtWEiEQ==
-----END CERTIFICATE-----
'''
key_content: str = '''-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA9zg0ddzBoVfeNI3oOcNihjs43pwB5UiVxCncIwee6WHi3cjc
WezJ6WlzzT2zuXm8SkCMwi5njQMkplCZX1ySZ7KUyJhsCTznX6LxhxFA95hhjsaC
3Sx+RjdNYgiqm1m2UiFe2RMJbDrGkcA+RjGo1OJQ3/S/BBbCIFLtaoPw1WM2GEei
i1guwyOdBhzXrYvydTDMbamMHdRio6V0LcWQde8GQbY557HxUzxStuW/SG4KagVH
K4yY2iXRBaqn7qfACB29/z1nfw0kHI8j1UdoEH9VXUUeIBl7cfw+HvDOBRJcG5Uc
ngFp4luDj5rHoFxylpCfbqOCkkZQSP5hH43B0wIDAQABAoIBAAPzz0ZUcqmR1Eva
5PH98gQzp2wB9snLY86HY3Z/JVAPf5Ht9sbAUWHhT8PVoWpIasSmFbuJxz6DRk3S
M8VVVipxxgcTWqo/JOD4HZiCNfcRru6+5dHxZ4p2B/n4EWfoy+KyEZkgd5jQFONj
jIX+rDR3qZzFqoBRhQSHLuD+i66eZ7l1LOqsnk51r3nTCnGmdyV8fll56MMB5D6+
8LN2rwbmSYX/UIBBqHUthgEt2onFNaetTLgSa3RSNGZ3xEZt4N32vw1SARxItuso
npAAY77POMUwWe3666fETI+yr/gJuppvTF4sQUXy7I4iz7I18n2SYivHabdgnk6H
7y1TcGECgYEA/NbBLFz1YPOQiT6TsuitIlfWcFWXYI4yHh/Mwwm/heHV683HrUti
RSHWbFxggW70BYJbGAQprEe9UIRVdP9YNi3aPeN5WNfnTFHlN2HRiKenlETM1tw9
yaSWjNbAyc2ka+l1EblMJy92xoCkErS8riEPW83o+3+LqJwnjsJ8tVECgYEA+k93
AyNpXuOZldAoqSHF3wHgzgd2jhfVdQcNlz9sLfT8TAdoR01mdBtdytcYAH+FHplW
wlkCfpT1RPf3fEd0Asy727pJnL9v/QfY/BB+vfgWKUQg9CWNIevwItCaTNOSekis
lKl5dxNGOyouU7rPbTj9BC26OHA50Z3vLMKmi+MCgYEAy0Sb6N6TJ26pNK1qcNs+
1e1oKMem+6lWAYHvTJ35q9jz8q9taJTCXHHnwRZDP8vDwuoZ8iTmm+rQ+HprebQP
Zv9WBYtrc1GgUmtErFGn8wVWZI0rYVGPGx2HK5M7SwJYvajixW0DHD28b7ncLm2/
gv5xKo1QUWEpFlT0OIGDYQECgYEA8WRlH6+s1Iel++ZM8B7T1ibXh5mG6a1ue3eb
0bqmNwPFtASIugqYvWwO3ajlSsWvuTyjgLWaRDye9C42i7HU3UZX/KUAjJvKAjjp
Nt0pfUadCJrdNNZp7sa8RLbrtx9qaWdgl9WAgCckWbZqCvFjTK/iwX7f0cHY4J/w
ojftqYUCgYARM6YaEJuBJEBmZV1I0rweiguqWssZz2j1awSlsfYxckwnci4VtSMI
D/sp0Wp0yn2N4cgqp49BFD0rCQCTsASVICEf9HWdMQXsUhzWsz4SjVEhjWWC1VAk
sEL+BOcbsHy3qMbV2uKBHrhuZShDdy5KtCm9TB+7zTWyDVHwE24nig==
-----END RSA PRIVATE KEY-----
'''
# HTTP配置
class HTTPConfig:
remote_addr = "https://uni-lab.test.bohrium.com/api/v1"

File diff suppressed because it is too large Load Diff

View File

@@ -656,16 +656,25 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
# self.success = True
# return self.success
def func_pack_send_msg_cmd(self, elec_use_num) -> bool:
def func_pack_send_msg_cmd(self, elec_use_num, elec_vol, assembly_type, assembly_pressure) -> bool:
"""UNILAB写参数"""
while (self.request_rec_msg_status) == False:
print("wait for request_rec_msg_status to True")
time.sleep(1)
self.success = False
#self._unilab_send_msg_electrolyte_num(elec_num)
time.sleep(1)
#设置平行样数目
self._unilab_send_msg_electrolyte_use_num(elec_use_num)
time.sleep(1)
#发送电解液加注量
self._unilab_send_msg_electrolyte_vol(elec_vol)
time.sleep(1)
#发送电解液组装类型
self._unilab_send_msg_assembly_type(assembly_type)
time.sleep(1)
#发送电池压制力
self._unilab_send_msg_assembly_pressure(assembly_pressure)
time.sleep(1)
self._unilab_send_msg_succ_cmd(True)
time.sleep(1)
while (self.request_rec_msg_status) == True:
@@ -775,8 +784,8 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
def func_allpack_cmd(self, elec_num, elec_use_num, file_path: str="D:\\coin_cell_data") -> bool:
elec_num, elec_use_num = int(elec_num), int(elec_use_num)
def func_allpack_cmd(self, elec_num, elec_use_num, elec_vol:int=50, assembly_type:int=7, assembly_pressure:int=4200, file_path: str="D:\\coin_cell_data") -> bool:
elec_num, elec_use_num, elec_vol, assembly_type, assembly_pressure = int(elec_num), int(elec_use_num), int(elec_vol), int(assembly_type), int(assembly_pressure)
summary_csv_file = os.path.join(file_path, "duandian.csv")
# 如果断点文件存在,先读取之前的进度
if os.path.exists(summary_csv_file):
@@ -826,7 +835,7 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
print(f"开始第{last_i+i+1}瓶电解液的组装")
#第一个循环从上次断点继续后续循环从0开始
j_start = last_j if i == last_i else 0
self.func_pack_send_msg_cmd(elec_use_num-j_start)
self.func_pack_send_msg_cmd(elec_use_num-j_start, elec_vol, assembly_type, assembly_pressure)
for j in range(j_start, elec_use_num):
print(f"开始第{last_i+i+1}瓶电解液的第{j+j_start+1}个电池组装")

View File

@@ -43,4 +43,21 @@ REG_DATA_ELECTROLYTE_USE_NUM,INT16,,,,hold_register,10000,
UNILAB_SEND_FINISHED_CMD,BOOL,,,,coil,8730,
UNILAB_RECE_FINISHED_CMD,BOOL,,,,coil,8530,
REG_DATA_ASSEMBLY_TYPE,INT16,,,,hold_register,10018,ASSEMBLY_TYPE7or8
COIL_ALUMINUM_FOIL,BOOL,,,,coil,8340,
COIL_ALUMINUM_FOIL,BOOL,,使用铝箔垫,,coil,8340,
REG_MSG_NE_PLATE_MATRIX,INT16,,负极片矩阵点位,,hold_register,440,
REG_MSG_SEPARATOR_PLATE_MATRIX,INT16,,隔膜矩阵点位,,hold_register,450,
REG_MSG_TIP_BOX_MATRIX,INT16,,移液枪头矩阵点位,,hold_register,480,
REG_MSG_NE_PLATE_NUM,INT16,,负极片盘数,,hold_register,443,
REG_MSG_SEPARATOR_PLATE_NUM,INT16,,隔膜盘数,,hold_register,453,
REG_MSG_PRESS_MODE,BOOL,,压制模式false:压力检测模式True:距离模式),,coil,8360,电池压制模式
,,,,,,,
,BOOL,,视觉对位false:使用true:忽略),,coil,8300,视觉对位
,BOOL,,复检false:使用true:忽略),,coil,8310,视觉复检
,BOOL,,手套箱_左仓false:使用true:忽略),,coil,8320,手套箱左仓
,BOOL,,手套箱_右仓false:使用true:忽略),,coil,8420,手套箱右仓
,BOOL,,真空检知false:使用true:忽略),,coil,8350,真空检知
,BOOL,,电解液添加模式false:单次滴液true:二次滴液),,coil,8370,滴液模式
,BOOL,,正极片称重false:使用true:忽略),,coil,8380,正极片称重
,BOOL,,正负极片组装方式false:正装true:倒装),,coil,8390,正负极反装
,BOOL,,压制清洁false:使用true:忽略),,coil,8400,压制清洁
,BOOL,,物料盘摆盘方式false:水平摆盘true:堆叠摆盘),,coil,8410,负极片摆盘方式
1 Name DataType InitValue Comment Attribute DeviceType Address
43 UNILAB_SEND_FINISHED_CMD BOOL coil 8730
44 UNILAB_RECE_FINISHED_CMD BOOL coil 8530
45 REG_DATA_ASSEMBLY_TYPE INT16 hold_register 10018 ASSEMBLY_TYPE7or8
46 COIL_ALUMINUM_FOIL BOOL ʹ coil 8340
47 REG_MSG_NE_PLATE_MATRIX INT16 Ƭλ hold_register 440
48 REG_MSG_SEPARATOR_PLATE_MATRIX INT16 Ĥλ hold_register 450
49 REG_MSG_TIP_BOX_MATRIX INT16 Һǹͷλ hold_register 480
50 REG_MSG_NE_PLATE_NUM INT16 Ƭ hold_register 443
51 REG_MSG_SEPARATOR_PLATE_NUM INT16 Ĥ hold_register 453
52 REG_MSG_PRESS_MODE BOOL ѹģʽfalse:ѹģʽTrue:ģʽ coil 8360 ѹģʽ
53
54 BOOL Ӿλfalse:ʹãtrue:ԣ coil 8300 Ӿλ
55 BOOL 죨false:ʹãtrue:ԣ coil 8310 Ӿ
56 BOOL _֣false:ʹãtrue:ԣ coil 8320
57 BOOL _Ҳ֣false:ʹãtrue:ԣ coil 8420 Ҳ
58 BOOL ռ֪false:ʹãtrue:ԣ coil 8350 ռ֪
59 BOOL Һģʽfalse:εҺtrue:εҺ coil 8370 Һģʽ
60 BOOL Ƭأfalse:ʹãtrue:ԣ coil 8380 Ƭ
61 BOOL Ƭװʽfalse:װtrue:װ coil 8390 װ
62 BOOL ѹࣨfalse:ʹãtrue:ԣ coil 8400 ѹ
63 BOOL ̷̰ʽfalse:ˮƽ̣true:ѵ̣ coil 8410 Ƭ̷ʽ

View File

@@ -1,44 +0,0 @@
Name,DataType,InitValue,Comment,Attribute,DeviceType,Address
COIL_SYS_START_CMD,BOOL,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8010
COIL_SYS_STOP_CMD,BOOL,,<EFBFBD>豸ֹͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8020
COIL_SYS_RESET_CMD,BOOL,,<EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8030
COIL_SYS_HAND_CMD,BOOL,,<EFBFBD><EFBFBD>ֶ<EFBFBD>ģʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8040
COIL_SYS_AUTO_CMD,BOOL,,<EFBFBD><EFBFBD>Զ<EFBFBD>ģʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8050
COIL_SYS_INIT_CMD,BOOL,,<EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ģʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8060
COIL_UNILAB_SEND_MSG_SUCC_CMD,BOOL,,UNILAB<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8700
COIL_UNILAB_REC_MSG_SUCC_CMD,BOOL,,UNILAB<EFBFBD><EFBFBD><EFBFBD>ܲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8710
COIL_SYS_START_STATUS,BOOL,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8210
COIL_SYS_STOP_STATUS,BOOL,,<EFBFBD>豸ֹͣ<EFBFBD><EFBFBD>,,coil,8220
COIL_SYS_RESET_STATUS,BOOL,,<EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>,,coil,8230
COIL_SYS_HAND_STATUS,BOOL,,<EFBFBD><EFBFBD>ֶ<EFBFBD>ģʽ,,coil,8240
COIL_SYS_AUTO_STATUS,BOOL,,<EFBFBD><EFBFBD>Զ<EFBFBD>ģʽ,,coil,8250
COIL_SYS_INIT_STATUS,BOOL,,<EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8260
COIL_REQUEST_REC_MSG_STATUS,BOOL,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8510
COIL_REQUEST_SEND_MSG_STATUS,BOOL,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,coil,8500
REG_MSG_ELECTROLYTE_USE_NUM,INT16,,<EFBFBD><EFBFBD>ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һʹ<EFBFBD>ô<EFBFBD><EFBFBD><EFBFBD>,,hold_register,11000
REG_MSG_ELECTROLYTE_NUM,INT16,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һʹ<EFBFBD><EFBFBD>ƿ<EFBFBD><EFBFBD>,,hold_register,11002
REG_MSG_ELECTROLYTE_VOLUME,INT16,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һ<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>,,hold_register,11004
REG_MSG_ASSEMBLY_TYPE,INT16,,<EFBFBD><EFBFBD>װ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD>ѵ<EFBFBD><EFBFBD><EFBFBD>ʽ,,hold_register,11006
REG_MSG_ASSEMBLY_PRESSURE,INT16,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,hold_register,11008
REG_DATA_ASSEMBLY_COIN_CELL_NUM,INT16,,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,hold_register,10000
REG_DATA_OPEN_CIRCUIT_VOLTAGE,FLOAT32,,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,hold_register,10002
REG_DATA_AXIS_X_POS,FLOAT32,,<EFBFBD><EFBFBD>ҺX<EFBFBD>ᵱǰλ<EFBFBD><EFBFBD>,,hold_register,10004
REG_DATA_AXIS_Y_POS,FLOAT32,,<EFBFBD><EFBFBD>ҺZ<EFBFBD>ᵱǰλ<EFBFBD><EFBFBD>,,hold_register,10006
REG_DATA_AXIS_Z_POS,FLOAT32,,<EFBFBD><EFBFBD>ҺY<EFBFBD>ᵱǰλ<EFBFBD><EFBFBD>,,hold_register,10008
REG_DATA_POLE_WEIGHT,FLOAT32,,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,hold_register,10010
REG_DATA_ASSEMBLY_PER_TIME,FLOAT32,,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD>ŵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װʱ<EFBFBD><EFBFBD>,,hold_register,10012
REG_DATA_ASSEMBLY_PRESSURE,INT16,,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,hold_register,10014
REG_DATA_ELECTROLYTE_VOLUME,INT16,,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һ<EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>,,hold_register,10016
REG_DATA_COIN_NUM,INT16,,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,hold_register,10018
REG_DATA_ELECTROLYTE_CODE,STRING,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һ<EFBFBD><EFBFBD>ά<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>к<EFBFBD>,,hold_register,10020
REG_DATA_COIN_CELL_CODE,STRING,,<EFBFBD><EFBFBD><EFBFBD>ض<EFBFBD>ά<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>к<EFBFBD>,,hold_register,10030
REG_DATA_STACK_VISON_CODE,STRING,,<EFBFBD><EFBFBD><EFBFBD>϶ѵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼƬ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,hold_register,12004
REG_DATA_GLOVE_BOX_PRESSURE,FLOAT32,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD>,,hold_register,10050
REG_DATA_GLOVE_BOX_WATER_CONTENT,FLOAT32,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˮ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,hold_register,10052
REG_DATA_GLOVE_BOX_O2_CONTENT,FLOAT32,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,hold_register,10054
UNILAB_SEND_ELECTROLYTE_BOTTLE_NUM,BOOL,,Unilabȷ<EFBFBD><EFBFBD><EFBFBD>ѷ<EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD>Һƿ<EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>,,coil,8720
UNILAB_RECE_ELECTROLYTE_BOTTLE_NUM,BOOL,,Unilab<EFBFBD>ɽ<EFBFBD><EFBFBD>ܵ<EFBFBD><EFBFBD><EFBFBD>Һƿ<EFBFBD><EFBFBD>,,coil,8520
REG_MSG_ELECTROLYTE_NUM_USED,INT16,,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һ<EFBFBD><EFBFBD>װ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,hold_register,496
REG_DATA_ELECTROLYTE_USE_NUM,INT16,,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>װƽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,,hold_register,10000
UNILAB_SEND_FINISHED_CMD,BOOL,,Unilab<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>յ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>,,coil,8730
UNILAB_RECE_FINISHED_CMD,BOOL,,<EFBFBD><EFBFBD>֪unilab<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>,,coil,8530
1 Name DataType InitValue Comment Attribute DeviceType Address
2 COIL_SYS_START_CMD BOOL 设备启动命令 coil 8010
3 COIL_SYS_STOP_CMD BOOL 设备停止命令 coil 8020
4 COIL_SYS_RESET_CMD BOOL 设备复位命令 coil 8030
5 COIL_SYS_HAND_CMD BOOL 设备手动模式命令 coil 8040
6 COIL_SYS_AUTO_CMD BOOL 设备自动模式命令 coil 8050
7 COIL_SYS_INIT_CMD BOOL 设备初始化模式命令 coil 8060
8 COIL_UNILAB_SEND_MSG_SUCC_CMD BOOL UNILAB发送配方完毕 coil 8700
9 COIL_UNILAB_REC_MSG_SUCC_CMD BOOL UNILAB接受测试数据完毕 coil 8710
10 COIL_SYS_START_STATUS BOOL 设备启动中 coil 8210
11 COIL_SYS_STOP_STATUS BOOL 设备停止中 coil 8220
12 COIL_SYS_RESET_STATUS BOOL 设备复位中 coil 8230
13 COIL_SYS_HAND_STATUS BOOL 设备手动模式 coil 8240
14 COIL_SYS_AUTO_STATUS BOOL 设备自动模式 coil 8250
15 COIL_SYS_INIT_STATUS BOOL 设备初始化完成 coil 8260
16 COIL_REQUEST_REC_MSG_STATUS BOOL 设备请求接受配方 coil 8510
17 COIL_REQUEST_SEND_MSG_STATUS BOOL 设备请求发送测试数据 coil 8500
18 REG_MSG_ELECTROLYTE_USE_NUM INT16 单瓶电解液使用次数 hold_register 11000
19 REG_MSG_ELECTROLYTE_NUM INT16 电解液使用瓶数 hold_register 11002
20 REG_MSG_ELECTROLYTE_VOLUME INT16 电解液吸取量 hold_register 11004
21 REG_MSG_ASSEMBLY_TYPE INT16 组装参数:极片堆叠方式 hold_register 11006
22 REG_MSG_ASSEMBLY_PRESSURE INT16 电池组装压制力 hold_register 11008
23 REG_DATA_ASSEMBLY_COIN_CELL_NUM INT16 当前完成组装电池数量 hold_register 10000
24 REG_DATA_OPEN_CIRCUIT_VOLTAGE FLOAT32 当前电池电压数据 hold_register 10002
25 REG_DATA_AXIS_X_POS FLOAT32 分液X轴当前位置 hold_register 10004
26 REG_DATA_AXIS_Y_POS FLOAT32 分液Z轴当前位置 hold_register 10006
27 REG_DATA_AXIS_Z_POS FLOAT32 分液Y轴当前位置 hold_register 10008
28 REG_DATA_POLE_WEIGHT FLOAT32 当前电池正极片称重数据 hold_register 10010
29 REG_DATA_ASSEMBLY_PER_TIME FLOAT32 当前单颗电池组装时间 hold_register 10012
30 REG_DATA_ASSEMBLY_PRESSURE INT16 当前电池组装压制力 hold_register 10014
31 REG_DATA_ELECTROLYTE_VOLUME INT16 当前电解液加注量 hold_register 10016
32 REG_DATA_COIN_NUM INT16 当前电池物料数 hold_register 10018
33 REG_DATA_ELECTROLYTE_CODE STRING 电解液二维码序列号 hold_register 10020
34 REG_DATA_COIN_CELL_CODE STRING 电池二维码序列号 hold_register 10030
35 REG_DATA_STACK_VISON_CODE STRING 物料堆叠复检图片编码 hold_register 12004
36 REG_DATA_GLOVE_BOX_PRESSURE FLOAT32 手套箱压力 hold_register 10050
37 REG_DATA_GLOVE_BOX_WATER_CONTENT FLOAT32 手套箱水含量 hold_register 10052
38 REG_DATA_GLOVE_BOX_O2_CONTENT FLOAT32 手套箱氧含量 hold_register 10054
39 UNILAB_SEND_ELECTROLYTE_BOTTLE_NUM BOOL Unilab确认已发送电解液瓶数信号 coil 8720
40 UNILAB_RECE_ELECTROLYTE_BOTTLE_NUM BOOL Unilab可接受电解液瓶数 coil 8520
41 REG_MSG_ELECTROLYTE_NUM_USED INT16 电解液组装电池平行样数 hold_register 496
42 REG_DATA_ELECTROLYTE_USE_NUM INT16 当前已组装平行样数 hold_register 10000
43 UNILAB_SEND_FINISHED_CMD BOOL Unilab发送收到完成信号 coil 8730
44 UNILAB_RECE_FINISHED_CMD BOOL 告知unilab结束信号 coil 8530

View File

@@ -1,135 +0,0 @@
import json
import re
from pymodbus.client import ModbusTcpClient
from unilabos.device_comms.modbus_plc.modbus import WorderOrder, Coil, DiscreteInputs, HoldRegister, InputRegister, DataType
from pymodbus.constants import Endian
import time
import threading
import csv
import os
from datetime import datetime
from typing import Callable
from unilabos.device_comms.modbus_plc.client import TCPClient, ModbusNode, PLCWorkflow, ModbusWorkflow, WorkflowAction, BaseClient
from unilabos.device_comms.modbus_plc.modbus import DeviceType, Base as ModbusNodeBase, DataType, WorderOrder
class Coin_Cell_Assembly:
if __name__ == '__main__':
coin_cell_assmbly = Coin_Cell_Assembly(address="192.168.1.20", port="502")
#params = {
# "elec_num": 32
#}
#str_data = json.dumps(params, ensure_ascii=False)
#print('param:', coin_cell_assmbly.func_pack_device_write_batch_elec_param(params))
#time.sleep(1)
print(coin_cell_assmbly.func_pack_device_write_per_elec_param(
elec_use_num=4,
elec_num=5,
elec_vol=55,
assembly_type=25,
assembly_pressure=550))
time.sleep(1)
'''
print('start:', coin_cell_assmbly.func_pack_device_start())
time.sleep(1)
print('start:', coin_cell_assmbly.func_pack_device_start())
time.sleep(1)
print('stop:', coin_cell_assmbly.func_pack_device_stop())
time.sleep(1)
while True:
# cmd coil
print('start cmd:', coin_cell_assmbly.sys_start_cmd(True))
time.sleep(1)
print('stop cmd:', coin_cell_assmbly.sys_stop_cmd(False))
time.sleep(1)
print('reset cmd:', coin_cell_assmbly.sys_reset_cmd(True))
time.sleep(1)
print('hand cmd:', coin_cell_assmbly.sys_hand_cmd(False))
time.sleep(1)
print('auto cmd:', coin_cell_assmbly.sys_auto_cmd(True))
time.sleep(1)
print('init cmd:', coin_cell_assmbly.sys_init_cmd(False))
time.sleep(1)
print('send msg succ cmd:', coin_cell_assmbly.unilab_send_msg_succ_cmd(False))
time.sleep(1)
print('rec msg succ cmd:', coin_cell_assmbly.unilab_rec_msg_succ_cmd(True))
time.sleep(1)
# cmd reg
print('elec use num msg:', coin_cell_assmbly.unilab_send_msg_electrolyte_use_num(8))
time.sleep(1)
print('elec num msg:', coin_cell_assmbly.unilab_send_msg_electrolyte_num(4))
time.sleep(1)
print('elec vol msg:', coin_cell_assmbly.unilab_send_msg_electrolyte_vol(3.3))
time.sleep(1)
print('assembly type msg:', coin_cell_assmbly.unilab_send_msg_assembly_type(1))
time.sleep(1)
print('assembly pressure msg:', coin_cell_assmbly.unilab_send_msg_assembly_pressure(1))
time.sleep(1)
# status coil
print('start status:',coin_cell_assmbly.sys_start_status)
time.sleep(1)
print('stop status:',coin_cell_assmbly.sys_stop_status)
time.sleep(1)
print('reset status:',coin_cell_assmbly.sys_reset_status)
time.sleep(1)
print('hand status:',coin_cell_assmbly.sys_hand_status)
time.sleep(1)
print('auto status:', coin_cell_assmbly.sys_auto_status)
time.sleep(1)
print('init ok:', coin_cell_assmbly.sys_init_status)
time.sleep(1)
print('request rec msg:', coin_cell_assmbly.request_rec_msg_status)
time.sleep(1)
print('request send msg:', coin_cell_assmbly.request_send_msg_status)
time.sleep(1)
# status reg
print('assembly coin cell num:', coin_cell_assmbly.data_assembly_coin_cell_num)
time.sleep(1)
print('assembly coin assembly per time:', coin_cell_assmbly.data_assembly_time)
time.sleep(1)
print('open circuit vol:', coin_cell_assmbly.data_open_circuit_voltage)
time.sleep(1)
print('axis x pos:', coin_cell_assmbly.data_axis_x_pos)
time.sleep(1)
print('axis y pos:', coin_cell_assmbly.data_axis_y_pos)
time.sleep(1)
print('axis z pos:', coin_cell_assmbly.data_axis_z_pos)
time.sleep(1)
print('pole weight:', coin_cell_assmbly.data_pole_weight)
time.sleep(1)
print('assembly pressure:', coin_cell_assmbly.data_assembly_coin_cell_num)
time.sleep(1)
print('assembly electrolyte vol:', coin_cell_assmbly.data_electrolyte_volume)
time.sleep(1)
print('assembly coin num:', coin_cell_assmbly.data_coin_num)
time.sleep(1)
print('coin cell code:', coin_cell_assmbly.data_coin_cell_code)
time.sleep(1)
print('elec code:', coin_cell_assmbly.data_electrolyte_code)
time.sleep(1)
print('glove box pressure:', coin_cell_assmbly.data_glove_box_pressure)
time.sleep(1)
print('glove box o2:', coin_cell_assmbly.data_glove_box_o2_content)
time.sleep(1)
print('glove box water:', coin_cell_assmbly.data_glove_box_water_content)
time.sleep(1)
'''

View File

@@ -1,750 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 22,
"id": "80bc9500",
"metadata": {},
"outputs": [],
"source": [
"from __future__ import annotations\n",
"\n",
"from collections import OrderedDict\n",
"from typing import Any, Dict, List, Optional, TypedDict, Union, cast\n",
"\n",
"from pylabrobot.resources.coordinate import Coordinate\n",
"from pylabrobot.resources.container import Container\n",
"from pylabrobot.resources.deck import Deck\n",
"from pylabrobot.resources.itemized_resource import ItemizedResource\n",
"from pylabrobot.resources.resource import Resource\n",
"from pylabrobot.resources.resource_stack import ResourceStack\n",
"from pylabrobot.resources.tip_rack import TipRack, TipSpot\n",
"from pylabrobot.resources.trash import Trash\n",
"from pylabrobot.resources.utils import create_ordered_items_2d"
]
},
{
"cell_type": "markdown",
"id": "498a9159",
"metadata": {},
"source": [
"物料类型构建"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "f4a27241",
"metadata": {},
"outputs": [],
"source": [
"\n",
"class ElectrodeSheetState(TypedDict):\n",
" diameter: float # 直径 (mm)\n",
" thickness: float # 厚度 (mm)\n",
" mass: float # 质量 (g)\n",
" material_type: str # 材料类型(正极、负极、隔膜、弹片、垫片、铝箔等)\n",
" info: Optional[str] # 附加信息\n",
"\n",
"class ElectrodeSheet(Resource):\n",
" \"\"\"极片类 - 包含正负极片、隔膜、弹片、垫片、铝箔等所有片状材料\"\"\"\n",
"\n",
" def __init__(\n",
" self,\n",
" name: str = \"极片\",\n",
" size_x=10,\n",
" size_y=10,\n",
" size_z=10,\n",
" category: str = \"electrode_sheet\",\n",
" model: Optional[str] = None,\n",
" ):\n",
" \"\"\"初始化极片\n",
"\n",
" Args:\n",
" name: 极片名称\n",
" category: 类别\n",
" model: 型号\n",
" \"\"\"\n",
" super().__init__(\n",
" name=name,\n",
" size_x=size_x,\n",
" size_y=size_y,\n",
" size_z=size_z,\n",
" category=category,\n",
" model=model,\n",
" )\n",
" self._unilabos_state: ElectrodeSheetState = ElectrodeSheetState(\n",
" diameter=14,\n",
" thickness=0.1,\n",
" mass=0.5,\n",
" material_type=\"copper\",\n",
" info=None\n",
" )\n",
"\n",
" # TODO: 这个还要不要给self._unilabos_state赋值的\n",
" def load_state(self, state: Dict[str, Any]) -> None:\n",
" \"\"\"格式不变\"\"\"\n",
" super().load_state(state)\n",
" self._unilabos_state = state\n",
" #序列化\n",
" def serialize_state(self) -> Dict[str, Dict[str, Any]]:\n",
" \"\"\"格式不变\"\"\"\n",
" data = super().serialize_state()\n",
" data.update(self._unilabos_state) # Container自身的信息云端物料将保存这一data本地也通过这里的data进行读写当前类用来表示这个物料的长宽高大小的属性而datastate用来表示物料的内容细节等\n",
" return data\n"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "830f052e",
"metadata": {},
"outputs": [],
"source": [
"# TODO: 这个应该只能放一个极片\n",
"class MaterialHoleState(TypedDict):\n",
" diameter: int\n",
" depth: int\n",
" max_sheets: int\n",
" info: Optional[str] # 附加信息\n",
"\n",
"class MaterialHole(Resource):\n",
" \"\"\"料板洞位类\"\"\"\n",
" children: List[ElectrodeSheet] = []\n",
"\n",
" def __init__(\n",
" self,\n",
" name: str,\n",
" size_x: float,\n",
" size_y: float,\n",
" size_z: float,\n",
" category: str = \"material_hole\",\n",
" **kwargs\n",
" ):\n",
" super().__init__(\n",
" name=name,\n",
" size_x=size_x,\n",
" size_y=size_y,\n",
" size_z=size_z,\n",
" category=category,\n",
" )\n",
" self._unilabos_state: MaterialHoleState = MaterialHoleState(\n",
" diameter=20,\n",
" depth=10,\n",
" max_sheets=1,\n",
" info=None\n",
" )\n",
"\n",
" def get_all_sheet_info(self):\n",
" info_list = []\n",
" for sheet in self.children:\n",
" info_list.append(sheet._unilabos_state[\"info\"])\n",
" return info_list\n",
" \n",
" #这个函数函数好像没用,一般不会集中赋值质量\n",
" def set_all_sheet_mass(self):\n",
" for sheet in self.children:\n",
" sheet._unilabos_state[\"mass\"] = 0.5 # 示例设置质量为0.5g\n",
"\n",
" def load_state(self, state: Dict[str, Any]) -> None:\n",
" \"\"\"格式不变\"\"\"\n",
" super().load_state(state)\n",
" self._unilabos_state = state\n",
"\n",
" def serialize_state(self) -> Dict[str, Dict[str, Any]]:\n",
" \"\"\"格式不变\"\"\"\n",
" data = super().serialize_state()\n",
" data.update(self._unilabos_state) # Container自身的信息云端物料将保存这一data本地也通过这里的data进行读写当前类用来表示这个物料的长宽高大小的属性而datastate用来表示物料的内容细节等\n",
" return data\n",
" #移动极片前先取出对象\n",
" def get_sheet_with_name(self, name: str) -> Optional[ElectrodeSheet]:\n",
" for sheet in self.children:\n",
" if sheet.name == name:\n",
" return sheet\n",
" return None\n",
"\n",
" def has_electrode_sheet(self) -> bool:\n",
" \"\"\"检查洞位是否有极片\"\"\"\n",
" return len(self.children) > 0\n",
"\n",
" def assign_child_resource(\n",
" self,\n",
" resource: ElectrodeSheet,\n",
" location: Optional[Coordinate],\n",
" reassign: bool = True,\n",
" ):\n",
" \"\"\"放置极片\"\"\"\n",
" # TODO: 这里要改diameter找不到加入._unilabos_state后应该没问题\n",
" if resource._unilabos_state[\"diameter\"] > self._unilabos_state[\"diameter\"]:\n",
" raise ValueError(f\"极片直径 {resource._unilabos_state['diameter']} 超过洞位直径 {self._unilabos_state['diameter']}\")\n",
" if len(self.children) >= self._unilabos_state[\"max_sheets\"]:\n",
" raise ValueError(f\"洞位已满,无法放置更多极片\")\n",
" super().assign_child_resource(resource, location, reassign)\n",
"\n",
" # 根据children的编号取物料对象。\n",
" def get_electrode_sheet_info(self, index: int) -> ElectrodeSheet:\n",
" return self.children[index]\n",
"\n",
"\n",
"#料板\n",
"class MaterialPlateState(TypedDict):\n",
" hole_spacing_x: float\n",
" hole_spacing_y: float\n",
" hole_diameter: float\n",
" info: Optional[str] # 附加信息\n",
"\n",
"class MaterialPlate(ItemizedResource[MaterialHole]):\n",
" \"\"\"料板类 - 4x4个洞位每个洞位放1个极片\"\"\"\n",
" \n",
" children: List[MaterialHole]\n",
"\n",
" def __init__(\n",
" self,\n",
" name: str,\n",
" size_x: float,\n",
" size_y: float,\n",
" size_z: float,\n",
" ordered_items: Optional[Dict[str, MaterialHole]] = None,\n",
" ordering: Optional[OrderedDict[str, str]] = None,\n",
" category: str = \"material_plate\",\n",
" model: Optional[str] = None,\n",
" fill: bool = False\n",
" ):\n",
" \"\"\"初始化料板\n",
"\n",
" Args:\n",
" name: 料板名称\n",
" size_x: 长度 (mm)\n",
" size_y: 宽度 (mm)\n",
" size_z: 高度 (mm)\n",
" hole_diameter: 洞直径 (mm)\n",
" hole_depth: 洞深度 (mm)\n",
" hole_spacing_x: X方向洞位间距 (mm)\n",
" hole_spacing_y: Y方向洞位间距 (mm)\n",
" number: 编号\n",
" category: 类别\n",
" model: 型号\n",
" \"\"\"\n",
" self._unilabos_state: MaterialPlateState = MaterialPlateState(\n",
" hole_spacing_x=24.0,\n",
" hole_spacing_y=24.0,\n",
" hole_diameter=20.0,\n",
" info=\"\",\n",
" )\n",
" # 创建4x4的洞位\n",
" # TODO: 这里要改,对应不同形状\n",
" holes = create_ordered_items_2d(\n",
" klass=MaterialHole,\n",
" num_items_x=4,\n",
" num_items_y=4,\n",
" dx=(size_x - 4 * self._unilabos_state[\"hole_spacing_x\"]) / 2, # 居中\n",
" dy=(size_y - 4 * self._unilabos_state[\"hole_spacing_y\"]) / 2, # 居中\n",
" dz=size_z,\n",
" item_dx=self._unilabos_state[\"hole_spacing_x\"],\n",
" item_dy=self._unilabos_state[\"hole_spacing_y\"],\n",
" size_x = 16,\n",
" size_y = 16,\n",
" size_z = 16,\n",
" )\n",
" if fill:\n",
" super().__init__(\n",
" name=name,\n",
" size_x=size_x,\n",
" size_y=size_y,\n",
" size_z=size_z,\n",
" ordered_items=holes,\n",
" category=category,\n",
" model=model,\n",
" )\n",
" else:\n",
" super().__init__(\n",
" name=name,\n",
" size_x=size_x,\n",
" size_y=size_y,\n",
" size_z=size_z,\n",
" ordered_items=ordered_items,\n",
" ordering=ordering,\n",
" category=category,\n",
" model=model,\n",
" )\n",
"\n",
" def update_locations(self):\n",
" # TODO:调多次相加\n",
" holes = create_ordered_items_2d(\n",
" klass=MaterialHole,\n",
" num_items_x=4,\n",
" num_items_y=4,\n",
" dx=(self._size_x - 3 * self._unilabos_state[\"hole_spacing_x\"]) / 2, # 居中\n",
" dy=(self._size_y - 3 * self._unilabos_state[\"hole_spacing_y\"]) / 2, # 居中\n",
" dz=self._size_z,\n",
" item_dx=self._unilabos_state[\"hole_spacing_x\"],\n",
" item_dy=self._unilabos_state[\"hole_spacing_y\"],\n",
" size_x = 1,\n",
" size_y = 1,\n",
" size_z = 1,\n",
" )\n",
" for item, original_item in zip(holes.items(), self.children):\n",
" original_item.location = item[1].location"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "8318ccca",
"metadata": {},
"outputs": [],
"source": [
"class CoincellDeck(Deck):\n",
" \"\"\"纽扣电池组装工作站台面类\"\"\"\n",
"\n",
" def __init__(\n",
" self,\n",
" name: str = \"coin_cell_deck\",\n",
" size_x: float = 1620.0, # 3.66m\n",
" size_y: float = 1270.0, # 1.23m\n",
" size_z: float = 500.0,\n",
" origin: Coordinate = Coordinate(0, 0, 0),\n",
" category: str = \"coin_cell_deck\",\n",
" ):\n",
" \"\"\"初始化纽扣电池组装工作站台面\n",
"\n",
" Args:\n",
" name: 台面名称\n",
" size_x: 长度 (mm) - 3.66m\n",
" size_y: 宽度 (mm) - 1.23m\n",
" size_z: 高度 (mm)\n",
" origin: 原点坐标\n",
" category: 类别\n",
" \"\"\"\n",
" super().__init__(\n",
" name=name,\n",
" size_x=size_x,\n",
" size_y=size_y,\n",
" size_z=size_z,\n",
" origin=origin,\n",
" category=category,\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "c73bae21",
"metadata": {},
"outputs": [],
"source": [
"import json"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "3369a1dd",
"metadata": {},
"outputs": [],
"source": [
"def upload_resources_to_unilab(wuliao: List[Resource]):\n",
" from unilabos.resources.graphio import convert_resources_from_type\n",
" from unilabos.config.config import BasicConfig \n",
" BasicConfig.ak = \"beb0c15f-2279-46a1-aba5-00eaf89aef55\"\n",
" BasicConfig.sk = \"15d4f25e-3512-4f9c-9bfb-43ab85e7b561\"\n",
" from unilabos.app.web.client import http_client\n",
" resources = convert_resources_from_type(wuliao, [Resource])\n",
" json.dump({\"nodes\": resources, \"links\": []}, open(\"button_battery_station_resources_unilab.json\", \"w\"), indent=2)\n",
" \n",
" #print(resources)\n",
" http_client.remote_addr = \"https://uni-lab.test.bohrium.com/api/v1\"\n",
" \n",
" http_client.resource_add(resources)"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "1543ddab",
"metadata": {},
"outputs": [],
"source": [
"liaopan1 = MaterialPlate(name=\"liaopan1\", size_x=120.8, size_y=120.5, size_z=10.0, fill=True)"
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "b732754a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"MaterialPlate(name=liaopan1, size_x=120.8, size_y=120.5, size_z=10.0, location=None)\n"
]
}
],
"source": [
"print(liaopan1)"
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "7e6e7252",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[MaterialHole(name=liaopan1_materialhole_0_0, location=Coordinate(012.400, 084.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_0_1, location=Coordinate(012.400, 060.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_0_2, location=Coordinate(012.400, 036.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_0_3, location=Coordinate(012.400, 012.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_1_0, location=Coordinate(036.400, 084.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_1_1, location=Coordinate(036.400, 060.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_1_2, location=Coordinate(036.400, 036.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_1_3, location=Coordinate(036.400, 012.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_2_0, location=Coordinate(060.400, 084.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_2_1, location=Coordinate(060.400, 060.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_2_2, location=Coordinate(060.400, 036.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_2_3, location=Coordinate(060.400, 012.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_3_0, location=Coordinate(084.400, 084.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_3_1, location=Coordinate(084.400, 060.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_3_2, location=Coordinate(084.400, 036.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole), MaterialHole(name=liaopan1_materialhole_3_3, location=Coordinate(084.400, 012.250, 010.000), size_x=16, size_y=16, size_z=16, category=material_hole)]\n"
]
}
],
"source": [
"print(liaopan1.children)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "836ff68d",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[37m25-09-22 [15:15:08,950]\u001b[0m \u001b[1;36m[DEBUG]\u001b[0m \u001b[37mStarting new HTTPS connection (1): uni-lab.test.bohrium.com:443\u001b[37m [_new_conn:1049] [urllib3.connectionpool.connectionpool]\u001b[0m\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"CoincellDeck(name=coin_cell_deck, location=Coordinate(000.000, 000.000, 000.000), size_x=1620.0, size_y=1270.0, size_z=500.0, category=coin_cell_deck)\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_plate\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_plate\n",
"转换pylabrobot的时候出现未知类型 coin_cell_deck\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[37m25-09-22 [15:15:09,218]\u001b[0m \u001b[1;36m[DEBUG]\u001b[0m \u001b[37mhttps://uni-lab.test.bohrium.com:443 \"POST /api/v1/lab/material HTTP/1.1\" 200 10\u001b[37m [_make_request:544] [urllib3.connectionpool.connectionpool]\u001b[0m\n"
]
}
],
"source": [
"deck = CoincellDeck()\n",
"#创建一个4*4的物料板\n",
"liaopan1 = MaterialPlate(name=\"liaopan1\", size_x=120.8, size_y=120.5, size_z=10.0, fill=True)\n",
"#把物料板放到桌子上\n",
"deck.assign_child_resource(liaopan1, Coordinate(x=0, y=0, z=0))\n",
"#创建一个极片\n",
"for i in range(16):\n",
" jipian = ElectrodeSheet(name=f\"jipian_{i}\", size_x= 12, size_y=12, size_z=0.1)\n",
" liaopan1.children[i].assign_child_resource(jipian, location=None)\n",
"#创建一个4*4的物料板\n",
"liaopan2 = MaterialPlate(name=\"liaopan2\", size_x=120.8, size_y=120.5, size_z=10.0, fill=True)\n",
"#把物料板放到桌子上\n",
"deck.assign_child_resource(liaopan2, Coordinate(x=500, y=0, z=0))\n",
"#liaopan.children[3].assign_child_resource(jipian, location=None)\n",
"print(deck)\n",
"\n",
"upload_resources_to_unilab([deck])"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "00aab9cf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"MaterialPlate(name=liaopan1, size_x=120.8, size_y=120.5, size_z=10.0, location=Coordinate(000.000, 000.000, 000.000))\n"
]
}
],
"source": [
"liaopan1 = deck.get_resource(\"liaopan1\")\n",
"print(liaopan1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7409969c",
"metadata": {},
"outputs": [],
"source": [
"liaopan1 = deck.get_resource(\"liaopan1\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "096dde04",
"metadata": {},
"outputs": [],
"source": [
"print()"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "5528df96",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[37m25-09-22 [15:17:44,322]\u001b[0m \u001b[1;36m[DEBUG]\u001b[0m \u001b[37mStarting new HTTPS connection (1): uni-lab.test.bohrium.com:443\u001b[37m [_new_conn:1049] [urllib3.connectionpool.connectionpool]\u001b[0m\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"ElectrodeSheet(name=jipian_1, location=None, size_x=12, size_y=12, size_z=0.1, category=electrode_sheet)\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_plate\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_plate\n",
"转换pylabrobot的时候出现未知类型 coin_cell_deck\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[37m25-09-22 [15:17:44,599]\u001b[0m \u001b[1;36m[DEBUG]\u001b[0m \u001b[37mhttps://uni-lab.test.bohrium.com:443 \"POST /api/v1/lab/material HTTP/1.1\" 200 10\u001b[37m [_make_request:544] [urllib3.connectionpool.connectionpool]\u001b[0m\n"
]
}
],
"source": [
"#在台面上找到料盘和极片\n",
"liaopan1 = deck.get_resource(\"liaopan1\")\n",
"liaopan2 = deck.get_resource(\"liaopan2\")\n",
"jipian1 = liaopan1.children[1].children[0]\n",
"#\n",
"print(jipian1)\n",
"#把物料解绑后放到另一盘上\n",
"jipian1.parent.unassign_child_resource(jipian1)\n",
"liaopan2.children[1].assign_child_resource(jipian1, location=None)\n",
"#print(jipian2.parent)\n",
"upload_resources_to_unilab([deck])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "43736700",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[37m25-09-22 [14:31:50,027]\u001b[0m \u001b[1;36m[DEBUG]\u001b[0m \u001b[37mStarting new HTTPS connection (1): uni-lab.test.bohrium.com:443\u001b[37m [_new_conn:1049] [urllib3.connectionpool.connectionpool]\u001b[0m\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_plate\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 electrode_sheet\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_hole\n",
"转换pylabrobot的时候出现未知类型 material_plate\n",
"转换pylabrobot的时候出现未知类型 coin_cell_deck\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[37m25-09-22 [14:31:50,358]\u001b[0m \u001b[1;36m[DEBUG]\u001b[0m \u001b[37mhttps://uni-lab.test.bohrium.com:443 \"POST /api/v1/lab/material HTTP/1.1\" 200 10\u001b[37m [_make_request:544] [urllib3.connectionpool.connectionpool]\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"<Response [200]>"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "unilab",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -0,0 +1,489 @@
"""
工作站基类
Workstation Base Class - 简化版
基于PLR Deck的简化工作站架构
专注于核心物料系统和工作流管理
"""
import collections
import time
from typing import Dict, Any, List, Optional, Union
from abc import ABC, abstractmethod
from dataclasses import dataclass
from enum import Enum
from pylabrobot.resources import Deck, Plate, Resource as PLRResource
from pylabrobot.resources.coordinate import Coordinate
from unilabos.ros.nodes.presets.workstation import ROS2WorkstationNode
from unilabos.utils.log import logger
class WorkflowStatus(Enum):
"""工作流状态"""
IDLE = "idle"
INITIALIZING = "initializing"
RUNNING = "running"
PAUSED = "paused"
STOPPING = "stopping"
STOPPED = "stopped"
ERROR = "error"
COMPLETED = "completed"
@dataclass
class WorkflowInfo:
"""工作流信息"""
name: str
description: str
estimated_duration: float # 预估持续时间(秒)
required_materials: List[str] # 所需物料类型
output_product: str # 输出产品类型
parameters_schema: Dict[str, Any] # 参数架构
class WorkStationContainer(Plate):
"""
WorkStation 专用 Container 类,继承自 Plate和TipRack
注意这个物料必须通过plr_additional_res_reg.py注册到edge才能正常序列化
"""
def __init__(
self,
name: str,
size_x: float,
size_y: float,
size_z: float,
category: str,
ordering: collections.OrderedDict,
model: Optional[str] = None,
):
"""
这里的初始化入参要和plr的保持一致
"""
super().__init__(name, size_x, size_y, size_z, category=category, ordering=ordering, model=model)
self._unilabos_state = {} # 必须有此行,自己的类描述的是物料的
def load_state(self, state: Dict[str, Any]) -> None:
"""从给定的状态加载工作台信息。"""
super().load_state(state)
self._unilabos_state = state
def serialize_state(self) -> Dict[str, Dict[str, Any]]:
data = super().serialize_state()
data.update(
self._unilabos_state
) # Container自身的信息云端物料将保存这一data本地也通过这里的data进行读写当前类用来表示这个物料的长宽高大小的属性而datastate用来表示物料的内容细节等
return data
def get_workstation_plate_resource(name: str) -> PLRResource: # 要给定一个返回plr的方法
"""
用于获取一些模板,例如返回一个带有特定信息/子物料的 Plate这里需要到注册表注册例如unilabos/registry/resources/organic/workstation.yaml
可以直接运行该函数或者利用注册表补全机制,来检查是否资源出错
:param name: 资源名称
:return: Resource对象
"""
plate = WorkStationContainer(
name, size_x=50, size_y=50, size_z=10, category="plate", ordering=collections.OrderedDict()
)
tip_rack = WorkStationContainer(
"tip_rack_inside_plate",
size_x=50,
size_y=50,
size_z=10,
category="tip_rack",
ordering=collections.OrderedDict(),
)
plate.assign_child_resource(tip_rack, Coordinate.zero())
return plate
class ResourceSynchronizer(ABC):
"""资源同步器基类
负责与外部物料系统的同步,并对 self.deck 做修改
"""
def __init__(self, workstation: "WorkstationBase"):
self.workstation = workstation
@abstractmethod
async def sync_from_external(self) -> bool:
"""从外部系统同步物料到本地deck"""
pass
@abstractmethod
async def sync_to_external(self, plr_resource: PLRResource) -> bool:
"""将本地物料同步到外部系统"""
pass
@abstractmethod
async def handle_external_change(self, change_info: Dict[str, Any]) -> bool:
"""处理外部系统的变更通知"""
pass
class WorkstationBase(ABC):
"""工作站基类 - 简化版
核心功能:
1. 基于 PLR Deck 的物料系统,支持格式转换
2. 可选的资源同步器支持外部物料系统
3. 简化的工作流管理
"""
_ros_node: ROS2WorkstationNode
@property
def _children(self) -> Dict[str, Any]: # 不要删除这个下划线,不然会自动导入注册表,后面改成装饰器识别
return self._ros_node.children
async def update_resource_example(self):
return await self._ros_node.update_resource([get_workstation_plate_resource("test")])
def __init__(
self,
station_resource: PLRResource,
*args,
**kwargs, # 必须有kwargs
):
# 基本配置
print(station_resource)
self.deck_config = station_resource
# PLR 物料系统
self.deck: Optional[Deck] = None
self.plr_resources: Dict[str, PLRResource] = {}
# 资源同步器(可选)
# self.resource_synchronizer = ResourceSynchronizer(self) # 要在driver中自行初始化只有workstation用
# 硬件接口
self.hardware_interface: Union[Any, str] = None
# 工作流状态
self.current_workflow_status = WorkflowStatus.IDLE
self.current_workflow_info = None
self.workflow_start_time = None
self.workflow_parameters = {}
# 支持的工作流(静态预定义)
self.supported_workflows: Dict[str, WorkflowInfo] = {}
# 初始化物料系统
self._initialize_material_system()
# 注册支持的工作流
# self._register_supported_workflows()
# logger.info(f"工作站 {device_id} 初始化完成(简化版)")
def _initialize_material_system(self):
"""初始化物料系统 - 使用 graphio 转换"""
try:
from unilabos.resources.graphio import resource_ulab_to_plr
# # 1. 合并 deck_config 和 children 创建完整的资源树
# complete_resource_config = self._create_complete_resource_config()
# # 2. 使用 graphio 转换为 PLR 资源
# self.deck = resource_ulab_to_plr(complete_resource_config, plr_model=True)
# # 3. 建立资源映射
# self._build_resource_mappings(self.deck)
# # 4. 如果有资源同步器,执行初始同步
# if self.resource_synchronizer:
# # 这里可以异步执行,暂时跳过
# pass
# logger.info(f"工作站 {self.device_id} 物料系统初始化成功,创建了 {len(self.plr_resources)} 个资源")
pass
except Exception as e:
# logger.error(f"工作站 {self.device_id} 物料系统初始化失败: {e}")
raise
def _create_complete_resource_config(self) -> Dict[str, Any]:
"""创建完整的资源配置 - 合并 deck_config 和 children"""
# 创建主 deck 配置
deck_resource = {
"id": f"{self.device_id}_deck",
"name": f"{self.device_id}_deck",
"type": "deck",
"position": {"x": 0, "y": 0, "z": 0},
"config": {
"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", 100.0),
**{k: v for k, v in self.deck_config.items() if k not in ["size_x", "size_y", "size_z"]},
},
"data": {},
"children": [],
"parent": None,
}
# 添加子资源
if self._children:
children_list = []
for child_id, child_config in self._children.items():
child_resource = self._normalize_child_resource(child_id, child_config, deck_resource["id"])
children_list.append(child_resource)
deck_resource["children"] = children_list
return deck_resource
def _normalize_child_resource(self, resource_id: str, config: Dict[str, Any], parent_id: str) -> Dict[str, Any]:
"""标准化子资源配置"""
return {
"id": resource_id,
"name": config.get("name", resource_id),
"type": config.get("type", "container"),
"position": self._normalize_position(config.get("position", {})),
"config": config.get("config", {}),
"data": config.get("data", {}),
"children": [], # 简化版本:只支持一层子资源
"parent": parent_id,
}
def _normalize_position(self, position: Any) -> Dict[str, float]:
"""标准化位置信息"""
if isinstance(position, dict):
return {
"x": float(position.get("x", 0)),
"y": float(position.get("y", 0)),
"z": float(position.get("z", 0)),
}
elif isinstance(position, (list, tuple)) and len(position) >= 2:
return {
"x": float(position[0]),
"y": float(position[1]),
"z": float(position[2]) if len(position) > 2 else 0.0,
}
else:
return {"x": 0.0, "y": 0.0, "z": 0.0}
def _build_resource_mappings(self, deck: Deck):
"""递归构建资源映射"""
def add_resource_recursive(resource: PLRResource):
if hasattr(resource, "name"):
self.plr_resources[resource.name] = resource
if hasattr(resource, "children"):
for child in resource.children:
add_resource_recursive(child)
add_resource_recursive(deck)
# ============ 硬件接口管理 ============
def set_hardware_interface(self, hardware_interface: Union[Any, str]):
"""设置硬件接口"""
self.hardware_interface = hardware_interface
logger.info(f"工作站 {self.device_id} 硬件接口设置: {type(hardware_interface).__name__}")
def set_workstation_node(self, workstation_node: "ROS2WorkstationNode"):
"""设置协议节点引用(用于代理模式)"""
self._ros_node = workstation_node
logger.info(f"工作站 {self.device_id} 关联协议节点")
# ============ 设备操作接口 ============
def call_device_method(self, method: str, *args, **kwargs) -> Any:
"""调用设备方法的统一接口"""
# 1. 代理模式:通过协议节点转发
if isinstance(self.hardware_interface, str) and self.hardware_interface.startswith("proxy:"):
if not self._ros_node:
raise RuntimeError("代理模式需要设置workstation_node")
device_id = self.hardware_interface[6:] # 移除 "proxy:" 前缀
return self._ros_node.call_device_method(device_id, method, *args, **kwargs)
# 2. 直接模式:直接调用硬件接口方法
elif self.hardware_interface and hasattr(self.hardware_interface, method):
return getattr(self.hardware_interface, method)(*args, **kwargs)
else:
raise AttributeError(f"硬件接口不支持方法: {method}")
def get_device_status(self) -> Dict[str, Any]:
"""获取设备状态"""
try:
return self.call_device_method("get_status")
except AttributeError:
# 如果设备不支持get_status方法返回基础状态
return {
"status": "unknown",
"interface_type": type(self.hardware_interface).__name__,
"timestamp": time.time(),
}
def is_device_available(self) -> bool:
"""检查设备是否可用"""
try:
self.get_device_status()
return True
except:
return False
# ============ 物料系统接口 ============
def get_deck(self) -> Deck:
"""获取主 Deck"""
return self.deck
def get_all_resources(self) -> Dict[str, PLRResource]:
"""获取所有 PLR 资源"""
return self.plr_resources.copy()
def find_resource_by_name(self, name: str) -> Optional[PLRResource]:
"""按名称查找资源"""
return self.plr_resources.get(name)
def find_resources_by_type(self, resource_type: type) -> List[PLRResource]:
"""按类型查找资源"""
return [res for res in self.plr_resources.values() if isinstance(res, resource_type)]
async def sync_with_external_system(self) -> bool:
"""与外部物料系统同步"""
if not self.resource_synchronizer:
logger.info(f"工作站 {self.device_id} 没有配置资源同步器")
return True
try:
success = await self.resource_synchronizer.sync_from_external()
if success:
logger.info(f"工作站 {self.device_id} 外部同步成功")
else:
logger.warning(f"工作站 {self.device_id} 外部同步失败")
return success
except Exception as e:
logger.error(f"工作站 {self.device_id} 外部同步异常: {e}")
return False
# ============ 简化的工作流控制 ============
def execute_workflow(self, workflow_name: str, parameters: Dict[str, Any]) -> bool:
"""执行工作流"""
try:
# 设置工作流状态
self.current_workflow_status = WorkflowStatus.INITIALIZING
self.workflow_parameters = parameters
self.workflow_start_time = time.time()
# 委托给子类实现
success = self._execute_workflow_impl(workflow_name, parameters)
if success:
self.current_workflow_status = WorkflowStatus.RUNNING
logger.info(f"工作站 {self.device_id} 工作流 {workflow_name} 启动成功")
else:
self.current_workflow_status = WorkflowStatus.ERROR
logger.error(f"工作站 {self.device_id} 工作流 {workflow_name} 启动失败")
return success
except Exception as e:
self.current_workflow_status = WorkflowStatus.ERROR
logger.error(f"工作站 {self.device_id} 执行工作流失败: {e}")
return False
def stop_workflow(self, emergency: bool = False) -> bool:
"""停止工作流"""
try:
if self.current_workflow_status in [WorkflowStatus.IDLE, WorkflowStatus.STOPPED]:
logger.warning(f"工作站 {self.device_id} 没有正在运行的工作流")
return True
self.current_workflow_status = WorkflowStatus.STOPPING
# 委托给子类实现
success = self._stop_workflow_impl(emergency)
if success:
self.current_workflow_status = WorkflowStatus.STOPPED
logger.info(f"工作站 {self.device_id} 工作流停止成功 (紧急: {emergency})")
else:
self.current_workflow_status = WorkflowStatus.ERROR
logger.error(f"工作站 {self.device_id} 工作流停止失败")
return success
except Exception as e:
self.current_workflow_status = WorkflowStatus.ERROR
logger.error(f"工作站 {self.device_id} 停止工作流失败: {e}")
return False
# ============ 状态属性 ============
@property
def workflow_status(self) -> WorkflowStatus:
"""获取当前工作流状态"""
return self.current_workflow_status
@property
def is_busy(self) -> bool:
"""检查工作站是否忙碌"""
return self.current_workflow_status in [
WorkflowStatus.INITIALIZING,
WorkflowStatus.RUNNING,
WorkflowStatus.STOPPING,
]
@property
def workflow_runtime(self) -> float:
"""获取工作流运行时间(秒)"""
if self.workflow_start_time is None:
return 0.0
return time.time() - self.workflow_start_time
# ============ 抽象方法 - 子类必须实现 ============
# @abstractmethod
# def _register_supported_workflows(self):
# """注册支持的工作流 - 子类必须实现"""
# pass
# @abstractmethod
# def _execute_workflow_impl(self, workflow_name: str, parameters: Dict[str, Any]) -> bool:
# """执行工作流的具体实现 - 子类必须实现"""
# pass
# @abstractmethod
# def _stop_workflow_impl(self, emergency: bool = False) -> bool:
# """停止工作流的具体实现 - 子类必须实现"""
# pass
class WorkstationExample(WorkstationBase):
"""工作站示例实现"""
def _register_supported_workflows(self):
"""注册支持的工作流"""
self.supported_workflows["example_workflow"] = WorkflowInfo(
name="example_workflow",
description="这是一个示例工作流",
estimated_duration=300.0,
required_materials=["sample_plate"],
output_product="processed_plate",
parameters_schema={"param1": "string", "param2": "integer"},
)
def _execute_workflow_impl(self, workflow_name: str, parameters: Dict[str, Any]) -> bool:
"""执行工作流的具体实现"""
if workflow_name not in self.supported_workflows:
logger.error(f"工作站 {self.device_id} 不支持工作流: {workflow_name}")
return False
# 这里添加实际的工作流逻辑
logger.info(f"工作站 {self.device_id} 正在执行工作流: {workflow_name} with parameters {parameters}")
return True
def _stop_workflow_impl(self, emergency: bool = False) -> bool:
"""停止工作流的具体实现"""
# 这里添加实际的停止逻辑
logger.info(f"工作站 {self.device_id} 正在停止工作流 (紧急: {emergency})")
return True

File diff suppressed because it is too large Load Diff