Compare commits
9
Commits
ffeb82cf8f
..
3.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3f1cfdea0 | ||
|
|
8457bd29c6 | ||
|
|
5bde549d91 | ||
|
|
d96ca4d031 | ||
|
|
ced66682ed | ||
|
|
a09b45738a | ||
|
|
e4d8454947 | ||
|
|
c09189332d | ||
|
|
a00baa1770 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
id: t11
|
||||
name: t11
|
||||
version: 2.17.14
|
||||
version: 3.0.5
|
||||
author: t11
|
||||
icon: ''
|
||||
desc: t11
|
||||
@@ -18,12 +18,8 @@ files:
|
||||
- laser_manager.py
|
||||
- logger_manager.py
|
||||
- main.py
|
||||
- model_317828.cvimodel
|
||||
- model_317828.mud
|
||||
- model_317211.cvimodel
|
||||
- model_317211.mud
|
||||
- model_270820.cvimodel
|
||||
- model_270820.mud
|
||||
- model_285484.cvimodel
|
||||
- model_285484.mud
|
||||
- network.py
|
||||
- ota_curl.sh
|
||||
- ota_manager.py
|
||||
|
||||
+17
-1
@@ -8,6 +8,15 @@ import threading
|
||||
import config
|
||||
from logger_manager import logger_manager
|
||||
|
||||
_USE_CV = False
|
||||
try:
|
||||
import cv2
|
||||
import numpy as np
|
||||
from maix import image as _maix_image
|
||||
_USE_CV = True
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class CameraManager:
|
||||
"""相机管理器(单例)"""
|
||||
@@ -57,6 +66,12 @@ class CameraManager:
|
||||
with self._camera_lock:
|
||||
if self._camera is None:
|
||||
self._camera = camera.Camera(width, height)
|
||||
v_flip = getattr(config, 'CAMERA_V_FLIP', False)
|
||||
h_mirror = getattr(config, 'CAMERA_H_MIRROR', False)
|
||||
if v_flip:
|
||||
self._camera.vflip(1)
|
||||
if h_mirror:
|
||||
self._camera.hmirror(1)
|
||||
|
||||
return self._camera
|
||||
|
||||
@@ -101,7 +116,8 @@ class CameraManager:
|
||||
with self._camera_lock:
|
||||
if self._camera is None:
|
||||
self.init_camera()
|
||||
return self._camera.read()
|
||||
frame = self._camera.read()
|
||||
return frame
|
||||
|
||||
def show(self, image):
|
||||
"""
|
||||
|
||||
@@ -15,6 +15,8 @@ LOCAL_FILENAME = APP_DIR + "/main_tmp.py"
|
||||
# 相机初始化分辨率(CameraManager / main.py 使用)
|
||||
CAMERA_WIDTH = 640
|
||||
CAMERA_HEIGHT = 480
|
||||
CAMERA_V_FLIP = True # 摄像头垂直翻转(上下颠倒时设为 True)
|
||||
CAMERA_H_MIRROR = True # 摄像头水平镜像(左右反了时设为 True)
|
||||
|
||||
# 三角形检测缩图比例:默认按相机最长边缩到 1/2(性能更稳;可按需调整)
|
||||
# 取值范围建议 (0.25 ~ 1.0];1.0 表示不缩图
|
||||
@@ -239,10 +241,10 @@ TRIANGLE_BLACKHAT_KERNEL_FRAC = 0.018 # 核大小 ≈ min(h,w)*frac,取奇数
|
||||
# ── YOLO(NPU) 靶环 ROI → 裁剪后再跑三角形(减小 CPU 处理面积)──────────────────
|
||||
# 日志里 net_in=W×H 来自 .mud 模型(det.input_width/height),不是这里配置的。
|
||||
TRIANGLE_YOLO_ROI_ENABLE = True
|
||||
TRIANGLE_YOLO_MODEL_PATH = APP_DIR + "/model_317211.mud"
|
||||
TRIANGLE_YOLO_MODEL_PATH = APP_DIR + "/model_270139.mud"
|
||||
# 参与 ROI 的类别:多类时只填「整靶/靶环」的 id;不要填角标类,否则 union 仍可对,但 largest 会偏小。
|
||||
TRIANGLE_YOLO_RING_CLASS_IDS = (0,)
|
||||
TRIANGLE_YOLO_CONF_TH = 0.9
|
||||
TRIANGLE_YOLO_CONF_TH = 0.7
|
||||
TRIANGLE_YOLO_IOU_TH = 0.45
|
||||
# YOLO 首次/临界帧可能在高阈值下 0 框;启用后仅在 0 候选时用较低阈值重试一次。
|
||||
# 后续仍会经过 min_box_side、ROI aspect、三角形几何校验,避免直接放大假阳性。
|
||||
@@ -269,9 +271,9 @@ TRIANGLE_YOLO_PRELOAD_ON_BOOT = False
|
||||
|
||||
# YOLO target size classification: class 0=20cm, class 1=40cm.
|
||||
TARGET_CLASS_YOLO_ENABLE = True
|
||||
TARGET_CLASS_YOLO_MODEL_PATH = APP_DIR + "/model_317828.mud"
|
||||
TARGET_CLASS_YOLO_MODEL_PATH = APP_DIR + "/model_285484.mud"
|
||||
TARGET_CLASS_YOLO_LABELS = (20, 40)
|
||||
TARGET_CLASS_YOLO_CONF_TH = 0.66
|
||||
TARGET_CLASS_YOLO_CONF_TH = 0.50
|
||||
TARGET_CLASS_YOLO_IOU_TH = 0.45
|
||||
TARGET_CLASS_YOLO_RETRY_ON_EMPTY = False
|
||||
TARGET_CLASS_YOLO_RETRY_CONF_TH = 0.25
|
||||
@@ -331,17 +333,14 @@ LOG_QUEUE_MAXSIZE = 10000 # 日志队列上限
|
||||
MAX_CMD_THREADS = 10 # 并发命令线程上限(防止服务器下发命令时无限创建线程)
|
||||
|
||||
# ==================== 图像保存配置 ====================
|
||||
SAVE_IMAGE_ENABLED = True # 是否保存图像(True=保存,False=不保存)
|
||||
SAVE_IMAGE_ON_FAILURE = False # 检测失败时是否强制保存图像(供调试测试用)
|
||||
SAVE_IMAGE_ENABLED = False # 是否保存图像(True=保存,False=不保存)
|
||||
SAVE_IMAGE_ON_FAILURE = True # 检测失败时是否强制保存图像(供调试测试用)
|
||||
PHOTO_DIR = "/root/phot" # 照片存储目录
|
||||
MAX_IMAGES = 1000
|
||||
SAVE_RAW_IMAGE_ENABLED = False # 原图保存功能保留,但当前关闭
|
||||
RAW_IMAGE_DIR = PHOTO_DIR + "/raw"
|
||||
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 = False # 是否在拍摄时显示摄像头图像(True=显示,False=不显示),建议在连着USB测试过程中打开
|
||||
|
||||
# ==================== OTA配置 ====================
|
||||
MAX_BACKUPS = 5
|
||||
|
||||
@@ -56,10 +56,17 @@ PYBIND11_MODULE(archery_netcore, m) {
|
||||
m.def("make_packet", &netcore::make_packet,
|
||||
"Pack TCP packet: header (len+type+checksum) + JSON body",
|
||||
py::arg("msg_type"), py::arg("body_dict"));
|
||||
|
||||
|
||||
m.def("make_packet_pb", &netcore::make_packet_pb,
|
||||
"Pack TCP packet: header (len+type+checksum) + raw bytes body (for protobuf)",
|
||||
py::arg("msg_type"), py::arg("body_bytes"));
|
||||
|
||||
m.def("parse_packet", &netcore::parse_packet,
|
||||
"Parse TCP packet, return (msg_type, body_dict)");
|
||||
|
||||
m.def("parse_packet_raw", &netcore::parse_packet_raw,
|
||||
"Parse TCP packet, return (msg_type, body_bytes) without JSON parsing");
|
||||
|
||||
m.def("get_config", &get_config, "Get system configuration");
|
||||
|
||||
m.def(
|
||||
|
||||
@@ -51,6 +51,43 @@ namespace netcore {
|
||||
return py::bytes(reinterpret_cast<const char*>(packet.data()), packet.size());
|
||||
}
|
||||
|
||||
// 打包 TCP 数据包 (raw bytes body, 用于 protobuf)
|
||||
py::bytes make_packet_pb(int msg_type, py::bytes body_bytes) {
|
||||
netcore::log_debug(std::string("make_packet_pb msg_type=") + std::to_string(msg_type));
|
||||
|
||||
py::buffer_info buf = py::buffer(body_bytes).request();
|
||||
uint32_t body_len = buf.size;
|
||||
uint32_t checksum = body_len + msg_type;
|
||||
|
||||
std::vector<uint8_t> packet;
|
||||
packet.reserve(12 + body_len);
|
||||
|
||||
// body_len (big-endian, 4 bytes)
|
||||
packet.push_back((body_len >> 24) & 0xFF);
|
||||
packet.push_back((body_len >> 16) & 0xFF);
|
||||
packet.push_back((body_len >> 8) & 0xFF);
|
||||
packet.push_back(body_len & 0xFF);
|
||||
|
||||
// msg_type (big-endian, 4 bytes)
|
||||
packet.push_back((msg_type >> 24) & 0xFF);
|
||||
packet.push_back((msg_type >> 16) & 0xFF);
|
||||
packet.push_back((msg_type >> 8) & 0xFF);
|
||||
packet.push_back(msg_type & 0xFF);
|
||||
|
||||
// checksum (big-endian, 4 bytes)
|
||||
packet.push_back((checksum >> 24) & 0xFF);
|
||||
packet.push_back((checksum >> 16) & 0xFF);
|
||||
packet.push_back((checksum >> 8) & 0xFF);
|
||||
packet.push_back(checksum & 0xFF);
|
||||
|
||||
// 追加 body bytes
|
||||
const uint8_t* body_ptr = static_cast<const uint8_t*>(buf.ptr);
|
||||
packet.insert(packet.end(), body_ptr, body_ptr + body_len);
|
||||
|
||||
netcore::log_debug(std::string("make_packet_pb done bytes=") + std::to_string(packet.size()));
|
||||
return py::bytes(reinterpret_cast<const char*>(packet.data()), packet.size());
|
||||
}
|
||||
|
||||
// 解析 TCP 数据包
|
||||
py::tuple parse_packet(py::bytes data) {
|
||||
// 1) 转换为 bytes view
|
||||
@@ -110,4 +147,26 @@ namespace netcore {
|
||||
return py::make_tuple(py::int_(msg_type), raw_dict);
|
||||
}
|
||||
}
|
||||
|
||||
// 解析 TCP 数据包 -> (msg_type, body_bytes) 不做 JSON 解析
|
||||
py::tuple parse_packet_raw(py::bytes data) {
|
||||
py::buffer_info buf = py::buffer(data).request();
|
||||
if (buf.size < 12) {
|
||||
return py::make_tuple(py::none(), py::none());
|
||||
}
|
||||
|
||||
const uint8_t* ptr = static_cast<const uint8_t*>(buf.ptr);
|
||||
|
||||
uint32_t body_len = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
|
||||
uint32_t msg_type = (ptr[4] << 24) | (ptr[5] << 16) | (ptr[6] << 8) | ptr[7];
|
||||
|
||||
uint32_t expected_len = 12 + body_len;
|
||||
if (buf.size < expected_len) {
|
||||
return py::make_tuple(py::none(), py::none());
|
||||
}
|
||||
|
||||
// 返回原始 body bytes(不做 JSON 解析)
|
||||
py::bytes body_bytes(reinterpret_cast<const char*>(ptr + 12), body_len);
|
||||
return py::make_tuple(py::int_(msg_type), body_bytes);
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,15 @@ namespace py = pybind11;
|
||||
|
||||
namespace netcore {
|
||||
|
||||
// 打包 TCP 数据包
|
||||
// 打包 TCP 数据包 (JSON body)
|
||||
py::bytes make_packet(int msg_type, py::dict body_dict);
|
||||
// 解包 TCP 数据包
|
||||
|
||||
// 打包 TCP 数据包 (raw bytes body, 用于 protobuf)
|
||||
py::bytes make_packet_pb(int msg_type, py::bytes body_bytes);
|
||||
|
||||
// 解包 TCP 数据包 -> (msg_type, body_dict)
|
||||
py::tuple parse_packet(py::bytes data);
|
||||
|
||||
// 解包 TCP 数据包 -> (msg_type, body_bytes) 不做 JSON 解析
|
||||
py::tuple parse_packet_raw(py::bytes data);
|
||||
}
|
||||
@@ -136,6 +136,7 @@ def cmd_str():
|
||||
sync_system_time_from_4g()
|
||||
|
||||
# 2.1 WiFi 热点配网兜底:仅当 STA 与 4G 均不可用时起 AP + HTTP;提交后删 /boot/wifi.ap、建 wifi.sta 并 reboot
|
||||
_ota_pending_path = f"{config.APP_DIR}/ota_pending.json"
|
||||
try:
|
||||
from wifi_config_httpd import maybe_start_wifi_ap_fallback
|
||||
|
||||
@@ -171,10 +172,8 @@ def cmd_str():
|
||||
and bool(getattr(config, "TARGET_CLASS_YOLO_PRELOAD_ON_BOOT", True))
|
||||
)
|
||||
_preload_yolo = _preload_yolo or _need_black_preload or _need_target_preload
|
||||
if _preload_yolo and not os.path.exists(f"{config.APP_DIR}/ota_pending.json"):
|
||||
if _preload_yolo:
|
||||
preload_yolo_detector(logger)
|
||||
elif _preload_yolo and logger:
|
||||
logger.warning("[YOLO] ota_pending.json found; skip model preload until rollback check")
|
||||
except Exception as e:
|
||||
if logger:
|
||||
logger.warning(f"[YOLO-ROI] 启动预加载异常(不影响后续射箭): {e}")
|
||||
@@ -256,11 +255,7 @@ def cmd_str():
|
||||
network_manager.read_device_id()
|
||||
|
||||
# 5. 创建照片存储目录(如果启用图像保存或检测失败时强制保存)
|
||||
if (
|
||||
config.SAVE_IMAGE_ENABLED
|
||||
or getattr(config, "SAVE_IMAGE_ON_FAILURE", False)
|
||||
or getattr(config, "SAVE_RAW_IMAGE_ENABLED", False)
|
||||
):
|
||||
if config.SAVE_IMAGE_ENABLED or getattr(config, "SAVE_IMAGE_ON_FAILURE", False):
|
||||
photo_dir = config.PHOTO_DIR
|
||||
if photo_dir not in os.listdir("/root"):
|
||||
try:
|
||||
@@ -293,8 +288,8 @@ def cmd_str():
|
||||
|
||||
last_adc_trigger = 0
|
||||
trigger_adc_val = 0 # 触发时的气压值,气压需降回此值以下才能再次触发
|
||||
enable_check = True
|
||||
# 读取一次ADC初始值,防止开机时传感器已有压力导致误触发
|
||||
enable_check = True
|
||||
try:
|
||||
last_adc_val = hardware_manager.adc_obj.read()
|
||||
except Exception:
|
||||
@@ -388,15 +383,15 @@ def cmd_str():
|
||||
pressure_max = adc_val
|
||||
if len(pressure_buf) >= PRESSURE_BATCH_SIZE:
|
||||
_flush_pressure_buf("batch")
|
||||
# 突变增量检测:压力增量大于500时触发。
|
||||
# 触发后需等气压降回触发点以下,才重新允许下一次触发。
|
||||
if adc_val < trigger_adc_val:
|
||||
# 突变增量检测:压力增量大于300时触发
|
||||
# 触发后需等气压降到触发值以下才重新检测增量
|
||||
if adc_val < trigger_adc_val :
|
||||
enable_check = True
|
||||
if (adc_val - last_adc_val) > 500 and enable_check:
|
||||
if (adc_val - last_adc_val) > 200 and enable_check:
|
||||
hardware_manager.start_idle_timer() # 重新计时
|
||||
last_adc_trigger = current_time
|
||||
trigger_adc_val = adc_val # 记录触发点
|
||||
last_adc_val = adc_val # 更新基准,防止连续增量重复触发
|
||||
trigger_adc_val = adc_val # 记录触发时的气压值
|
||||
last_adc_val = adc_val # 更新基准值,防止连续增量误触发
|
||||
enable_check = False
|
||||
_flush_pressure_buf("before_trigger")
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,13 +0,0 @@
|
||||
|
||||
[basic]
|
||||
type = cvimodel
|
||||
model = model_270139.cvimodel
|
||||
|
||||
[extra]
|
||||
model_type = yolov5
|
||||
input_type = rgb
|
||||
mean = 0, 0, 0
|
||||
scale = 0.00392156862745098, 0.00392156862745098, 0.00392156862745098
|
||||
anchors = 10, 13, 16, 30, 33, 23, 30, 61, 62, 45, 59, 119, 116, 90, 156, 198, 373, 326
|
||||
labels = 黑三角和圆环
|
||||
|
||||
Binary file not shown.
@@ -1,13 +0,0 @@
|
||||
|
||||
[basic]
|
||||
type = cvimodel
|
||||
model = model_270820.cvimodel
|
||||
|
||||
[extra]
|
||||
model_type = yolov5
|
||||
input_type = rgb
|
||||
mean = 0, 0, 0
|
||||
scale = 0.00392156862745098, 0.00392156862745098, 0.00392156862745098
|
||||
anchors = 10, 13, 16, 30, 33, 23, 30, 61, 62, 45, 59, 119, 116, 90, 156, 198, 373, 326
|
||||
labels = triangle
|
||||
|
||||
Binary file not shown.
@@ -1,13 +0,0 @@
|
||||
|
||||
[basic]
|
||||
type = cvimodel
|
||||
model = model_317211.cvimodel
|
||||
|
||||
[extra]
|
||||
model_type = yolov5
|
||||
input_type = rgb
|
||||
mean = 0, 0, 0
|
||||
scale = 0.00392156862745098, 0.00392156862745098, 0.00392156862745098
|
||||
anchors = 10, 13, 16, 30, 33, 23, 30, 61, 62, 45, 59, 119, 116, 90, 156, 198, 373, 326
|
||||
labels = circle, triangle
|
||||
|
||||
Binary file not shown.
@@ -1,13 +0,0 @@
|
||||
|
||||
[basic]
|
||||
type = cvimodel
|
||||
model = model_317828.cvimodel
|
||||
|
||||
[extra]
|
||||
model_type = yolov5
|
||||
input_type = rgb
|
||||
mean = 0, 0, 0
|
||||
scale = 0.00392156862745098, 0.00392156862745098, 0.00392156862745098
|
||||
anchors = 10, 13, 16, 30, 33, 23, 30, 61, 62, 45, 59, 119, 116, 90, 156, 198, 373, 326
|
||||
labels = 20, 40
|
||||
|
||||
+114
-7
@@ -23,6 +23,14 @@ from logger_manager import logger_manager
|
||||
from wifi import wifi_manager
|
||||
import subprocess
|
||||
|
||||
# protobuf 支持
|
||||
try:
|
||||
import tcp_messages_pb2 as pb
|
||||
_HAS_PROTO = True
|
||||
except ImportError:
|
||||
_HAS_PROTO = False
|
||||
print("[NET] tcp_messages_pb2 not found, protobuf disabled")
|
||||
|
||||
|
||||
def _wifi_tls_would_block(exc):
|
||||
"""
|
||||
@@ -72,6 +80,9 @@ class NetworkManager:
|
||||
self._raw_line_data = []
|
||||
self._manual_trigger_flag = False
|
||||
|
||||
# protobuf 协议支持
|
||||
self._use_proto = _HAS_PROTO # 默认启用 proto(如果可用)
|
||||
|
||||
# 限制并发命令线程数
|
||||
self._cmd_thread_lock = threading.Lock()
|
||||
self._cmd_thread_count = 0
|
||||
@@ -711,6 +722,103 @@ class NetworkManager:
|
||||
"""线程安全地将消息加入队列(公共方法)"""
|
||||
self._enqueue((msg_type, data_dict), high)
|
||||
|
||||
def _make_send_packet(self, msg_type, data_dict):
|
||||
"""根据协议模式构造发送数据包"""
|
||||
if self._use_proto and _HAS_PROTO:
|
||||
return self._make_proto_packet(msg_type, data_dict)
|
||||
return self._netcore.make_packet(msg_type, data_dict)
|
||||
|
||||
def _make_proto_packet(self, msg_type, data_dict):
|
||||
"""使用 protobuf 序列化构造数据包"""
|
||||
try:
|
||||
if msg_type == 1:
|
||||
# 登录消息
|
||||
msg = pb.LoginRequest(
|
||||
device_id=data_dict.get("deviceId", ""),
|
||||
password=data_dict.get("password", ""),
|
||||
if_admin=data_dict.get("ifAdmin", False),
|
||||
version=data_dict.get("version", ""),
|
||||
vol=data_dict.get("vol", 0),
|
||||
vol_per=data_dict.get("vol_per", 0),
|
||||
iccid=data_dict.get("iccid", ""),
|
||||
)
|
||||
elif msg_type == 4:
|
||||
# 心跳消息
|
||||
msg = pb.Heartbeat(
|
||||
t=data_dict.get("t", 0),
|
||||
vol=data_dict.get("vol", 0),
|
||||
vol_per=data_dict.get("vol_per", 0),
|
||||
)
|
||||
elif msg_type == 2:
|
||||
# 业务逻辑消息
|
||||
cmd = data_dict.get("cmd", 0)
|
||||
inner_data = {k: v for k, v in data_dict.items() if k != "cmd"}
|
||||
data_bytes = json.dumps(inner_data).encode("utf-8") if inner_data else b""
|
||||
msg = pb.LogicBody(cmd=cmd, data=data_bytes)
|
||||
else:
|
||||
# 其他消息类型,回退到 JSON
|
||||
return self._netcore.make_packet(msg_type, data_dict)
|
||||
|
||||
body_bytes = msg.SerializeToString()
|
||||
return self._netcore.make_packet_pb(msg_type, body_bytes)
|
||||
except Exception as e:
|
||||
self.logger.error(f"[NET] protobuf 序列化失败,回退到 JSON: {e}")
|
||||
return self._netcore.make_packet(msg_type, data_dict)
|
||||
|
||||
def _parse_recv(self, payload):
|
||||
"""解析接收的数据包,返回 (msg_type, body_dict)"""
|
||||
if self._use_proto and _HAS_PROTO:
|
||||
msg_type, body_bytes = self._netcore.parse_packet_raw(payload)
|
||||
if msg_type is None:
|
||||
return None, None
|
||||
try:
|
||||
body_dict = self._parse_proto_body(msg_type, body_bytes)
|
||||
return msg_type, body_dict
|
||||
except Exception as e:
|
||||
self.logger.error(f"[NET] protobuf 反序列化失败: {e}")
|
||||
# 回退到 JSON 解析
|
||||
return self._netcore.parse_packet(payload)
|
||||
else:
|
||||
return self._netcore.parse_packet(payload)
|
||||
|
||||
def _parse_proto_body(self, msg_type, body_bytes):
|
||||
"""将 protobuf body bytes 反序列化为 dict"""
|
||||
if msg_type == 1:
|
||||
msg = pb.LoginResponse()
|
||||
msg.ParseFromString(body_bytes)
|
||||
return {"cmd": msg.cmd, "data": msg.data}
|
||||
elif msg_type == 4:
|
||||
# 心跳 ACK 通常无 body
|
||||
return {}
|
||||
elif msg_type == 2:
|
||||
msg = pb.LogicBody()
|
||||
msg.ParseFromString(body_bytes)
|
||||
result = {"cmd": msg.cmd}
|
||||
if msg.data:
|
||||
try:
|
||||
result["data"] = json.loads(msg.data.decode("utf-8"))
|
||||
except:
|
||||
result["data"] = {"raw": msg.data.hex()}
|
||||
return result
|
||||
elif msg_type == 40:
|
||||
msg = pb.OtaFragment()
|
||||
msg.ParseFromString(body_bytes)
|
||||
return {"l": msg.l, "d": msg.d, "t": msg.t, "v": msg.v}
|
||||
elif msg_type == 100:
|
||||
msg = pb.ImageUploadCommand()
|
||||
msg.ParseFromString(body_bytes)
|
||||
return {"uploadUrl": msg.upload_url, "token": msg.token, "shootId": msg.shoot_id, "outlink": msg.outlink}
|
||||
elif msg_type == 101:
|
||||
msg = pb.LogUploadCommand()
|
||||
msg.ParseFromString(body_bytes)
|
||||
return {"uploadUrl": msg.upload_url, "token": msg.token, "key": msg.key, "outlink": msg.outlink, "archive": msg.archive}
|
||||
else:
|
||||
# 未知类型,尝试 JSON 解析
|
||||
try:
|
||||
return json.loads(body_bytes.decode("utf-8"))
|
||||
except:
|
||||
return {"raw": body_bytes.hex()}
|
||||
|
||||
def connect_server(self):
|
||||
"""
|
||||
连接到服务器(自动选择WiFi或4G)
|
||||
@@ -1842,14 +1950,13 @@ class NetworkManager:
|
||||
login_data = {
|
||||
"deviceId": self.device_id,
|
||||
"password": self.password,
|
||||
"version": config.APP_VERSION,
|
||||
"version": config.APP_VERSION + ("+proto" if self._use_proto else ""),
|
||||
"vol": vol_val,
|
||||
"vol_per": voltage_to_percent(vol_val)
|
||||
}
|
||||
iccid_pending_marker = self._maybe_add_iccid_to_login(login_data)
|
||||
print(f"login_data: {login_data}")
|
||||
# if not self.tcp_send_raw(self.make_packet(1, login_data)):
|
||||
if not self.tcp_send_raw(self._netcore.make_packet(1, login_data)):
|
||||
if not self.tcp_send_raw(self._make_send_packet(1, login_data)):
|
||||
self._tcp_connected = False
|
||||
try:
|
||||
self.disconnect_server()
|
||||
@@ -1926,7 +2033,7 @@ class NetworkManager:
|
||||
pass
|
||||
|
||||
# msg_type, body = self.parse_packet(payload)
|
||||
msg_type, body = self._netcore.parse_packet(payload)
|
||||
msg_type, body = self._parse_recv(payload)
|
||||
|
||||
# 处理登录响应
|
||||
if not logged_in and msg_type == 1:
|
||||
@@ -2310,7 +2417,7 @@ class NetworkManager:
|
||||
|
||||
if item:
|
||||
msg_type, data_dict = item
|
||||
pkt = self._netcore.make_packet(msg_type, data_dict)
|
||||
pkt = self._make_send_packet(msg_type, data_dict)
|
||||
if not self.tcp_send_raw(pkt):
|
||||
# 发送失败:将消息放回队首(队列满则丢弃)
|
||||
with self.get_queue_lock():
|
||||
@@ -2339,8 +2446,8 @@ 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()
|
||||
if not self.tcp_send_raw(
|
||||
self._netcore.make_packet(4, {"vol": vol_val, "vol_per": voltage_to_percent(vol_val)})):
|
||||
heartbeat_pkt = self._make_send_packet(4, {"vol": vol_val, "vol_per": voltage_to_percent(vol_val)})
|
||||
if not self.tcp_send_raw(heartbeat_pkt):
|
||||
# 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
|
||||
# 短暂波动可能导致一次发送失败:连续失败达到阈值才重连,避免重连风暴
|
||||
|
||||
+5
-13
@@ -8,7 +8,7 @@ from laser_manager import laser_manager
|
||||
from logger_manager import logger_manager
|
||||
from network import network_manager
|
||||
from triangle_target import load_camera_from_xml, load_triangle_positions, try_triangle_scoring
|
||||
from vision import estimate_distance, detect_circle_v3, enqueue_save_shot, enqueue_save_raw_shot
|
||||
from vision import estimate_distance, detect_circle_v3, enqueue_save_shot
|
||||
from maix import image, time
|
||||
|
||||
# 缓存相机标定与三角形位置,避免每次射箭重复读磁盘
|
||||
@@ -322,11 +322,6 @@ def process_shot(adc_val):
|
||||
try:
|
||||
frame = camera_manager.read_frame()
|
||||
|
||||
# 在任何检测和绘图之前复制原始帧;默认由配置关闭,不增加量产开销。
|
||||
from shot_id_generator import shot_id_generator
|
||||
shot_id = shot_id_generator.generate_id()
|
||||
enqueue_save_raw_shot(frame, shot_id)
|
||||
|
||||
# 网络事件移到拍照之后,避免阻塞拍照
|
||||
network_manager.safe_enqueue({"shoot_event": "start"}, msg_type=2, high=True)
|
||||
|
||||
@@ -385,6 +380,10 @@ def process_shot(adc_val):
|
||||
if dx is None and dy is None and logger:
|
||||
logger.warning("[MAIN] 未检测到偏移量(三角形与圆形均失败),但会保存图像")
|
||||
|
||||
# 生成射箭ID
|
||||
from shot_id_generator import shot_id_generator
|
||||
shot_id = shot_id_generator.generate_id()
|
||||
|
||||
if logger:
|
||||
logger.info(f"[MAIN] 射箭ID: {shot_id}")
|
||||
|
||||
@@ -442,13 +441,6 @@ def process_shot(adc_val):
|
||||
inner_data["ellipse_center_x"] = None
|
||||
inner_data["ellipse_center_y"] = None
|
||||
|
||||
upload_time_ms = int(time_std.time() * 1000)
|
||||
upload_time_sec, upload_time_millis = divmod(upload_time_ms, 1000)
|
||||
inner_data["upload_time"] = (
|
||||
time_std.strftime("%Y-%m-%d %H:%M:%S", time_std.localtime(upload_time_sec))
|
||||
+ f".{upload_time_millis:03d}"
|
||||
)
|
||||
|
||||
report_data = {"cmd": 1, "data": inner_data}
|
||||
if logger:
|
||||
logger.info(
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: tcp_messages.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12tcp_messages.proto\x12\x03tcp\"\x83\x01\n\x0cLoginRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\x12\x10\n\x08if_admin\x18\x03 \x01(\x08\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x0b\n\x03vol\x18\x05 \x01(\x01\x12\x0f\n\x07vol_per\x18\x06 \x01(\x01\x12\r\n\x05iccid\x18\x07 \x01(\t\"*\n\rLoginResponse\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\"4\n\tHeartbeat\x12\t\n\x01t\x18\x01 \x01(\x03\x12\x0b\n\x03vol\x18\x02 \x01(\x01\x12\x0f\n\x07vol_per\x18\x03 \x01(\x01\"&\n\tLogicBody\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\")\n\x0cResponseBody\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"@\n\x0bMonitorBody\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x10\n\x08msg_type\x18\x03 \x01(\r\",\n\x16MonitorDevicesResponse\x12\x12\n\ndevice_ids\x18\x01 \x03(\t\"9\n\x0bOtaFragment\x12\t\n\x01l\x18\x01 \x01(\x05\x12\t\n\x01\x64\x18\x02 \x01(\t\x12\t\n\x01t\x18\x03 \x01(\x05\x12\t\n\x01v\x18\x04 \x01(\t\"\xab\x02\n\tShootData\x12\x0f\n\x07shot_id\x18\x01 \x01(\t\x12\t\n\x01x\x18\x02 \x01(\x01\x12\t\n\x01y\x18\x03 \x01(\x01\x12\t\n\x01r\x18\x04 \x01(\x01\x12\t\n\x01\x64\x18\x05 \x01(\x01\x12\x0b\n\x03\x61\x64\x63\x18\x06 \x01(\x01\x12\x14\n\x0ctarget_class\x18\x07 \x01(\t\x12\x1f\n\x17target_class_confidence\x18\x08 \x01(\x01\x12\x0f\n\x07\x64_laser\x18\t \x01(\x01\x12\x17\n\x0f\x64_laser_quality\x18\n \x01(\x01\x12\t\n\x01m\x18\x0b \x01(\t\x12\x14\n\x0claser_method\x18\x0c \x01(\t\x12\x10\n\x08target_x\x18\r \x01(\x01\x12\x10\n\x08target_y\x18\x0e \x01(\x01\x12\x15\n\roffset_method\x18\x0f \x01(\t\x12\x17\n\x0f\x64istance_method\x18\x10 \x01(\t\"!\n\nShootEvent\x12\x13\n\x0bshoot_event\x18\x01 \x01(\t\"C\n\rBatteryReport\x12\x0f\n\x07\x62\x61ttery\x18\x01 \x01(\x01\x12\x0f\n\x07voltage\x18\x02 \x01(\x01\x12\x10\n\x08net_type\x18\x03 \x01(\t\"9\n\x11\x43\x65nterPointResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\t\n\x01x\x18\x02 \x01(\x01\x12\t\n\x01y\x18\x03 \x01(\x01\"3\n\x0e\x43\x65nterPointSet\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\x12\t\n\x01x\x18\x02 \x01(\x01\x12\t\n\x01y\x18\x03 \x01(\x01\"(\n\tOtaResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\"\x1f\n\rGenericResult\x12\x0e\n\x06result\x18\x01 \x01(\t\"&\n\x08IpReport\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\n\n\x02ip\x18\x02 \x01(\t\"Z\n\x12ImageUploadCommand\x12\x12\n\nupload_url\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x10\n\x08shoot_id\x18\x03 \x01(\t\x12\x0f\n\x07outlink\x18\x04 \x01(\t\"d\n\x10LogUploadCommand\x12\x12\n\nupload_url\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\x0f\n\x07outlink\x18\x04 \x01(\t\x12\x0f\n\x07\x61rchive\x18\x05 \x01(\t\"K\n\x0eOtaRequestData\x12\x0c\n\x04ssid\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\x0c\n\x04mode\x18\x04 \x01(\t\"1\n\x0fWifiConnectData\x12\x0c\n\x04ssid\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\"_\n\x11ImageUploadResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\x10\n\x08shoot_id\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\x0e\n\x06reason\x18\x04 \x01(\t\x12\x0b\n\x03via\x18\x05 \x01(\t\"v\n\x0fLogUploadResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t\x12\x13\n\x0bstatus_code\x18\x04 \x01(\x05\x12\x0c\n\x04ssid\x18\x05 \x01(\t\x12\x0e\n\x06\x64\x65tail\x18\x06 \x01(\t\"J\n\x14\x42\x61tteryQueryResponse\x12\x0f\n\x07\x62\x61ttery\x18\x01 \x01(\x01\x12\x0f\n\x07voltage\x18\x02 \x01(\x01\x12\x10\n\x08net_type\x18\x03 \x01(\t\"\'\n\x0fOta4gSubCodeReq\x12\t\n\x01l\x18\x01 \x01(\x05\x12\t\n\x01v\x18\x02 \x01(\t\"5\n\x10Ota4gSubCodeResp\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\x12\t\n\x01l\x18\x02 \x01(\x05\x12\t\n\x01v\x18\x03 \x01(\t\"\x1e\n\x0fShutdownCommand\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\" \n\x0c\x41utoShutdown\x12\x10\n\x08poweroff\x18\x01 \x01(\tBB\n\rcom.shoot.tcpZ1git.shelingxingqiu.com/shoot-tcp-server/proto;tcpb\x06proto3')
|
||||
|
||||
|
||||
|
||||
_LOGINREQUEST = DESCRIPTOR.message_types_by_name['LoginRequest']
|
||||
_LOGINRESPONSE = DESCRIPTOR.message_types_by_name['LoginResponse']
|
||||
_HEARTBEAT = DESCRIPTOR.message_types_by_name['Heartbeat']
|
||||
_LOGICBODY = DESCRIPTOR.message_types_by_name['LogicBody']
|
||||
_RESPONSEBODY = DESCRIPTOR.message_types_by_name['ResponseBody']
|
||||
_MONITORBODY = DESCRIPTOR.message_types_by_name['MonitorBody']
|
||||
_MONITORDEVICESRESPONSE = DESCRIPTOR.message_types_by_name['MonitorDevicesResponse']
|
||||
_OTAFRAGMENT = DESCRIPTOR.message_types_by_name['OtaFragment']
|
||||
_SHOOTDATA = DESCRIPTOR.message_types_by_name['ShootData']
|
||||
_SHOOTEVENT = DESCRIPTOR.message_types_by_name['ShootEvent']
|
||||
_BATTERYREPORT = DESCRIPTOR.message_types_by_name['BatteryReport']
|
||||
_CENTERPOINTRESULT = DESCRIPTOR.message_types_by_name['CenterPointResult']
|
||||
_CENTERPOINTSET = DESCRIPTOR.message_types_by_name['CenterPointSet']
|
||||
_OTARESULT = DESCRIPTOR.message_types_by_name['OtaResult']
|
||||
_GENERICRESULT = DESCRIPTOR.message_types_by_name['GenericResult']
|
||||
_IPREPORT = DESCRIPTOR.message_types_by_name['IpReport']
|
||||
_IMAGEUPLOADCOMMAND = DESCRIPTOR.message_types_by_name['ImageUploadCommand']
|
||||
_LOGUPLOADCOMMAND = DESCRIPTOR.message_types_by_name['LogUploadCommand']
|
||||
_OTAREQUESTDATA = DESCRIPTOR.message_types_by_name['OtaRequestData']
|
||||
_WIFICONNECTDATA = DESCRIPTOR.message_types_by_name['WifiConnectData']
|
||||
_IMAGEUPLOADRESULT = DESCRIPTOR.message_types_by_name['ImageUploadResult']
|
||||
_LOGUPLOADRESULT = DESCRIPTOR.message_types_by_name['LogUploadResult']
|
||||
_BATTERYQUERYRESPONSE = DESCRIPTOR.message_types_by_name['BatteryQueryResponse']
|
||||
_OTA4GSUBCODEREQ = DESCRIPTOR.message_types_by_name['Ota4gSubCodeReq']
|
||||
_OTA4GSUBCODERESP = DESCRIPTOR.message_types_by_name['Ota4gSubCodeResp']
|
||||
_SHUTDOWNCOMMAND = DESCRIPTOR.message_types_by_name['ShutdownCommand']
|
||||
_AUTOSHUTDOWN = DESCRIPTOR.message_types_by_name['AutoShutdown']
|
||||
LoginRequest = _reflection.GeneratedProtocolMessageType('LoginRequest', (_message.Message,), {
|
||||
'DESCRIPTOR' : _LOGINREQUEST,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.LoginRequest)
|
||||
})
|
||||
_sym_db.RegisterMessage(LoginRequest)
|
||||
|
||||
LoginResponse = _reflection.GeneratedProtocolMessageType('LoginResponse', (_message.Message,), {
|
||||
'DESCRIPTOR' : _LOGINRESPONSE,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.LoginResponse)
|
||||
})
|
||||
_sym_db.RegisterMessage(LoginResponse)
|
||||
|
||||
Heartbeat = _reflection.GeneratedProtocolMessageType('Heartbeat', (_message.Message,), {
|
||||
'DESCRIPTOR' : _HEARTBEAT,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.Heartbeat)
|
||||
})
|
||||
_sym_db.RegisterMessage(Heartbeat)
|
||||
|
||||
LogicBody = _reflection.GeneratedProtocolMessageType('LogicBody', (_message.Message,), {
|
||||
'DESCRIPTOR' : _LOGICBODY,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.LogicBody)
|
||||
})
|
||||
_sym_db.RegisterMessage(LogicBody)
|
||||
|
||||
ResponseBody = _reflection.GeneratedProtocolMessageType('ResponseBody', (_message.Message,), {
|
||||
'DESCRIPTOR' : _RESPONSEBODY,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.ResponseBody)
|
||||
})
|
||||
_sym_db.RegisterMessage(ResponseBody)
|
||||
|
||||
MonitorBody = _reflection.GeneratedProtocolMessageType('MonitorBody', (_message.Message,), {
|
||||
'DESCRIPTOR' : _MONITORBODY,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.MonitorBody)
|
||||
})
|
||||
_sym_db.RegisterMessage(MonitorBody)
|
||||
|
||||
MonitorDevicesResponse = _reflection.GeneratedProtocolMessageType('MonitorDevicesResponse', (_message.Message,), {
|
||||
'DESCRIPTOR' : _MONITORDEVICESRESPONSE,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.MonitorDevicesResponse)
|
||||
})
|
||||
_sym_db.RegisterMessage(MonitorDevicesResponse)
|
||||
|
||||
OtaFragment = _reflection.GeneratedProtocolMessageType('OtaFragment', (_message.Message,), {
|
||||
'DESCRIPTOR' : _OTAFRAGMENT,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.OtaFragment)
|
||||
})
|
||||
_sym_db.RegisterMessage(OtaFragment)
|
||||
|
||||
ShootData = _reflection.GeneratedProtocolMessageType('ShootData', (_message.Message,), {
|
||||
'DESCRIPTOR' : _SHOOTDATA,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.ShootData)
|
||||
})
|
||||
_sym_db.RegisterMessage(ShootData)
|
||||
|
||||
ShootEvent = _reflection.GeneratedProtocolMessageType('ShootEvent', (_message.Message,), {
|
||||
'DESCRIPTOR' : _SHOOTEVENT,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.ShootEvent)
|
||||
})
|
||||
_sym_db.RegisterMessage(ShootEvent)
|
||||
|
||||
BatteryReport = _reflection.GeneratedProtocolMessageType('BatteryReport', (_message.Message,), {
|
||||
'DESCRIPTOR' : _BATTERYREPORT,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.BatteryReport)
|
||||
})
|
||||
_sym_db.RegisterMessage(BatteryReport)
|
||||
|
||||
CenterPointResult = _reflection.GeneratedProtocolMessageType('CenterPointResult', (_message.Message,), {
|
||||
'DESCRIPTOR' : _CENTERPOINTRESULT,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.CenterPointResult)
|
||||
})
|
||||
_sym_db.RegisterMessage(CenterPointResult)
|
||||
|
||||
CenterPointSet = _reflection.GeneratedProtocolMessageType('CenterPointSet', (_message.Message,), {
|
||||
'DESCRIPTOR' : _CENTERPOINTSET,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.CenterPointSet)
|
||||
})
|
||||
_sym_db.RegisterMessage(CenterPointSet)
|
||||
|
||||
OtaResult = _reflection.GeneratedProtocolMessageType('OtaResult', (_message.Message,), {
|
||||
'DESCRIPTOR' : _OTARESULT,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.OtaResult)
|
||||
})
|
||||
_sym_db.RegisterMessage(OtaResult)
|
||||
|
||||
GenericResult = _reflection.GeneratedProtocolMessageType('GenericResult', (_message.Message,), {
|
||||
'DESCRIPTOR' : _GENERICRESULT,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.GenericResult)
|
||||
})
|
||||
_sym_db.RegisterMessage(GenericResult)
|
||||
|
||||
IpReport = _reflection.GeneratedProtocolMessageType('IpReport', (_message.Message,), {
|
||||
'DESCRIPTOR' : _IPREPORT,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.IpReport)
|
||||
})
|
||||
_sym_db.RegisterMessage(IpReport)
|
||||
|
||||
ImageUploadCommand = _reflection.GeneratedProtocolMessageType('ImageUploadCommand', (_message.Message,), {
|
||||
'DESCRIPTOR' : _IMAGEUPLOADCOMMAND,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.ImageUploadCommand)
|
||||
})
|
||||
_sym_db.RegisterMessage(ImageUploadCommand)
|
||||
|
||||
LogUploadCommand = _reflection.GeneratedProtocolMessageType('LogUploadCommand', (_message.Message,), {
|
||||
'DESCRIPTOR' : _LOGUPLOADCOMMAND,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.LogUploadCommand)
|
||||
})
|
||||
_sym_db.RegisterMessage(LogUploadCommand)
|
||||
|
||||
OtaRequestData = _reflection.GeneratedProtocolMessageType('OtaRequestData', (_message.Message,), {
|
||||
'DESCRIPTOR' : _OTAREQUESTDATA,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.OtaRequestData)
|
||||
})
|
||||
_sym_db.RegisterMessage(OtaRequestData)
|
||||
|
||||
WifiConnectData = _reflection.GeneratedProtocolMessageType('WifiConnectData', (_message.Message,), {
|
||||
'DESCRIPTOR' : _WIFICONNECTDATA,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.WifiConnectData)
|
||||
})
|
||||
_sym_db.RegisterMessage(WifiConnectData)
|
||||
|
||||
ImageUploadResult = _reflection.GeneratedProtocolMessageType('ImageUploadResult', (_message.Message,), {
|
||||
'DESCRIPTOR' : _IMAGEUPLOADRESULT,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.ImageUploadResult)
|
||||
})
|
||||
_sym_db.RegisterMessage(ImageUploadResult)
|
||||
|
||||
LogUploadResult = _reflection.GeneratedProtocolMessageType('LogUploadResult', (_message.Message,), {
|
||||
'DESCRIPTOR' : _LOGUPLOADRESULT,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.LogUploadResult)
|
||||
})
|
||||
_sym_db.RegisterMessage(LogUploadResult)
|
||||
|
||||
BatteryQueryResponse = _reflection.GeneratedProtocolMessageType('BatteryQueryResponse', (_message.Message,), {
|
||||
'DESCRIPTOR' : _BATTERYQUERYRESPONSE,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.BatteryQueryResponse)
|
||||
})
|
||||
_sym_db.RegisterMessage(BatteryQueryResponse)
|
||||
|
||||
Ota4gSubCodeReq = _reflection.GeneratedProtocolMessageType('Ota4gSubCodeReq', (_message.Message,), {
|
||||
'DESCRIPTOR' : _OTA4GSUBCODEREQ,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.Ota4gSubCodeReq)
|
||||
})
|
||||
_sym_db.RegisterMessage(Ota4gSubCodeReq)
|
||||
|
||||
Ota4gSubCodeResp = _reflection.GeneratedProtocolMessageType('Ota4gSubCodeResp', (_message.Message,), {
|
||||
'DESCRIPTOR' : _OTA4GSUBCODERESP,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.Ota4gSubCodeResp)
|
||||
})
|
||||
_sym_db.RegisterMessage(Ota4gSubCodeResp)
|
||||
|
||||
ShutdownCommand = _reflection.GeneratedProtocolMessageType('ShutdownCommand', (_message.Message,), {
|
||||
'DESCRIPTOR' : _SHUTDOWNCOMMAND,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.ShutdownCommand)
|
||||
})
|
||||
_sym_db.RegisterMessage(ShutdownCommand)
|
||||
|
||||
AutoShutdown = _reflection.GeneratedProtocolMessageType('AutoShutdown', (_message.Message,), {
|
||||
'DESCRIPTOR' : _AUTOSHUTDOWN,
|
||||
'__module__' : 'tcp_messages_pb2'
|
||||
# @@protoc_insertion_point(class_scope:tcp.AutoShutdown)
|
||||
})
|
||||
_sym_db.RegisterMessage(AutoShutdown)
|
||||
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\rcom.shoot.tcpZ1git.shelingxingqiu.com/shoot-tcp-server/proto;tcp'
|
||||
_LOGINREQUEST._serialized_start=28
|
||||
_LOGINREQUEST._serialized_end=159
|
||||
_LOGINRESPONSE._serialized_start=161
|
||||
_LOGINRESPONSE._serialized_end=203
|
||||
_HEARTBEAT._serialized_start=205
|
||||
_HEARTBEAT._serialized_end=257
|
||||
_LOGICBODY._serialized_start=259
|
||||
_LOGICBODY._serialized_end=297
|
||||
_RESPONSEBODY._serialized_start=299
|
||||
_RESPONSEBODY._serialized_end=340
|
||||
_MONITORBODY._serialized_start=342
|
||||
_MONITORBODY._serialized_end=406
|
||||
_MONITORDEVICESRESPONSE._serialized_start=408
|
||||
_MONITORDEVICESRESPONSE._serialized_end=452
|
||||
_OTAFRAGMENT._serialized_start=454
|
||||
_OTAFRAGMENT._serialized_end=511
|
||||
_SHOOTDATA._serialized_start=514
|
||||
_SHOOTDATA._serialized_end=813
|
||||
_SHOOTEVENT._serialized_start=815
|
||||
_SHOOTEVENT._serialized_end=848
|
||||
_BATTERYREPORT._serialized_start=850
|
||||
_BATTERYREPORT._serialized_end=917
|
||||
_CENTERPOINTRESULT._serialized_start=919
|
||||
_CENTERPOINTRESULT._serialized_end=976
|
||||
_CENTERPOINTSET._serialized_start=978
|
||||
_CENTERPOINTSET._serialized_end=1029
|
||||
_OTARESULT._serialized_start=1031
|
||||
_OTARESULT._serialized_end=1071
|
||||
_GENERICRESULT._serialized_start=1073
|
||||
_GENERICRESULT._serialized_end=1104
|
||||
_IPREPORT._serialized_start=1106
|
||||
_IPREPORT._serialized_end=1144
|
||||
_IMAGEUPLOADCOMMAND._serialized_start=1146
|
||||
_IMAGEUPLOADCOMMAND._serialized_end=1236
|
||||
_LOGUPLOADCOMMAND._serialized_start=1238
|
||||
_LOGUPLOADCOMMAND._serialized_end=1338
|
||||
_OTAREQUESTDATA._serialized_start=1340
|
||||
_OTAREQUESTDATA._serialized_end=1415
|
||||
_WIFICONNECTDATA._serialized_start=1417
|
||||
_WIFICONNECTDATA._serialized_end=1466
|
||||
_IMAGEUPLOADRESULT._serialized_start=1468
|
||||
_IMAGEUPLOADRESULT._serialized_end=1563
|
||||
_LOGUPLOADRESULT._serialized_start=1565
|
||||
_LOGUPLOADRESULT._serialized_end=1683
|
||||
_BATTERYQUERYRESPONSE._serialized_start=1685
|
||||
_BATTERYQUERYRESPONSE._serialized_end=1759
|
||||
_OTA4GSUBCODEREQ._serialized_start=1761
|
||||
_OTA4GSUBCODEREQ._serialized_end=1800
|
||||
_OTA4GSUBCODERESP._serialized_start=1802
|
||||
_OTA4GSUBCODERESP._serialized_end=1855
|
||||
_SHUTDOWNCOMMAND._serialized_start=1857
|
||||
_SHUTDOWNCOMMAND._serialized_end=1887
|
||||
_AUTOSHUTDOWN._serialized_start=1889
|
||||
_AUTOSHUTDOWN._serialized_end=1921
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
Binary file not shown.
+1
-5
@@ -30,8 +30,4 @@
|
||||
# 2.15.17 修复wifi连接问题
|
||||
# 2.15.18 wifi连接成功重新登录
|
||||
# 2.16.4 优化射箭延迟
|
||||
# 2.17.0 yolo标靶类别识别
|
||||
# 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.0 yolo标靶类别识别
|
||||
+1
-1
@@ -4,6 +4,6 @@
|
||||
应用版本号
|
||||
每次 OTA 更新时,只需要更新这个文件中的版本号
|
||||
"""
|
||||
VERSION = '2.17.14'
|
||||
VERSION = '3.0.5'
|
||||
|
||||
|
||||
|
||||
@@ -902,16 +902,13 @@ def _save_shot_image_impl(img_cv, center, radius, method, ellipse_params,
|
||||
|
||||
|
||||
def _save_worker_loop():
|
||||
"""存图 worker:处理标注图和可选的纯原图任务。"""
|
||||
"""存图 worker:从队列取任务并调用 _save_shot_image_impl。"""
|
||||
while True:
|
||||
try:
|
||||
item = _save_queue.get()
|
||||
if item is None:
|
||||
break
|
||||
if isinstance(item, dict) and item.get("kind") == "raw":
|
||||
_save_raw_image_impl(item["img_cv"], item["shot_id"], item["photo_dir"])
|
||||
else:
|
||||
_save_shot_image_impl(*item)
|
||||
_save_shot_image_impl(*item)
|
||||
except Exception as e:
|
||||
logger = logger_manager.logger
|
||||
if logger:
|
||||
@@ -939,52 +936,6 @@ def start_save_shot_worker():
|
||||
logger.info("[VISION] 存图 worker 线程已启动")
|
||||
|
||||
|
||||
def _save_raw_image_impl(img_cv, shot_id, photo_dir):
|
||||
"""保存未标注、未裁剪的完整原始帧。"""
|
||||
logger = logger_manager.logger
|
||||
try:
|
||||
os.makedirs(photo_dir, exist_ok=True)
|
||||
filename = os.path.join(photo_dir, f"shot_{shot_id}_raw.jpg")
|
||||
image.cv2image(img_cv, False, False).save(filename)
|
||||
prune_old_images_in_dir(
|
||||
photo_dir,
|
||||
getattr(config, "RAW_IMAGE_MAX_IMAGES", config.MAX_IMAGES),
|
||||
logger,
|
||||
"[VISION-RAW]",
|
||||
)
|
||||
if logger:
|
||||
logger.info(f"[VISION-RAW] 已保存纯原图: {filename}")
|
||||
return filename
|
||||
except Exception as e:
|
||||
if logger:
|
||||
logger.error(f"[VISION-RAW] 保存纯原图失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def enqueue_save_raw_shot(frame, shot_id, photo_dir=None):
|
||||
"""复制并异步保存原始帧;由 SAVE_RAW_IMAGE_ENABLED 控制是否启用。"""
|
||||
if not getattr(config, "SAVE_RAW_IMAGE_ENABLED", False):
|
||||
return
|
||||
if photo_dir is None:
|
||||
photo_dir = getattr(config, "RAW_IMAGE_DIR", os.path.join(config.PHOTO_DIR, "raw"))
|
||||
try:
|
||||
img_copy = np.copy(image.image2cv(frame, False, False))
|
||||
_save_queue.put_nowait({
|
||||
"kind": "raw",
|
||||
"img_cv": img_copy,
|
||||
"shot_id": shot_id,
|
||||
"photo_dir": photo_dir,
|
||||
})
|
||||
except queue.Full:
|
||||
logger = logger_manager.logger
|
||||
if logger:
|
||||
logger.warning("[VISION-RAW] 存图队列已满,跳过本次纯原图保存")
|
||||
except Exception as e:
|
||||
logger = logger_manager.logger
|
||||
if logger:
|
||||
logger.error(f"[VISION-RAW] 复制纯原图失败: {e}")
|
||||
|
||||
|
||||
def enqueue_save_shot(result_img, center, radius, method, ellipse_params,
|
||||
laser_point, distance_m, shot_id=None, photo_dir=None,
|
||||
yolo_roi_xyxy=None, force_save=False):
|
||||
|
||||
Reference in New Issue
Block a user