-
This commit is contained in:
@@ -857,13 +857,51 @@ createApp({
|
|||||||
body: JSON.stringify({ joint: 'J' + (idx + 1), angle: val })
|
body: JSON.stringify({ joint: 'J' + (idx + 1), angle: val })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async applyAngles() {
|
async applyAngles(angles = null) {
|
||||||
|
const targetAngles = angles || this.angleInputs
|
||||||
await fetch(API + '/api/arm/set_angles', {
|
await fetch(API + '/api/arm/set_angles', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ angles: this.angleInputs, speed: 500 })
|
body: JSON.stringify({ angles: targetAngles, speed: 500 })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
async invertAngles() {
|
||||||
|
// 每个角度取反:10 → -10, -10 → 10
|
||||||
|
const inverted = this.angleInputs.map(a => -a)
|
||||||
|
|
||||||
|
// 🔍 角度范围检查(myCobot 630 限位)
|
||||||
|
const limits = [
|
||||||
|
[-180, 180], // J1
|
||||||
|
[-90, 90], // J2
|
||||||
|
[-90, 90], // J3
|
||||||
|
[-180, 180], // J4
|
||||||
|
[-90, 90], // J5
|
||||||
|
[-180, 180] // J6
|
||||||
|
]
|
||||||
|
const outOfRange = []
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
if (inverted[i] < limits[i][0] || inverted[i] > limits[i][1]) {
|
||||||
|
outOfRange.push('J' + (i+1) + '=' + inverted[i].toFixed(1) + '° (范围: ' + limits[i][0] + '~' + limits[i][1] + '°)')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (outOfRange.length > 0) {
|
||||||
|
alert('⚠️ 角度超出范围:\n' + outOfRange.join('\n'))
|
||||||
|
return // 不执行反转
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用到机械臂
|
||||||
|
try {
|
||||||
|
await this.applyAngles(inverted)
|
||||||
|
this.angleInputs = inverted // 只有在成功后才更新显示
|
||||||
|
alert('✅ 角度已反转并应用')
|
||||||
|
} catch (e) {
|
||||||
|
alert('❌ 应用失败: ' + e.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待2秒让机械臂到位,然后刷新显示
|
||||||
|
setTimeout(() => this.refreshAngles(), 2000)
|
||||||
|
},
|
||||||
jogStart(idx, dir) {
|
jogStart(idx, dir) {
|
||||||
const joint = 'J' + (idx + 1)
|
const joint = 'J' + (idx + 1)
|
||||||
fetch(API + '/api/arm/jog', {
|
fetch(API + '/api/arm/jog', {
|
||||||
|
|||||||
@@ -510,6 +510,7 @@
|
|||||||
<div class="btn-row">
|
<div class="btn-row">
|
||||||
<button class="btn btn-primary" @click="refreshAngles">🔄 刷新角度</button>
|
<button class="btn btn-primary" @click="refreshAngles">🔄 刷新角度</button>
|
||||||
<button class="btn btn-secondary" @click="applyAngles">✅ 应用角度</button>
|
<button class="btn btn-secondary" @click="applyAngles">✅ 应用角度</button>
|
||||||
|
<button class="btn btn-warning" @click="invertAngles">🔄 反转角度</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -781,7 +781,7 @@ class MissionExecutorV3:
|
|||||||
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,
|
pose_idx: int, qr_value: str,
|
||||||
upload_index: int = 0) -> Optional[str]:
|
upload_index: int = 0) -> Optional[str]:
|
||||||
"""从机械臂摄像头拍照存本地,然后上传到服务器
|
"""从机械臂摄像头拍照,直接上传到服务器(不保存本地)
|
||||||
|
|
||||||
upload_index: 从1开始,先正面后背面,由调用方维护
|
upload_index: 从1开始,先正面后背面,由调用方维护
|
||||||
"""
|
"""
|
||||||
@@ -791,21 +791,17 @@ class MissionExecutorV3:
|
|||||||
logger.error("arm snapshot 请求失败")
|
logger.error("arm snapshot 请求失败")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
os.makedirs(PHOTOS_DIR, exist_ok=True)
|
# 生成文件名(用于上传)
|
||||||
ts = time.strftime("%Y%m%d_%H%M%S")
|
ts = time.strftime("%Y%m%d_%H%M%S")
|
||||||
fname = f"{ts}_r{row}c{col}_{side}_p{pose_idx}_{qr_value[:20]}.jpg"
|
fname = f"{ts}_r{row}c{col}_{side}_p{pose_idx}_{qr_value[:20]}.jpg"
|
||||||
fpath = os.path.join(PHOTOS_DIR, fname)
|
|
||||||
with open(fpath, "wb") as f:
|
|
||||||
f.write(resp.content)
|
|
||||||
self._log(f" 💾 本地保存: {os.path.basename(fpath)}")
|
|
||||||
|
|
||||||
# 上传到服务器
|
# 直接上传到服务器(不保存本地)
|
||||||
if qr_value:
|
if qr_value:
|
||||||
self._upload_photo(fpath, qr_value, upload_index)
|
self._upload_photo_bytes(fname, resp.content, qr_value, upload_index)
|
||||||
else:
|
else:
|
||||||
self._log(" ⚠️ 无二维码,跳过上传")
|
self._log(" ⚠️ 无二维码,跳过上传")
|
||||||
|
|
||||||
return fpath
|
return fname # 返回文件名(用于日志)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"拍照异常: {e}")
|
logger.error(f"拍照异常: {e}")
|
||||||
return None
|
return None
|
||||||
@@ -820,10 +816,13 @@ class MissionExecutorV3:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
filename = os.path.basename(filepath)
|
filename = os.path.basename(filepath)
|
||||||
|
headers = {
|
||||||
|
"Authorization": "Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX2tleSI6ImZhNTNkZTZiLWE3NjYtNDZmNC05MDUyLTQ2MjUzZTAyNjdmNSIsInVzZXJuYW1lIjoiYWRtaW4ifQ.lC4vKThZo4aAOLsekm2kPgaEJRqRx-YDQWKfHFqxdPNESCKy57l3eIqaKTj2ZjAMaoYAwYlMrv5M1zAOJsO_PA"
|
||||||
|
}
|
||||||
with open(filepath, "rb") as f:
|
with open(filepath, "rb") as f:
|
||||||
files = {"file": (filename, f, "image/jpeg")}
|
files = {"file": (filename, f, "image/jpeg")}
|
||||||
data = {"serialNumber": serial_number, "index": str(index)}
|
data = {"serialNumber": serial_number, "index": str(index)}
|
||||||
resp = requests.post(UPLOAD_URL, files=files, data=data, timeout=30)
|
resp = requests.post(UPLOAD_URL, files=files, data=data, headers=headers, timeout=30)
|
||||||
if resp.status_code == 200:
|
if resp.status_code == 200:
|
||||||
self._log(f" ☁️ 上传成功 [{index}]: {filename}")
|
self._log(f" ☁️ 上传成功 [{index}]: {filename}")
|
||||||
return True
|
return True
|
||||||
|
|||||||
Reference in New Issue
Block a user