照片上传

This commit is contained in:
ywb
2026-05-29 18:22:02 +08:00
parent a009fe9bb5
commit 0d0dd15853
+54 -11
View File
@@ -31,11 +31,12 @@ ROS2_SETUP_CMD = "source /opt/ros/humble/setup.bash && source ~/agv_pro_ros2/ins
from config import ARM_CAMERA_CONFIG from config import ARM_CAMERA_CONFIG
ARM_CAMERA_SNAPSHOT = ARM_CAMERA_CONFIG["snapshot_url"] ARM_CAMERA_SNAPSHOT = ARM_CAMERA_CONFIG["snapshot_url"]
PHOTOS_DIR = "/home/elephant/photos" PHOTOS_DIR = "/home/elephant/photos"
UPLOAD_URL = "https://ts.zhijian168.com/prod-api/file/uploadImage"
# 二维码扫描重试参数 # 二维码扫描重试参数
QR_SCAN_TIMEOUT = 5 # 单次扫描超时 QR_SCAN_TIMEOUT = 5 # 单次扫描超时
QR_POSE_WAIT = 1.5 # 调整姿态后等待时间 QR_POSE_WAIT = 1.5 # 调整姿态后等待时间
MANUAL_QR_TIMEOUT = 300 # 5分钟超时 MANUAL_QR_TIMEOUT = 300 # 5分钟超时(现已改为无限等待,stop 时解除)
class MissionStatus(str, Enum): class MissionStatus(str, Enum):
@@ -111,6 +112,9 @@ class MissionExecutorV3:
self.arm_speed = 500 self.arm_speed = 500
self.agv_speed = 0.5 self.agv_speed = 0.5
# 照片上传序号计数器(连续递增,从1开始)
self.next_upload_index = 1
# ==================== 连接 ==================== # ==================== 连接 ====================
def connect_all(self) -> Dict[str, bool]: def connect_all(self) -> Dict[str, bool]:
@@ -242,6 +246,9 @@ class MissionExecutorV3:
self._log(f"📍 点位蛇形路径: {len(path)} 个点位, {total_machines} 台机器") self._log(f"📍 点位蛇形路径: {len(path)} 个点位, {total_machines} 台机器")
# 重置照片上传序号(每次任务开始时重置,从1开始)
self.next_upload_index = 1
# 任务步骤控制开关 # 任务步骤控制开关
if options is None: if options is None:
options = {} options = {}
@@ -688,22 +695,21 @@ class MissionExecutorV3:
return None return None
def _request_manual_qr(self) -> Optional[str]: def _request_manual_qr(self) -> Optional[str]:
"""暂停任务,等待手动输入""" """暂停任务,等待手动输入(不超时,必须输入才能继续;stop 时解除)"""
self.status = MissionStatus.WAITING_QR self.status = MissionStatus.WAITING_QR
self.report["status"] = "waiting_qr" self.report["status"] = "waiting_qr"
self.report["step"] = "等待手动输入二维码" self.report["step"] = "等待手动输入二维码"
self._log(" ⌨️ 弹窗等待手动输入二维码...") self._log(" ⌨️ 弹窗等待手动输入二维码(不可跳过)...")
self._qr_event.clear() self._qr_event.clear()
if self._qr_event.wait(timeout=MANUAL_QR_TIMEOUT): self._qr_event.wait() # 无限等待,直到 set_manual_qr 或 stop() 触发
self.status = MissionStatus.RUNNING self.status = MissionStatus.RUNNING
self.report["status"] = "running" self.report["status"] = "running"
if self._qr_value:
self._log(f" ✏️ 手动输入: {self._qr_value}") self._log(f" ✏️ 手动输入: {self._qr_value}")
return self._qr_value return self._qr_value
else: else:
self.status = MissionStatus.RUNNING self._log(f" ⚠️ 任务已停止")
self.report["status"] = "running"
self._log(f" ⚠️ 等待超时({MANUAL_QR_TIMEOUT}s),跳过")
return None return None
def set_manual_qr(self, value: str): def set_manual_qr(self, value: str):
@@ -766,14 +772,19 @@ class MissionExecutorV3:
self.arm_client.set_angles(angles, speed=self.arm_speed) self.arm_client.set_angles(angles, speed=self.arm_speed)
self._wait_arm_ready(angles) self._wait_arm_ready(angles)
# 拍照 # 拍照upload_index 连续递增)
path = self._capture_arm_photo(row, col, side, pi + 1, qr_value) path = self._capture_arm_photo(row, col, side, pi + 1, qr_value, upload_index=self.next_upload_index)
self.next_upload_index += 1
if path: if path:
self._log(f" 💾 {os.path.basename(path)}") self._log(f" 💾 {os.path.basename(path)}")
def _capture_arm_photo(self, row: int, col: int, side: str, def _capture_arm_photo(self, row: int, col: int, side: str,
pose_idx: int, qr_value: str) -> Optional[str]: pose_idx: int, qr_value: str,
"""从机械臂摄像头拍照存本地""" upload_index: int = 0) -> Optional[str]:
"""从机械臂摄像头拍照存本地,然后上传到服务器
upload_index: 从1开始,先正面后背面,由调用方维护
"""
try: try:
resp = requests.get(ARM_CAMERA_SNAPSHOT, timeout=10) resp = requests.get(ARM_CAMERA_SNAPSHOT, timeout=10)
if resp.status_code != 200 or not resp.content: if resp.status_code != 200 or not resp.content:
@@ -786,11 +797,43 @@ class MissionExecutorV3:
fpath = os.path.join(PHOTOS_DIR, fname) fpath = os.path.join(PHOTOS_DIR, fname)
with open(fpath, "wb") as f: with open(fpath, "wb") as f:
f.write(resp.content) f.write(resp.content)
self._log(f" 💾 本地保存: {os.path.basename(fpath)}")
# 上传到服务器
if qr_value:
self._upload_photo(fpath, qr_value, upload_index)
else:
self._log(" ⚠️ 无二维码,跳过上传")
return fpath return fpath
except Exception as e: except Exception as e:
logger.error(f"拍照异常: {e}") logger.error(f"拍照异常: {e}")
return None return None
def _upload_photo(self, filepath: str, serial_number: str, index: int) -> bool:
"""上传照片到远程服务器
Args:
filepath: 本地文件路径
serial_number: 二维码/序列号
index: 1=正面, 2=背面
"""
try:
filename = os.path.basename(filepath)
with open(filepath, "rb") as f:
files = {"file": (filename, f, "image/jpeg")}
data = {"serialNumber": serial_number, "index": str(index)}
resp = requests.post(UPLOAD_URL, files=files, data=data, timeout=30)
if resp.status_code == 200:
self._log(f" ☁️ 上传成功 [{index}]: {filename}")
return True
else:
self._log(f" ⚠️ 上传失败 [{index}] HTTP {resp.status_code}: {resp.text[:200]}")
return False
except Exception as e:
self._log(f" ❌ 上传异常 [{index}]: {e}")
return False
# ==================== 控制 ==================== # ==================== 控制 ====================
def _wait_pause(self): def _wait_pause(self):