From a009fe9bb5eb207b4ec683095df5459955448dd8 Mon Sep 17 00:00:00 2001 From: ywb <347742090@qq.com> Date: Fri, 29 May 2026 15:09:34 +0800 Subject: [PATCH] - --- agv_app/__pycache__/app.cpython-312.pyc | Bin 91918 -> 91969 bytes agv_app/static/js/running.js | 33 +++++++++++------- agv_app/utils/mission_executor.py | 43 ++++++++++++++++++------ 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/agv_app/__pycache__/app.cpython-312.pyc b/agv_app/__pycache__/app.cpython-312.pyc index 08361e93fc1a452ab605b3152a2b298eb3dc72ba..47ecec135a0b4892e048be677a8b113b4d403805 100644 GIT binary patch delta 71 zcmeA>$9nJ_>xP}uCYJi4#i>Qb`uU}miFxVesd-76dHQ;V$vKJT`sMjW*~JBk$*KB5 b`APXD`ibdf@reZm`pvtfx9^f>4Dkj41{@pJ delta 20 ccmX?jjxP}ujBL$srMJJ8W(@HL0AT_MYXATM diff --git a/agv_app/static/js/running.js b/agv_app/static/js/running.js index 7757013..9ebe055 100644 --- a/agv_app/static/js/running.js +++ b/agv_app/static/js/running.js @@ -134,19 +134,28 @@ createApp({ this.progress = 0 this.report = null this.showQrModal = false - await fetch(API + '/api/mission/start', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - agv_move: this.agvMoveEnabled, - qr_scan: this.qrScanEnabled, - front_photo: this.frontPhotoEnabled, - back_photo: this.backPhotoEnabled, - agv_speed: this.agvSpeed, - arm_speed: this.armSpeed, + try { + const res = await fetch(API + '/api/mission/start', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + agv_move: this.agvMoveEnabled, + qr_scan: this.qrScanEnabled, + front_photo: this.frontPhotoEnabled, + back_photo: this.backPhotoEnabled, + agv_speed: this.agvSpeed, + arm_speed: this.armSpeed, + }) }) - }) - this.missionState = 'running' + const data = await res.json() + if (!data.ok) { + alert('❌ 启动失败: ' + (data.error || '未知错误')) + return + } + this.missionState = 'running' + } catch (e) { + alert('❌ 启动请求失败: ' + e.message) + } }, async startSingleStep() { if (this.missionState !== 'idle') return diff --git a/agv_app/utils/mission_executor.py b/agv_app/utils/mission_executor.py index 98b212c..052cd06 100644 --- a/agv_app/utils/mission_executor.py +++ b/agv_app/utils/mission_executor.py @@ -358,7 +358,7 @@ class MissionExecutorV3: self.report["machine_status"][mk]["status"] = "active" self.report["machine_status"][mk]["step"] = "正面扫码" 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(): break else: @@ -371,6 +371,7 @@ class MissionExecutorV3: self.report["machine_status"][mk2]["qr_val"] = qr_value self.report["machine_status"][mk2]["step"] = "正面拍照" + task = self._get_task(pr, c) if task and qr_value: task["qr_value"] = qr_value @@ -383,7 +384,7 @@ class MissionExecutorV3: if opt_front_photo and not self._stop.is_set(): model = self._find_model(models, model_name) 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: self._log(f" ⚠️ 未找到机型 {model_name}") else: @@ -414,7 +415,7 @@ class MissionExecutorV3: if opt_back_photo and not self._stop.is_set(): model = self._find_model(models, model_name) 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: self._log(f" ⚠️ 未找到机型 {model_name}") else: @@ -626,11 +627,18 @@ class MissionExecutorV3: time.sleep(0.5) self._log(f" ⚠️ 机械臂稳定等待超时 (target={target_angles})") return False - def _scan_qr_with_poses(self, qr_configs: list) -> Optional[str]: - """用二维码配置中的姿态依次尝试,逐一调整姿态+等2秒+扫码,全部失败才弹框""" + def _scan_qr_with_poses(self, qr_configs: list, machine_row: int = 0) -> Optional[str]: + """用二维码配置中的姿态依次尝试,逐一调整姿态+等2秒+扫码,全部失败才弹框 + + machine_row: 机器所在行,奇数行(1,3,5)时关节角度需取反 + """ if not qr_configs: self._log(f" ⚠️ 无二维码配置") return self._request_manual_qr() + # 判断是否需要反转关节角度 + invert = (machine_row % 2 == 1) + if invert: + self._log(f" 🔄 扫码:AGV朝向相反,关节角度取反") self._log(f" 🔍 尝试 {len(qr_configs)} 个二维码姿态...") for i, qc in enumerate(qr_configs): if self._stop.is_set(): @@ -639,8 +647,11 @@ class MissionExecutorV3: angles = qc.get("joint_angles", []) if not angles or len(angles) < 6: continue + # 需要时反转关节角度 + if invert: + angles = [-a for a in angles] 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: 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): - """按机型配置的所有姿态依次拍照""" - # 更新任务照片计数 - task = self._get_task(row - 1, col - 1) + def _shoot(self, model: dict, side: str, row: int, col: int, qr_value: str, machine_row: int = 0): + """按机型配置的所有姿态依次拍照 + + machine_row: 当前操作的机器所在行,用于判断是否需要关节反转 + 蛇形路径下,AGV 朝向在奇数行(1,3,5)时与出发时相反, + 此时机器的正面/背面朝向与标定相反,需要把所有关节角度取反 + """ + # 判断是否需要反转关节角度(AGV 朝向与出发时相反) + invert = (machine_row % 2 == 1) # 机器行是奇数(1,3,5...)时,AGV从对面来,需反转 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", []) if not poses: self._log(f" ⚠️ 机型无{side_label}姿态配置") @@ -737,8 +755,11 @@ class MissionExecutorV3: self._log(f" 跳过 {pose.get('name', f'姿态{pi+1}')}: 无效角度") continue + # 需要时对所有关节角度取反 + if invert: + angles = [-a for a in angles] name = pose.get("name", f"{side_label}-{pi+1}") - self._log(f" 🎯 {name}") + self._log(f" 🎯 {name}{' (反转)' if invert else ''}") # 调整机械臂 if self.arm_client: