This commit is contained in:
ywb
2026-05-29 15:09:34 +08:00
parent f64068475f
commit a009fe9bb5
3 changed files with 53 additions and 23 deletions
Binary file not shown.
+10 -1
View File
@@ -134,7 +134,8 @@ createApp({
this.progress = 0 this.progress = 0
this.report = null this.report = null
this.showQrModal = false this.showQrModal = false
await fetch(API + '/api/mission/start', { try {
const res = await fetch(API + '/api/mission/start', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
@@ -146,7 +147,15 @@ createApp({
arm_speed: this.armSpeed, arm_speed: this.armSpeed,
}) })
}) })
const data = await res.json()
if (!data.ok) {
alert('❌ 启动失败: ' + (data.error || '未知错误'))
return
}
this.missionState = 'running' this.missionState = 'running'
} catch (e) {
alert('❌ 启动请求失败: ' + e.message)
}
}, },
async startSingleStep() { async startSingleStep() {
if (this.missionState !== 'idle') return if (this.missionState !== 'idle') return
+32 -11
View File
@@ -358,7 +358,7 @@ class MissionExecutorV3:
self.report["machine_status"][mk]["status"] = "active" self.report["machine_status"][mk]["status"] = "active"
self.report["machine_status"][mk]["step"] = "正面扫码" self.report["machine_status"][mk]["step"] = "正面扫码"
if opt_qr_scan: if opt_qr_scan:
qr_value = self._scan_qr_with_poses(qr_configs) qr_value = self._scan_qr_with_poses(qr_configs, machine_row=pr)
if self._stop.is_set(): if self._stop.is_set():
break break
else: else:
@@ -371,6 +371,7 @@ class MissionExecutorV3:
self.report["machine_status"][mk2]["qr_val"] = qr_value self.report["machine_status"][mk2]["qr_val"] = qr_value
self.report["machine_status"][mk2]["step"] = "正面拍照" self.report["machine_status"][mk2]["step"] = "正面拍照"
task = self._get_task(pr, c) task = self._get_task(pr, c)
if task and qr_value: if task and qr_value:
task["qr_value"] = qr_value task["qr_value"] = qr_value
@@ -383,7 +384,7 @@ class MissionExecutorV3:
if opt_front_photo and not self._stop.is_set(): if opt_front_photo and not self._stop.is_set():
model = self._find_model(models, model_name) model = self._find_model(models, model_name)
if model: if model:
self._shoot(model, "front", rl_front, cl_front, qr_value or "unknown") self._shoot(model, "front", rl_front, cl_front, qr_value or "unknown", pr)
else: else:
self._log(f" ⚠️ 未找到机型 {model_name}") self._log(f" ⚠️ 未找到机型 {model_name}")
else: else:
@@ -414,7 +415,7 @@ class MissionExecutorV3:
if opt_back_photo and not self._stop.is_set(): if opt_back_photo and not self._stop.is_set():
model = self._find_model(models, model_name) model = self._find_model(models, model_name)
if model: if model:
self._shoot(model, "back", rl_back, cl_back, back_qr) self._shoot(model, "back", rl_back, cl_back, back_qr, pr - 1)
else: else:
self._log(f" ⚠️ 未找到机型 {model_name}") self._log(f" ⚠️ 未找到机型 {model_name}")
else: else:
@@ -626,11 +627,18 @@ class MissionExecutorV3:
time.sleep(0.5) time.sleep(0.5)
self._log(f" ⚠️ 机械臂稳定等待超时 (target={target_angles})") self._log(f" ⚠️ 机械臂稳定等待超时 (target={target_angles})")
return False return False
def _scan_qr_with_poses(self, qr_configs: list) -> Optional[str]: def _scan_qr_with_poses(self, qr_configs: list, machine_row: int = 0) -> Optional[str]:
"""用二维码配置中的姿态依次尝试,逐一调整姿态+等2秒+扫码,全部失败才弹框""" """用二维码配置中的姿态依次尝试,逐一调整姿态+等2秒+扫码,全部失败才弹框
machine_row: 机器所在行,奇数行(1,3,5)时关节角度需取反
"""
if not qr_configs: if not qr_configs:
self._log(f" ⚠️ 无二维码配置") self._log(f" ⚠️ 无二维码配置")
return self._request_manual_qr() return self._request_manual_qr()
# 判断是否需要反转关节角度
invert = (machine_row % 2 == 1)
if invert:
self._log(f" 🔄 扫码:AGV朝向相反,关节角度取反")
self._log(f" 🔍 尝试 {len(qr_configs)} 个二维码姿态...") self._log(f" 🔍 尝试 {len(qr_configs)} 个二维码姿态...")
for i, qc in enumerate(qr_configs): for i, qc in enumerate(qr_configs):
if self._stop.is_set(): if self._stop.is_set():
@@ -639,8 +647,11 @@ class MissionExecutorV3:
angles = qc.get("joint_angles", []) angles = qc.get("joint_angles", [])
if not angles or len(angles) < 6: if not angles or len(angles) < 6:
continue continue
# 需要时反转关节角度
if invert:
angles = [-a for a in angles]
name = qc.get("name", f"姿态{i+1}") name = qc.get("name", f"姿态{i+1}")
self._log(f" [{i+1}/{len(qr_configs)}] {name}") self._log(f" [{i+1}/{len(qr_configs)}] {name}{' (反转)' if invert else ''}")
# 调整机械臂姿态 # 调整机械臂姿态
if self.arm_client: if self.arm_client:
self.arm_client.set_angles(angles, speed=self.arm_speed) self.arm_client.set_angles(angles, speed=self.arm_speed)
@@ -716,11 +727,18 @@ class MissionExecutorV3:
# ==================== 姿态拍照 ==================== # ==================== 姿态拍照 ====================
def _shoot(self, model: dict, side: str, row: int, col: int, qr_value: str): def _shoot(self, model: dict, side: str, row: int, col: int, qr_value: str, machine_row: int = 0):
"""按机型配置的所有姿态依次拍照""" """按机型配置的所有姿态依次拍照
# 更新任务照片计数
task = self._get_task(row - 1, col - 1) machine_row: 当前操作的机器所在行,用于判断是否需要关节反转
蛇形路径下,AGV 朝向在奇数行(1,3,5)时与出发时相反,
此时机器的正面/背面朝向与标定相反,需要把所有关节角度取反
"""
# 判断是否需要反转关节角度(AGV 朝向与出发时相反)
invert = (machine_row % 2 == 1) # 机器行是奇数(1,3,5...)时,AGV从对面来,需反转
side_label = "正面" if side == "front" else "背面" side_label = "正面" if side == "front" else "背面"
if invert:
self._log(f" 🔄 {side_label}拍摄:AGV朝向相反,关节角度取反")
poses = model.get("poses", []) if side == "front" else model.get("poses_back", []) poses = model.get("poses", []) if side == "front" else model.get("poses_back", [])
if not poses: if not poses:
self._log(f" ⚠️ 机型无{side_label}姿态配置") self._log(f" ⚠️ 机型无{side_label}姿态配置")
@@ -737,8 +755,11 @@ class MissionExecutorV3:
self._log(f" 跳过 {pose.get('name', f'姿态{pi+1}')}: 无效角度") self._log(f" 跳过 {pose.get('name', f'姿态{pi+1}')}: 无效角度")
continue continue
# 需要时对所有关节角度取反
if invert:
angles = [-a for a in angles]
name = pose.get("name", f"{side_label}-{pi+1}") name = pose.get("name", f"{side_label}-{pi+1}")
self._log(f" 🎯 {name}") self._log(f" 🎯 {name}{' (反转)' if invert else ''}")
# 调整机械臂 # 调整机械臂
if self.arm_client: if self.arm_client: