diff --git a/__pycache__/config.cpython-312.pyc b/__pycache__/config.cpython-312.pyc index 9511b07143d3f4cfb217ab97f0aeeb0fa0111a0a..add8b197de9d7d6101499cb954538af000e23f8b 100644 GIT binary patch delta 1110 zcmZuvS5uQw6y(#)Akh#&#HdJ76al*^3bq(P5D<)rx`?rCM6iKau>`Sq@v{r|-W7ZA zy*>Eg_~cLU+3~?8<2XK;naw%(p8d}5J@+1SeQ^c9v)QZx`q_8xDUT|t3w9Vk>f)1q zfe2y?SQ&(tw4xPT!p2qzrVVxmBZPK@G7w=5L2K2*g*M6~7>c$GgM+Qnj^Sv}Hs~N; zBqPv~Z4pHWqJ#;Q?k8iptmIYFb;iH>&GrgW>@rAZ2;quqWVB~!yv^}CLoQ87%U4zv>w_l zz&ngd-c&l+oreCK;OkKublzy1i;N8a55-{5e;Cfc41+S`Z(^|bKa3IV0~h-uU6wQ0 z51CBHNcKk-2OwJ*#T4YoYOXBjG0=z6I!C_91ssSm90WI0F_vj4014i?z2z>!pg-%)v6n<;=wj#g(#`=eOtM zXw)ztt5|?qRaSEh*3gZ$9E)`<#CndyhNkmx)ctM}VKa-ch2ybR_q$E&?ZOVVo8WI( z$BEcUz*M_kGO=4H+M~Fa#n>n2e&K-Fll<(160etFgV={8c39SrumnfNI>yO3P7h9S z3Qp2z;FQ{&R^g0rmQ!&~@x1mfXkZsP4VUzQF3Z#vPRCW@nr75U;=1N@L)@F<-l7+` z#lNHcuJ<-)_-)+t-obsA;(=HXb(7a^HY5Zxq(A@ZJo^DYb zZF4#EGTcs2ktZ`ZyWpGs&oaxCm+f}vyBm$5Ut!izz5S-=U)5j+MkZUohJ@GHzJ^8A k*c;O#Pc%2;%xDKnDH+L$dyylIc!Zn5i|-?8IXrvLx| delta 1009 zcmX|AS5uQw6wIe_Mj`>k0w`)w5Qqh(+XXCiL=klXMcsf@DPqAAdsoV**s%9rqGInI z%Zq=((f{C!J9#jZopbIvo4b4Nnfy#Um*&@Px7#fG{K)L6{8iNE7i|1#i;Q>oh7WyU zqYZu72fp-$op$)q5B~H=00Yohy+EO#^8W0L0Sv@I_CpZ+BbWmaBHkbl#9#&?l))Gx z3>Ahk1P+&#gPNs^Fb>9WhGK*&L%fx6WkV~yX#|I1Bprxk7@{~F(UNm=1V-uV(UKiQ z17jr-!*GmKZ#*Lq%aMpvFP@P|P(P7TNK#B@G$zoAiOMI*#^fFr*A$L&C7ansh|kpj zr&^t+{XexDA@1oMj}*otRjO%>!wkk_CKE7=iI^>u)1-v59$ba}GAEwT1cE%DLFadDzYZ?BIOtRDG8=v|Dix z3$d3AuumJ>FPQ_X9n`c7y|=Y+5n2hf>9%%tO$~HNjKeHKhvE_8sMy7BFa4Ork4x}` z=$#TfDetFPg43d%;bNTS5}acx&TG9FRJ$l#5-xKot|(rW#5KLwbuPmVt^cM>-QsfG z7VhYc?vl8t_wk5(U)%?D;i33lbO+#(>mkd$HXggW@Py@fD#|nM`8ikMh2l$Au##1* zW({lUi~WXmc*}aclfZl7gG_vs;3uxaXPNjSv2G3cRkwXxS03He z1pPm3zddHSwcYHpW*G&Z9=&e#G`^d+dlz|}K7Rvk{)WY(ucgs6V?yISHK7-J8WCoo YBgu#|GaVI%)4cE4uRJBJ#cCJvAJ_sw;s5{u diff --git a/__pycache__/hardware.cpython-312.pyc b/__pycache__/hardware.cpython-312.pyc index 53ebcd2fee7bad7f22713b74ebd83dffe1e0baf5..c2ade48c6faf45a95f4676a3e553018b70b863e4 100644 GIT binary patch delta 1624 zcmbVM%WD%s7@yhACcB$#-rGlP8*Pgk5uX)Xlv)oOB+`S5;xoo>t!_$`>C{@8H445E zk>Us{D(Xq0C`$1l9@K-V^ipUK5-8}=zd;Xv+ji2R*4G@q`R1G7eBbYTFxNMo-)xK; zhK^w6&fKuKJTsO@CCSU%qlqmTX~;s3Of~n~U33cQYL>@RhGkbnh_o}TvQR%h ziAf!lHuO`8z>U2GvYwYrAml{nM)M11su*Ko;$tyrX%M^{PO#u*Q8i z>e7*~i3r}fV!UD1Q2Jx*hFAU<{@3Y=)~z>t?&WXgAEhQ5TE@2Rgu9OPJO3O1`}9P| zjyv>z`eEil=BYm3ylx`7er!*6WJw*x)mJl~Ocfff(lYJxXwuBI$)jybrhVjj{b~uH f9{G}7hW+l;kh88h#~T++;!D>Wx8W;%d*jCM8A%qz delta 1471 zcma)6OHUI~6ux)b=}aHfX{V2Y7Fz^^Vnpy2b)kugLIlG?V-#QYF%>LW^)iT$;3>ytQS1w!_NQ_1o+Qj$=T$;G`jP%;70hz_QbI$qZJLfz1w0C+R?K2h( zBSi2yyy0=F>xI#6DUVdK+sd?D^mE@umHR0P5{GcrH9VO2xKS}?HE)S8dX3hNO0Q(e zxB3ZG^dyo>DJ|Yw*^?@g1{z5v&R1`Qz0GT`wg}r?vM$3jj|S;PP|d2c%JIaCYQ;7 zPjyyOU@;9+cn@KukMLMI07>)=^gIz11;rd=6eX~=E50MP#2sl;3MJ*!$Q!BrBHjij zgnvy!g;0d>5SBHuSZaxd2r&h;GW}~Yb}Uh}VSUOSe@Up+Z-hWYcPra7h(U04J5DC; zc1t1$=QTqd6XIxNV9k)Hfx2pl@u0g&VoRIF6FbpvG~}aTT*u!!PTj1%ncf14ceY&_ zm?Bf8ow!@&_iG5t^R%M_DI{gAp_4eIvAR-cAM*Z7(l^pmwR4hAl54&pGD$nFL0m#q zvJXwCuWAk#-NM<4@xs+hWA2&ZVl{kWd{yDx$Qd?#p*&o*YT<%=sc^Z-&K1k9C^q$( z{__)KV^v+^#6r`E#*TWtL!zhoh4|Kd%(hv^3-o&Ch-Yf~LmA#x)oN_4fSIaRE5lBE zxKo}PL^E!qX>AohGQH+A?D{78qOba@_rKTs=k{mgG}rYZ*FD|$Y1iIYS6&`}pX+&U zf6VQC<4pH`&aa>0b2BY2wIB8e`}1Tz9~{tp^XpOrif=(t2ei44+!lrMxnr#xY50a$ Y@up{P3$gkOy(_M?9i;cf>$W{V0Wo#~X8-^I diff --git a/__pycache__/laser_manager.cpython-312.pyc b/__pycache__/laser_manager.cpython-312.pyc index 51df997b04b0ec2e9f27c48cecec22593806b85e..5a170bdae88e487e0224aec6ea464c93b3ff83cf 100644 GIT binary patch delta 160 zcmew`mHGWtX5Q1hyj%=Gz~3`1>)%G+G;Zc6d;2Drahr390Yzen!LC8E3XX;*U@O8Dg&8NwTW?;X^lcfV_vYCr GLm2^9TR1}i delta 145 zcmaDqmHER|X5Q1hyj%=GutRNX*8h#XY23^&SI?MS#%<0i4ivTZ@O1asyp_9|k=^qG zpVw6m@6GnSVT>R(n`iJ{=9?_9$UC`0)@!npqU`1evI>loGnA}1TgyLToSZGoE84pG w<@B}B_BT9j?R?zO1$E6`tAQl3elH<+Z$)hc1h0H-+OP~EdO*CesC7ruGnlZgSa2*fCXI#1 zB4g2l+1k$FA$tqlgx|2&kY~~n#}|#zMdVm7NGq!_ppz z4-2u}^s+Go9LPSRBV{+OXa-%Ay|OrsN+TUZGi4vs*VnZ1$^O+g%Hz5Pk@&XN!6;AQ zGqzyPteWM(37BSNzh>TmOHdB2#ythoF$f5T|7ZgMWE6lKMI=>5rf@B^7vIxT;O#e zN;5rLq$-L$p~&bf5TssMPB;kzyS(3EgXy|bQ1}(E-Bc`w(u;rSjln*=6q5u?*|x%x z6RpIO7LMX<6O&}OQr+;-X+gEit)qmOYLn||K}owltJ762a@zyd__Y|Rv8mQ_{#Vz7 zxLwXWYA3Y__?~TFtL?kWt(FniZ1Qe7gfIKzte^_nKKyrI6CrK&OHD#KM8bBXGyjx7 zLPAeY1Ph~n2P|hn>@CB{yyhf7mn>>-{ENWOy&idw<{bc&A(@|y$a^QlL`t$S8I|{C zAJx-ygc%QxhsLGx@OWfAdc-I{{IXROvuE{n<@7Rm-Qan2aJdMr zp(D6MjN`?S1HT<|VP3Mq9}oixcSu$6Exaq@w$j3Aev;7UWutFO`*Qw?=ov=!O-3g| z%8ztkWvTkhaZN;2|ELXsNg^l0M@h@18Pz`-CL`(S?&Xn`eOtGl2P`+C|-E zCEe6x*_GFV@)JB0u6(0i)-B318^<@pA-p7*absk=gLqq={FV$e#pK!3!fBxfKyV05 zarswIp+n##tO40C>rk~I9n*{?&u)4J;92O-sm4z?;vpaln(k1l~#$nh{^F zjc~!0vpZGeVT(r>H;eK1ua=vx!t=fjJTIfxte{qwqNK}DltQCk@X1;}PFur}e{BO~ zrNpVvLPVcSUd`NPLvNXbK~fvrkrBvt5d*ai#d_a9BSz=s4d4J{@3<%Fos`A`d!zA!xfN+k3F9qEWDEpK{iIJ8^ynE zZG-19Y61JlEbReryDx>NmU2cg+MEXBstMWWxRVg?-S4JS9yiEaeF1Fh&rD@*lmZqSNuS|EKoxWRUG)8`#* zK{s1is&}$OM$;`w3Etwkp#-|+^bT!Bw;GIeW-Ci)5{T+aRsp8mtqwC`K94x13C&x* zN&}j&rd#J5SUS^0x6U_n!_{cM-8(Fy+kDTCVV+rVKr&e1nPE4(;AE*Tv1HRi9W&gB z7Mi$}h!&FGloKsFS)wlnEU7qJY=HE+g&XNWi`zR!k|=kl*+7E5lVr)%oeo6xF7CJu zEtxuwo6%i{uHH4XWah4ouHNOj3_^GPJ&|-5`lyXAf7Hd2se6bn-!pQV0J`TeQr*K+ zJy4vNxDzb8SKqVs1VHya=9j|EeF>fbPIN!ayj0EJj|RxXKLLA!#TR>j48L9I-!l%4 OgDi|LJ%{J^F8&_?&=79` delta 3928 zcmbVOX-r(#6~6b~_hxv^`j~xZ7{Ck|FvgfYn0kp_HxiJ>Evg-wz;Xzve9<@`N;+{P?#<2du!$CNGng z1t4XAMp%>PQheK>!$ET&e&5`8)E#fm-~n)bjevj$qFJ=O>>ms$ECdXY*$MY`m=Qw| zKfHwn9uk7j$HS^5&Z?AX6YbYgW~X8(n)q>5zNL*rbZ)kho+0OTW2V5HP_(jEbPdBO zBRUmr{MfcoZqc(D>H>@gAs`seGi3mfotqqLdlc`6LnPKRq2%pgiMNEmCCNtb6HxYvc-{3sJ!e-x+rj&QA-um$GcV8 zS`!Fl4?)C6oLeT`QDMT3uefaZp2eQX38&=$?_tXMY7kRQ6!9Q_N)1HL7mLKujbgR1 zbwJU@djP;us|V|fc&nlp1^RcL$(TTp(Bo^?ATr2$eA^lf8)d!pk_wky#WK~UVj@R# z(4*OHiLh)SSt*x|Z-L9KszEAXkd0?f0x$)mwM5%F;g$|&u~bT|NL%lw)?(#lZiBrk z8viC~F{@CSRW{+@+rolL1)^a_M>C%ha=m<{PN&rx*=@Md{vzj&mZWt<+H~!t zgZP#`2s`mo&?l^C9D)s2)eb$eqIEvtI8HQ^j*4o7SU*a_k@aFp3t2Z+r(tt-@aK*| zNH6QM1=(C6;%_b8sF4)ufb&#nt7-C7_D;nFGTZ*(v_TL4&>7~;vN_&~Sy!d5Q_Yto zlHixVW6~Niix>NL_Sqj z`U$>d@IVK?;dvAFX9|f=d3!eu`?u4>{!OnRCmcHb&})KM@V~tQe9&j1Zv)<=Hw1sC z;$_!NkrdLI(LHOp7kx()&WXS!Ms`dFCOp!+S#6b)ooZ{5Ht@^NQ3C*zWS#JxA@?cD z$j(V0*?G?#THAT!S5?~yk7_I1=-r6sk>|rMcBx!)Yn*<$AOl1*Dm!KCD0v3OXVY-C zvIRfyuQ=>b1lg$+kbkS_Q7mbY?`A=BH_9yTogiN)^&p^KKaH4)D1>p2*eMl_QfC?R5+4cYmTdLmANNx zV>b{5h5HdVrA>Bbs1Y~uIcy<1#`O6B)c-M@W+LoZcUQi(%m}R zmNTq2Cpw$FzmD!pyz+lwH*JGGwL_AwKAC>6%T(##^>`VjDl!(I1ClnXe$5UDxa!EJSSG=L5@q5%Smn`1FuTJ6C zGk}s!J7~X?iIS&LHm1EUm)Ja;%9=B(u2PpThb|d@F6q}KcCUt~zsBwOTIq2EJpxMJ z&IFZWc0CJI{bkj#K&T#yztD5`bVMA8^i@f*p-AfWaHkg5r{?xp8F&)^XYURCms$_L zR$GQ2)>h-=j>9O`fIB7j{#JCS`A`|z{H?fbARm0FZzc3} zejfd{7$p`=2OR_TXu2Ut=ozhTuoTSr+8u*c;9j9W;sGDmSYv+hiKZk{2|n5VEd$wn z*4!Q*Y6JI++iPR~1bE=oofE)=kU&Ha>UPDn;B&8o(6c(G&&$UeapxFkF z&~t$AH=sE^q~B(~zX{E`?EQ6Uu8yO0D>tCk&NDQ?`Fwt0ADXw=2ddG0SVKA09Odjo zl&Y8awbd*1l~v+9S#umG(FnDZfSHRvXS fe?e|ogMWAU=kS$O-;r^s>EmGG@=3h<^wNI;#yA|- diff --git a/__pycache__/power.cpython-312.pyc b/__pycache__/power.cpython-312.pyc index ef59564bccd92a56978da916c9cf33a9152982b2..08014642e632dada386351d24ccf27c3ea5d738b 100644 GIT binary patch delta 2766 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 diff --git a/__pycache__/vision.cpython-312.pyc b/__pycache__/vision.cpython-312.pyc index 1d101c73bcf7a82cf5981367594af8c435bf9399..9150d27cd7cf3ca2e10ccd6ba71af9e4088d3e0a 100644 GIT binary patch delta 24 ecmca|fa%HsCf?J$yj%=G@S<*7R`*6;_XPlN@Cd&E delta 24 ecmca|fa%HsCf?J$yj%=GFx7KfR_I1v_XPlIPY3}3 diff --git a/app.yaml b/app.yaml index 702e16c..b028360 100644 --- a/app.yaml +++ b/app.yaml @@ -18,6 +18,10 @@ files: - laser_manager.py - logger_manager.py - main.py + - model_270820.cvimodel + - model_270820.mud + - model_317211.cvimodel + - model_317211.mud - model_317828.cvimodel - model_317828.mud - network.py diff --git a/config.py b/config.py index 7df78c0..772305f 100644 --- a/config.py +++ b/config.py @@ -98,7 +98,7 @@ ADC_LASER_THRESHOLD = 3000 # ==================== 激光配置 ==================== MODULE_ADDR = 0x00 -# 激光开关改由 A14 GPIO 控制:低电平开启,高电平关闭。 +# 激光开关改由 A14 GPIO 控制:高电平开启,低电平关闭。 LASER_CONTROL_PIN = "A14" LASER_CONTROL_GPIO = "GPIOA14" LASER_CONTROL_ON_LEVEL = 0 @@ -267,7 +267,7 @@ TRIANGLE_SAMPLE_RADIUS_CM = 15.0 TRIANGLE_SAMPLE_ANGLES_DEG = (0, 90, 180, 270) TRIANGLE_SAMPLE_PATCH_HALF_PX = 2 # 开机阶段预加载 YOLO detector;detect 使用 dual_buff=False,避免返回上一帧结果。 -TRIANGLE_YOLO_PRELOAD_ON_BOOT = False +TRIANGLE_YOLO_PRELOAD_ON_BOOT = True # 诊断:本轮仅预加载 317211 # YOLO target size classification: class 0=20cm, class 1=40cm. TARGET_CLASS_YOLO_ENABLE = True @@ -277,7 +277,7 @@ TARGET_CLASS_YOLO_CONF_TH = 0.66 TARGET_CLASS_YOLO_IOU_TH = 0.45 TARGET_CLASS_YOLO_RETRY_ON_EMPTY = False TARGET_CLASS_YOLO_RETRY_CONF_TH = 0.25 -TARGET_CLASS_YOLO_PRELOAD_ON_BOOT = True +TARGET_CLASS_YOLO_PRELOAD_ON_BOOT = False # 诊断:暂不与 317211 同时加载 # ── 第二段 YOLO:仅在 Stage1 裁切出的靶环图上推理(与合成 stage2 训练数据一致)→ 子框内传统算法取直角点 ── # Stage1 靶环裁切内如何找黑三角标记(对比耗时时可切换): @@ -307,7 +307,7 @@ TRIANGLE_PATCH_APPROXPOLY_FRAC = 0.055 TRIANGLE_PATCH_APPROXPOLY_RELAX_MULTS = (1.0, 1.3, 1.65) # Otsu/Adaptive 前对子框灰度轻模糊:0=关闭;3 或 5=Gaussian ksize(须为奇数),压锯齿利于收成 3 顶点 TRIANGLE_PATCH_PRE_BLUR_KSIZE = 0 -TRIANGLE_BLACK_YOLO_PRELOAD_ON_BOOT = True +TRIANGLE_BLACK_YOLO_PRELOAD_ON_BOOT = False # 诊断:暂不预加载 270820 # 每箭是否在日志中打印黑三角 detect 统计(raw/类过滤/是否在环内);调通后可 False 减日志 TRIANGLE_BLACK_YOLO_LOG_EACH_SHOT = True # True=每次射箭将 Stage1 裁切图(黑三角模型输入)存为 JPEG;调试用,量产请 False @@ -343,7 +343,7 @@ RAW_IMAGE_MAX_IMAGES = MAX_IMAGES # Stage2 调试目录(默认 PHOTO_DIR/stage2_roi)内 JPEG 最多保留张数;None 表示与 MAX_IMAGES 相同 TRIANGLE_BLACK_YOLO_STAGE2_ROI_MAX_IMAGES = None -SHOW_CAMERA_PHOTO_WHILE_SHOOTING = False # 关闭拍摄实时显示 +SHOW_CAMERA_PHOTO_WHILE_SHOOTING = True # 关闭拍摄实时显示 # ==================== OTA配置 ==================== MAX_BACKUPS = 5 @@ -358,7 +358,7 @@ PIN_MAPPINGS = { "A28": "UART2_TX", "A15": "I2C5_SCL", "A27": "I2C5_SDA", - "A14": "GPIOA14", # 激光开关:低开、高关 + "A14": "GPIOA14", # 激光开关:高开、低关 "A24": "GPIOA24", # 电源板关机控制 "A25": "GPIOA25", # 电源状态绿灯 "A23": "GPIOA23", # 电源状态红灯 diff --git a/hardware.py b/hardware.py index f1f0455..75ed3ac 100644 --- a/hardware.py +++ b/hardware.py @@ -120,7 +120,7 @@ class HardwareManager: def _status_led_loop(self): from maix import gpio - from power import get_bus_voltage, is_charging, voltage_to_percent + from power import get_battery_status try: green = None @@ -148,9 +148,9 @@ class HardwareManager: while self._status_led_monitor_started: if sensor_elapsed >= poll_ms: - voltage = get_bus_voltage() - percent = voltage_to_percent(voltage) if voltage > 0 else None - charging = is_charging() + battery = get_battery_status() + percent = battery.get("percent") if battery.get("valid") else None + charging = bool(battery.get("charging")) if battery.get("valid") else False low = percent is not None and percent <= int(config.STATUS_LED_LOW_BATTERY_PERCENT) full = percent is not None and percent >= int(config.STATUS_LED_FULL_BATTERY_PERCENT) if charging: diff --git a/laser_manager.py b/laser_manager.py index 21d7bd9..d5df485 100644 --- a/laser_manager.py +++ b/laser_manager.py @@ -31,7 +31,7 @@ class LaserManager: # 私有状态 self._serial = None # 激光串口,由 laser_manager 自己持有 - self._laser_gpio = None # A14 激光开关,低电平开启、高电平关闭 + self._laser_gpio = None # A14 激光开关,高电平开启、低电平关闭 self._calibration_active = False self._calibration_result = None self._calibration_lock = threading.Lock() @@ -71,7 +71,7 @@ class LaserManager: # ==================== 初始化方法 ==================== def init_control_gpio(self): - """尽早初始化 A14,并拉高确保激光关闭。""" + """尽早初始化 A14,并拉低确保激光关闭。""" from maix import gpio, pinmap pinmap.set_pin_function(config.LASER_CONTROL_PIN, config.LASER_CONTROL_GPIO) @@ -79,12 +79,12 @@ class LaserManager: self._laser_gpio = gpio.GPIO(config.LASER_CONTROL_GPIO, gpio.Mode.OUT) self._laser_gpio.value(config.LASER_CONTROL_OFF_LEVEL) self._laser_turned_on = False - print(f"[LASER] {config.LASER_CONTROL_PIN}=HIGH,激光已关闭") + print(f"[LASER] {config.LASER_CONTROL_PIN}=LOW,激光已关闭") def init(self, serial_device=None, baudrate=None): """ 初始化激光模块(A14 开关 + 测距串口) - 初始化时先将 A14 拉高关闭激光,防止开机误触发 + 初始化时先将 A14 拉低关闭激光,防止开机误触发 Args: serial_device: 串口设备路径,默认使用 config.DISTANCE_SERIAL_DEVICE @@ -147,7 +147,7 @@ class LaserManager: return False def turn_on_laser(self): - """A14 输出低电平,开启激光。""" + """A14 输出高电平,开启激光。""" if self._laser_gpio is None: if self.logger: self.logger.error("[LASER] A14 GPIO 未初始化,请先调用 init()") @@ -156,7 +156,7 @@ class LaserManager: self._laser_gpio.value(config.LASER_CONTROL_ON_LEVEL) self._laser_turned_on = True if self.logger: - self.logger.info("[LASER] A14=LOW,激光开启") + self.logger.info("[LASER] A14=HIGH,激光开启") return True except Exception as e: if self.logger: @@ -164,7 +164,7 @@ class LaserManager: return False def turn_off_laser(self): - """A14 输出高电平,关闭激光。""" + """A14 输出低电平,关闭激光。""" if self._laser_gpio is None: if self.logger: self.logger.error("[LASER] A14 GPIO 未初始化,请先调用 init()") @@ -173,7 +173,7 @@ class LaserManager: self._laser_gpio.value(config.LASER_CONTROL_OFF_LEVEL) self._laser_turned_on = False if self.logger: - self.logger.info("[LASER] A14=HIGH,激光关闭") + self.logger.info("[LASER] A14=LOW,激光关闭") return True except Exception as e: if self.logger: diff --git a/main.py b/main.py index e222fc8..ffd9e70 100644 --- a/main.py +++ b/main.py @@ -81,7 +81,7 @@ def cmd_str(): # ==================== 第一阶段:硬件初始化 ==================== # 按照 main104.py 的顺序,先完成所有硬件初始化 - # 开机第一步先拉高 A14 关闭激光,避免其他硬件初始化期间误亮。 + # 开机第一步先拉低 A14 关闭激光,避免其他硬件初始化期间误亮。 laser_manager.init_control_gpio() # 1. 引脚功能映射 @@ -105,8 +105,6 @@ def cmd_str(): print(f"[BOOT] init_ina226 开始 wall_s={_w_boot:.3f}") init_ina226() print(f"[BOOT] init_ina226 结束 wall +{int(round((wall_time.time() - _w_boot) * 1000))} ms") - # 启动 A25 绿灯和 A23 红灯状态指示。 - hardware_manager.start_status_led_monitor() # 4. 初始化显示和相机 _w_boot = wall_time.time() @@ -121,6 +119,8 @@ def cmd_str(): print(f"[BOOT] init_display 开始 wall_s={_w_boot:.3f}") camera_manager.init_display() print(f"[BOOT] init_display 结束 wall +{int(round((wall_time.time() - _w_boot) * 1000))} ms") + # 相机和显示初始化完成后再启动状态灯;灯状态复用网络电量上报快照,不访问 I2C。 + hardware_manager.start_status_led_monitor() # ==================== 第二阶段:软件初始化 ==================== @@ -358,7 +358,7 @@ def cmd_str(): logger.info("[MAIN] 超过设定时间未检测活动,自动关机") network_manager.safe_enqueue({"poweroff": "超过设定时间未检测活动,自动关机"}, 2) time.sleep_ms(100) - hardware_manager.power_off() + #hardware_manager.power_off() time.sleep_ms(2000) # 让关机指令生效 break diff --git a/network.py b/network.py index e8d7d16..9da9b2b 100644 --- a/network.py +++ b/network.py @@ -18,7 +18,7 @@ import socket import config from hardware import hardware_manager -from power import get_bus_voltage, voltage_to_percent, is_charging +from power import get_bus_voltage, voltage_to_percent, is_charging, update_battery_status from logger_manager import logger_manager from wifi import wifi_manager import subprocess @@ -2139,14 +2139,16 @@ class NetworkManager: elif inner_cmd == 4: # 上报电量 voltage = get_bus_voltage() battery_percent = voltage_to_percent(voltage) + charging = is_charging() + update_battery_status(voltage, battery_percent, charging) battery_data = { "battery": battery_percent, "voltage": round(float(voltage), 3), "netType": self.network_type, } self.safe_enqueue(battery_data, 2) - self.logger.info(f"电量上报: {battery_percent}% 充电: {is_charging()}") - if getattr(config, "CHARGING_AUTO_POWER_OFF_ENABLED", False) and is_charging(): + self.logger.info(f"电量上报: {battery_percent}% 充电: {charging}") + if getattr(config, "CHARGING_AUTO_POWER_OFF_ENABLED", False) and charging: self.safe_enqueue( { "cmd": 700, @@ -2339,8 +2341,10 @@ class NetworkManager: current_time = time.ticks_ms() if logged_in and current_time - last_heartbeat_send_time > config.HEARTBEAT_INTERVAL * 1000: vol_val = get_bus_voltage() + vol_percent = voltage_to_percent(vol_val) + update_battery_status(vol_val, vol_percent, is_charging()) if not self.tcp_send_raw( - self._netcore.make_packet(4, {"vol": vol_val, "vol_per": voltage_to_percent(vol_val)})): + self._netcore.make_packet(4, {"vol": vol_val, "vol_per": vol_percent})): # if not self.tcp_send_raw(self.make_packet(4, {"vol": vol_val, "vol_per": voltage_to_percent(vol_val)})): send_hartbeat_fail_count += 1 # 短暂波动可能导致一次发送失败:连续失败达到阈值才重连,避免重连风暴 diff --git a/power.py b/power.py index fb0ec26..14e8bb8 100644 --- a/power.py +++ b/power.py @@ -13,6 +13,31 @@ from maix import time as maix_time _INA226_PRESENT = None _INA226_LOCK = _thread.allocate_lock() +_BATTERY_STATUS = {"voltage": 0.0, "percent": None, "charging": False, "valid": False} +_BATTERY_STATUS_LOCK = _thread.allocate_lock() + + +def update_battery_status(voltage, percent=None, charging=None): + """保存网络电量上报得到的最近状态,供状态灯复用,不重复读 I2C。""" + _BATTERY_STATUS_LOCK.acquire() + try: + _BATTERY_STATUS["voltage"] = float(voltage or 0.0) + _BATTERY_STATUS["percent"] = percent + if charging is not None: + _BATTERY_STATUS["charging"] = bool(charging) + _BATTERY_STATUS["valid"] = _BATTERY_STATUS["voltage"] > 0 and percent is not None + return dict(_BATTERY_STATUS) + finally: + _BATTERY_STATUS_LOCK.release() + + +def get_battery_status(): + """返回最近一次电量上报快照;不会触发 I2C 访问。""" + _BATTERY_STATUS_LOCK.acquire() + try: + return dict(_BATTERY_STATUS) + finally: + _BATTERY_STATUS_LOCK.release() def _ina226_ready() -> bool: diff --git a/version.md b/version.md index 1fab875..6dfc69d 100644 --- a/version.md +++ b/version.md @@ -34,4 +34,5 @@ # 2.17.1 26-08-19 17:39 压力传感修改 增量方式 # 2.17.2 26-08-24 17:56 靶纸识别模型更替 # 2.17.3 26-08-25 9:57 原图拍摄开关 -# 2.17.4 26-08-25 14:57 模型修改 +# 2.17.4 26-08-25 14:57 模型修改 +# 2.18.0 二代 \ No newline at end of file