可基本执行任务
This commit is contained in:
+210
-8
@@ -26,6 +26,9 @@ createApp({
|
||||
newPointName: '',
|
||||
newPointMode: 'front',
|
||||
newPointSequence: ['front', 'back'],
|
||||
// 点位编辑器弹窗
|
||||
editingPoint: null,
|
||||
pointEditor: { x: 0, y: 0, yaw: 0 },
|
||||
// 机型(姿态组)
|
||||
models: [],
|
||||
selectedModelId: null,
|
||||
@@ -56,6 +59,7 @@ createApp({
|
||||
qrScanningId: null,
|
||||
armCameraUrl: API + '/api/camera/arm_refresh',
|
||||
newQrName: '',
|
||||
armInitialPose: [0, 0, 0, 0, 0, 0],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -158,20 +162,41 @@ createApp({
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
this.nav2Available = data.nav2_available
|
||||
if (data.current_pos) {
|
||||
this.navCurrentPos = data.current_pos
|
||||
if (data.current_position) {
|
||||
this.navCurrentPos = data.current_position
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
},
|
||||
async onMapClick(e) {
|
||||
if (!this.mapMeta || !this.agvConnected) return
|
||||
if (!this.mapMeta) {
|
||||
this.mapMsg = '❌ 地图未加载'
|
||||
setTimeout(() => { this.mapMsg = '' }, 3000)
|
||||
return
|
||||
}
|
||||
if (!this.agvConnected) {
|
||||
this.mapMsg = '❌ AGV 未连接,无法导航'
|
||||
setTimeout(() => { this.mapMsg = '' }, 3000)
|
||||
return
|
||||
}
|
||||
const rect = e.target.getBoundingClientRect()
|
||||
const px = (e.clientX - rect.left) / rect.width
|
||||
const py = (e.clientY - rect.top) / rect.height
|
||||
let px = (e.clientX - rect.left) / rect.width
|
||||
let py = (e.clientY - rect.top) / rect.height
|
||||
// 逆旋转补偿:地图 CSS transform: rotate() 后,点击坐标需反向旋转
|
||||
// 使同一物理点在不同旋转角度下返回相同的世界坐标
|
||||
const rotation = (this.mapRotation || 0) * Math.PI / 180
|
||||
if (rotation !== 0) {
|
||||
const cx = px - 0.5
|
||||
const cy = py - 0.5
|
||||
const cos = Math.cos(-rotation)
|
||||
const sin = Math.sin(-rotation)
|
||||
px = cx * cos - cy * sin + 0.5
|
||||
py = cx * sin + cy * cos + 0.5
|
||||
}
|
||||
const { resolution, origin } = this.mapMeta
|
||||
const wx = origin[0] + px * resolution * this.mapMeta.width
|
||||
const wy = origin[1] + (1 - py) * resolution * this.mapMeta.height
|
||||
if (!confirm(`是否导航到该坐标?\nX: ${wx.toFixed(3)}\nY: ${wy.toFixed(3)}`)) return
|
||||
try {
|
||||
const res = await fetch(API + '/api/navigate/to', {
|
||||
method: 'POST',
|
||||
@@ -254,6 +279,129 @@ createApp({
|
||||
if (!angles) return '—'
|
||||
return angles.map(a => (a || 0).toFixed(1) + '°').join(' / ')
|
||||
},
|
||||
// === 点位编辑器弹窗 ===
|
||||
openPointEdit(ri, ci) {
|
||||
const point = this.getPointAt(ri, ci)
|
||||
this.editingPoint = { pointRow: ri, col: ci }
|
||||
if (point && point.coords && point.coords.length >= 3) {
|
||||
this.pointEditor = { x: point.coords[0], y: point.coords[1], yaw: point.coords[2] || 0 }
|
||||
} else {
|
||||
this.pointEditor = { x: 0, y: 0, yaw: 0 }
|
||||
}
|
||||
},
|
||||
closePointEdit() {
|
||||
this.editingPoint = null
|
||||
},
|
||||
getPointOwnerLabel(pointRow, col) {
|
||||
const rows = this.missionConfig.rows || 0
|
||||
if (pointRow === 0) {
|
||||
return `机器行1·正面`
|
||||
} else if (pointRow >= rows) {
|
||||
return `机器行${rows}·背面`
|
||||
} else {
|
||||
return `机器行${pointRow}·背面 + 机器行${pointRow+1}·正面`
|
||||
}
|
||||
},
|
||||
async loadPointFromAgv() {
|
||||
try {
|
||||
const res = await fetch(API + '/api/agv/position')
|
||||
const data = await res.json()
|
||||
if (data.ok && data.position && data.position.length >= 3) {
|
||||
this.pointEditor.x = data.position[0] || 0
|
||||
this.pointEditor.y = data.position[1] || 0
|
||||
this.pointEditor.yaw = data.position[2] || 0
|
||||
} else {
|
||||
alert('读取AGV位置失败')
|
||||
}
|
||||
} catch (e) { alert('读取AGV位置失败: ' + e.message) }
|
||||
},
|
||||
async savePoint() {
|
||||
if (!this.editingPoint) return
|
||||
const { pointRow, col } = this.editingPoint
|
||||
const coords = [this.pointEditor.x, this.pointEditor.y, this.pointEditor.yaw]
|
||||
const rows = this.missionConfig.rows || 0
|
||||
// 根据点位行确定 side
|
||||
const sides = []
|
||||
if (pointRow === 0) {
|
||||
sides.push('front')
|
||||
} else if (pointRow >= rows) {
|
||||
sides.push('back')
|
||||
} else {
|
||||
sides.push('back')
|
||||
sides.push('front')
|
||||
}
|
||||
try {
|
||||
for (const side of sides) {
|
||||
const res = await fetch(API + '/api/mission/positions', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ row: pointRow, col, side, coords, poses: [] })
|
||||
})
|
||||
const data = await res.json()
|
||||
if (!data.ok) { alert(`保存失败(${side}): ` + (data.error || '')); return }
|
||||
}
|
||||
alert('点位已保存')
|
||||
await this.loadMissionConfig()
|
||||
this.closePointEdit()
|
||||
} catch (e) { alert('保存失败: ' + e.message) }
|
||||
},
|
||||
async navigateToPoint() {
|
||||
if (!confirm(`确认导航到该点位?\nX: ${this.pointEditor.x} Y: ${this.pointEditor.y} Yaw: ${this.pointEditor.yaw}`)) return
|
||||
try {
|
||||
const res = await fetch(API + '/api/navigate/to', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
x: this.pointEditor.x,
|
||||
y: this.pointEditor.y,
|
||||
yaw: this.pointEditor.yaw
|
||||
})
|
||||
})
|
||||
const data = await res.json()
|
||||
if (!data.ok) { alert('导航失败: ' + (data.error || '')) }
|
||||
} catch (e) { alert('导航失败: ' + e.message) }
|
||||
},
|
||||
async goToOrigin() {
|
||||
if (!confirm('确认导航到原点 (0, 0, 0)?')) return
|
||||
try {
|
||||
const res = await fetch(API + '/api/navigate/to', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ x: 0, y: 0, yaw: 0 })
|
||||
})
|
||||
const data = await res.json()
|
||||
if (data.ok) {
|
||||
this.mapMsg = '✅ 已发送导航到原点'
|
||||
} else {
|
||||
this.mapMsg = '❌ ' + (data.error || '导航失败')
|
||||
}
|
||||
} catch (e) {
|
||||
this.mapMsg = '❌ 导航请求失败: ' + e.message
|
||||
}
|
||||
setTimeout(() => { this.mapMsg = '' }, 3000)
|
||||
},
|
||||
async clearPoint() {
|
||||
if (!this.editingPoint) return
|
||||
const { pointRow, col } = this.editingPoint
|
||||
const rows = this.missionConfig.rows || 0
|
||||
const sides = pointRow === 0 ? ['front'] : pointRow >= rows ? ['back'] : ['front', 'back']
|
||||
try {
|
||||
for (const side of sides) {
|
||||
await fetch(API + '/api/mission/positions', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ row: pointRow, col, side, coords: [0, 0, 0], poses: [] })
|
||||
})
|
||||
}
|
||||
await this.loadMissionConfig()
|
||||
this.closePointEdit()
|
||||
} catch (e) { alert('清空失败: ' + e.message) }
|
||||
},
|
||||
canClearPoint(pointRow, col) {
|
||||
const point = this.getPointAt(pointRow, col)
|
||||
if (!point || !point.coords) return true
|
||||
return point.coords[0] === 0 && point.coords[1] === 0
|
||||
},
|
||||
// === 机型管理 ===
|
||||
async loadAllModels() {
|
||||
const res = await fetch(API + '/api/models/list')
|
||||
@@ -344,7 +492,7 @@ createApp({
|
||||
const res = await fetch(API + '/api/arm/set_angles', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ angles: pose.arm_angles, speed: 50 })
|
||||
body: JSON.stringify({ angles: pose.arm_angles, speed: 500 })
|
||||
})
|
||||
const data = await res.json()
|
||||
if (data.ok) { alert('姿态已应用到机械臂') }
|
||||
@@ -382,6 +530,8 @@ createApp({
|
||||
this.missionConfig.rows = data.config.rows || 3
|
||||
this.missionConfig.cols = data.config.cols || 3
|
||||
this.missionConfig.grid = data.config.grid || []
|
||||
this.missionConfig.positions = data.config.positions || []
|
||||
this.armInitialPose = data.config.arm_initial_pose || [0, 0, 0, 0, 0, 0]
|
||||
}
|
||||
} catch (e) { console.error('加载任务配置失败', e) }
|
||||
},
|
||||
@@ -413,7 +563,8 @@ createApp({
|
||||
body: JSON.stringify({
|
||||
rows: this.missionConfig.rows,
|
||||
cols: this.missionConfig.cols,
|
||||
grid: this.missionConfig.grid
|
||||
grid: this.missionConfig.grid,
|
||||
arm_initial_pose: this.armInitialPose
|
||||
})
|
||||
})
|
||||
const data = await res.json()
|
||||
@@ -422,6 +573,47 @@ createApp({
|
||||
}
|
||||
} catch (e) { alert('保存失败: ' + e.message) }
|
||||
},
|
||||
async saveArmInitialPose() {
|
||||
try {
|
||||
const res = await fetch(API + '/api/mission/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
rows: this.missionConfig.rows,
|
||||
cols: this.missionConfig.cols,
|
||||
grid: this.missionConfig.grid,
|
||||
arm_initial_pose: this.armInitialPose
|
||||
})
|
||||
})
|
||||
const data = await res.json()
|
||||
if (data.ok) alert('✅ 机械臂初始姿态已保存')
|
||||
else alert('❌ 保存失败')
|
||||
} catch (e) { alert('保存失败: ' + e.message) }
|
||||
},
|
||||
async loadArmCurrentAngles() {
|
||||
if (!this.armConnected) { alert('机械臂未连接'); return }
|
||||
try {
|
||||
const res = await fetch(API + '/api/arm/get_angles')
|
||||
const data = await res.json()
|
||||
if (data.ok && data.angles) {
|
||||
this.armInitialPose = [...data.angles]
|
||||
}
|
||||
} catch (e) { alert('读取角度失败: ' + e.message) }
|
||||
},
|
||||
async applyArmInitialPose() {
|
||||
if (!this.armConnected) { alert('机械臂未连接'); return }
|
||||
if (!confirm('确认应用初始姿态到机械臂?')) return
|
||||
try {
|
||||
const res = await fetch(API + '/api/arm/set_angles', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ angles: this.armInitialPose, speed: 30 })
|
||||
})
|
||||
const data = await res.json()
|
||||
if (data.ok) alert('✅ 机械臂已移动到初始姿态')
|
||||
else alert('❌ 应用失败: ' + (data.error || ''))
|
||||
} catch (e) { alert('应用失败: ' + e.message) }
|
||||
},
|
||||
async loadAllMachines() {
|
||||
try {
|
||||
const res = await fetch(API + '/api/mission/machines')
|
||||
@@ -465,6 +657,16 @@ createApp({
|
||||
this.selectMachine(m)
|
||||
}
|
||||
},
|
||||
toggleMachine(ri, ci, event) {
|
||||
if (event.target.checked) {
|
||||
// 无机器 → 创建机器
|
||||
this.createMachine(ri, ci)
|
||||
} else {
|
||||
// 有机器 → 删除机器
|
||||
const m = this.getMachineAt(ri, ci)
|
||||
if (m) this.deleteMachine(m.id)
|
||||
}
|
||||
},
|
||||
async createMachine(ri, ci) {
|
||||
try {
|
||||
const machineId = 'm_' + ri + '_' + ci
|
||||
@@ -887,7 +1089,7 @@ createApp({
|
||||
const res = await fetch(API + '/api/arm/set_angles', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type':'application/json'},
|
||||
body: JSON.stringify({ angles: q.joint_angles, speed: 50 })
|
||||
body: JSON.stringify({ angles: q.joint_angles, speed: 500 })
|
||||
})
|
||||
const data = await res.json()
|
||||
if (data.ok) { alert('姿态已应用到机械臂')
|
||||
|
||||
Reference in New Issue
Block a user