From 92bd36c7051c053ed463c6b0908c62214088c416 Mon Sep 17 00:00:00 2001
From: zhanghao <774378400@qq.com>
Date: Fri, 14 Aug 2026 17:31:21 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=8C=89=E6=9C=BA=E5=99=A8?=
=?UTF-8?q?=E4=BA=BA=E5=8A=A8=E6=80=81=E8=A7=A3=E6=9E=90gRPC=E7=AB=AF?=
=?UTF-8?q?=E7=82=B9=E4=B8=8E=E8=AE=BE=E5=A4=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
server/audioWebSocket.js | 21 ++++-
server/cameraVideoStream.js | 9 +-
server/index.js | 115 +++++++++++++++----------
server/robotRegistry.js | 9 ++
src/api/agv.js | 4 +-
src/stores/robot.js | 26 +-----
src/utils/request.js | 5 +-
src/views/Address.vue | 83 +++---------------
src/views/arm/MechanicalArm.vue | 25 +-----
src/views/camera/VoiceConversation.vue | 20 ++---
src/views/camera/index.vue | 16 +---
src/views/chassis/Chassis.vue | 5 +-
src/views/chassis/MapCanvas.vue | 4 +-
13 files changed, 130 insertions(+), 212 deletions(-)
diff --git a/server/audioWebSocket.js b/server/audioWebSocket.js
index cf4beba..9c85a96 100644
--- a/server/audioWebSocket.js
+++ b/server/audioWebSocket.js
@@ -23,7 +23,7 @@ function waitForGrpcReady(client, timeoutMs = 5000) {
})
}
-export function attachAudioWebSocket(httpServer) {
+export function attachAudioWebSocket(httpServer, { resolveRobotAddress, resolveRobotDeviceId } = {}) {
const wss = new WebSocketServer({ server: httpServer, path: '/audio' })
wss.on('connection', (socket) => {
@@ -101,14 +101,27 @@ export function attachAudioWebSocket(httpServer) {
}
if (message.type !== 'init' || initialized) return
- const { microphoneId, robotAddress } = message
- speakerId = message.speakerId?.trim()
- if (![microphoneId, speakerId, robotAddress].every((value) => typeof value === 'string' && value.trim())) {
+ const { robotId } = message
+ if (typeof robotId !== 'string' || !robotId.trim()) {
sendJson(socket, { type: 'error', message: '机器人地址、麦克风 ID 和扬声器 ID 不能为空' })
socket.close(1008, 'invalid init')
return
}
+ const robotAddress = resolveRobotAddress?.(robotId.trim())
+ if (!robotAddress) {
+ sendJson(socket, { type: 'error', message: `机器人 ${robotId} 不在线或尚未注册` })
+ socket.close(1008, 'robot unavailable')
+ return
+ }
+ const microphoneId = resolveRobotDeviceId?.(robotId.trim(), 'microphone')
+ speakerId = resolveRobotDeviceId?.(robotId.trim(), 'speaker')
+ if (!microphoneId || !speakerId) {
+ sendJson(socket, { type: 'error', message: `机器人 ${robotId} 缺少麦克风或扬声器设备` })
+ socket.close(1008, 'audio device unavailable')
+ return
+ }
+
initialized = true
microphoneClient = createMicrophoneGrpcClient(robotAddress.trim())
speakerClient = createSpeakerGrpcClient(robotAddress.trim())
diff --git a/server/cameraVideoStream.js b/server/cameraVideoStream.js
index 27c279d..b92772d 100644
--- a/server/cameraVideoStream.js
+++ b/server/cameraVideoStream.js
@@ -84,14 +84,9 @@ function message(error) {
}
export function streamCameraVideo(req, res) {
- const ip = typeof req.query.ip === 'string' ? req.query.ip.trim() : ''
- const deviceId = typeof req.query.deviceId === 'string' ? req.query.deviceId.trim() : ''
- if (!ip || !deviceId) {
- res.status(400).json({ code: 400, message: 'ip 和 deviceId 不能为空' })
- return
- }
+ const deviceId = req.deviceId
- const client = createCameraGrpcClient(ip)
+ const client = createCameraGrpcClient(req.robotAddress)
const grpcStream = client.getRgbImageStream()
let transcoder
let closed = false
diff --git a/server/index.js b/server/index.js
index b4014e2..c217a6c 100644
--- a/server/index.js
+++ b/server/index.js
@@ -17,7 +17,7 @@ import {
import { attachAudioWebSocket } from './audioWebSocket.js';
import { streamCameraVideo } from './cameraVideoStream.js';
import { startQuicServer } from './quicServer.js';
-import { consumeQuicEvent, listRobots } from './robotRegistry.js';
+import { consumeQuicEvent, getRobotAddress, getRobotDeviceId, listRobots } from './robotRegistry.js';
const app = express()
app.use(express.static(path.join(__dirname, '../dist')));
@@ -28,19 +28,49 @@ app.get('/api/quic/robots', (req, res) => {
res.json({ code: 200, data: listRobots() })
})
+app.use('/api', (req, res, next) => {
+ const robotId = String(req.body?.robotId || req.query?.robotId || '').trim()
+ if (!robotId) {
+ res.status(400).json({ code: 400, message: 'robotId 不能为空' })
+ return
+ }
+ const address = getRobotAddress(robotId)
+ if (!address) {
+ res.status(404).json({ code: 404, message: `机器人 ${robotId} 不在线或尚未注册` })
+ return
+ }
+ req.robotId = robotId
+ req.robotAddress = address
+ next()
+})
+
+app.use('/api', (req, res, next) => {
+ let kind = ''
+ if (req.path.startsWith('/agv/')) kind = 'agv'
+ else if (req.path.startsWith('/arm/')) kind = 'arm'
+ else if (req.path.startsWith('/audio/microphone/')) kind = 'microphone'
+ else if (req.path.startsWith('/audio/speaker/')) kind = 'speaker'
+ else if (req.path.startsWith('/camera/')) kind = 'camera'
+ if (!kind) return next()
+
+ const deviceId = getRobotDeviceId(req.robotId, kind)
+ if (!deviceId) {
+ res.status(404).json({ code: 404, message: `机器人 ${req.robotId} 没有可用的 ${kind} 设备` })
+ return
+ }
+ req.deviceId = deviceId
+ next()
+})
+
// 将相机逐帧 gRPC 数据转码为浏览器可直接播放的 fragmented MP4。
-// 示例:/api/camera/video?ip=192.168.0.28%3A50052&deviceId=camera1
+// 示例:/api/camera/video?robotId=robot-1
app.get('/api/camera/video', streamCameraVideo)
// 获取机器人麦克风音量(0-100)。
app.post('/api/audio/microphone/volume/get', (req, res) => {
- const { ip, deviceId } = req.body
- if (!ip || !deviceId) {
- res.status(400).json({ code: 400, message: '机器人地址和麦克风设备 ID 不能为空' })
- return
- }
+ const deviceId = req.deviceId
- const grpcClient = createMicrophoneGrpcClient(ip)
+ const grpcClient = createMicrophoneGrpcClient(req.robotAddress)
grpcClient.getVolume(
{ header: { device_id: deviceId } },
{ deadline: Date.now() + 5000 },
@@ -65,18 +95,14 @@ app.post('/api/audio/microphone/volume/get', (req, res) => {
// 设置机器人麦克风音量(0-100)。
app.post('/api/audio/microphone/volume/set', (req, res) => {
- const { ip, deviceId } = req.body
+ const deviceId = req.deviceId
const volume = Number(req.body.volume)
- if (!ip || !deviceId) {
- res.status(400).json({ code: 400, message: '机器人地址和麦克风设备 ID 不能为空' })
- return
- }
if (!Number.isInteger(volume) || volume < 0 || volume > 100) {
res.status(400).json({ code: 400, message: '音量必须是 0 到 100 的整数' })
return
}
- const grpcClient = createMicrophoneGrpcClient(ip)
+ const grpcClient = createMicrophoneGrpcClient(req.robotAddress)
grpcClient.setVolume({
header: { device_id: deviceId },
volume
@@ -100,13 +126,9 @@ app.post('/api/audio/microphone/volume/set', (req, res) => {
// 获取机器人扬声器音量(0-100)。
app.post('/api/audio/speaker/volume/get', (req, res) => {
- const { ip, deviceId } = req.body
- if (!ip || !deviceId) {
- res.status(400).json({ code: 400, message: '机器人地址和扬声器设备 ID 不能为空' })
- return
- }
+ const deviceId = req.deviceId
- const grpcClient = createSpeakerGrpcClient(ip)
+ const grpcClient = createSpeakerGrpcClient(req.robotAddress)
grpcClient.getVolume(
{ header: { device_id: deviceId } },
{ deadline: Date.now() + 5000 },
@@ -131,18 +153,14 @@ app.post('/api/audio/speaker/volume/get', (req, res) => {
// 设置机器人扬声器音量(0-100)。
app.post('/api/audio/speaker/volume/set', (req, res) => {
- const { ip, deviceId } = req.body
+ const deviceId = req.deviceId
const volume = Number(req.body.volume)
- if (!ip || !deviceId) {
- res.status(400).json({ code: 400, message: '机器人地址和扬声器设备 ID 不能为空' })
- return
- }
if (!Number.isInteger(volume) || volume < 0 || volume > 100) {
res.status(400).json({ code: 400, message: '音量必须是 0 到 100 的整数' })
return
}
- const grpcClient = createSpeakerGrpcClient(ip)
+ const grpcClient = createSpeakerGrpcClient(req.robotAddress)
grpcClient.setVolume({
header: { device_id: deviceId },
volume
@@ -168,11 +186,11 @@ app.post('/api/audio/speaker/volume/set', (req, res) => {
app.post('/api/agv/getRuntimeState', async (req, res) => {
const request = {
header: {
- device_id: req.body.deviceId || 'agv_src1100'
+ device_id: req.deviceId
}
};
- const grpcClient = createAGVGrpcClient(req.body.ip)
+ const grpcClient = createAGVGrpcClient(req.robotAddress)
const resp = await new Promise((resolve, reject) => {
grpcClient.getRuntimeState(request, (err, res) => {
@@ -199,10 +217,10 @@ app.post('/api/agv/getRuntimeState', async (req, res) => {
// 获取机器人当前地图
app.post('/api/agv/getCurrentMap', async (req, res) => {
- const grpcClient = createAGVGrpcClient(req.body.ip)
+ const grpcClient = createAGVGrpcClient(req.robotAddress)
const request = {
header: {
- device_id: req.body.deviceId || 'agv_src1100'
+ device_id: req.deviceId
},
map_name: req.body.mapName
};
@@ -232,10 +250,10 @@ app.post('/api/agv/getCurrentMap', async (req, res) => {
// 机器人运动控制
app.post('/api/agv/moveRobot', async (req, res) => {
- const grpcClient = createAGVGrpcClient(req.body.ip)
+ const grpcClient = createAGVGrpcClient(req.robotAddress)
const request = {
header: {
- device_id: req.body.deviceId || 'agv_src1100'
+ device_id: req.deviceId
},
velocity: {
vx: req.body.vx,
@@ -272,10 +290,10 @@ app.post('/api/agv/moveRobot', async (req, res) => {
// 机器人停止运动
app.post('/api/agv/stopRobot', async (req, res) => {
- const grpcClient = createAGVGrpcClient(req.body.ip)
+ const grpcClient = createAGVGrpcClient(req.robotAddress)
const request = {
header: {
- device_id: req.body.deviceId || 'agv_src1100'
+ device_id: req.deviceId
}
};
@@ -312,11 +330,11 @@ app.post('/api/agv/stopRobot', async (req, res) => {
app.post('/api/arm/getPose', async (req, res) => {
const request = {
header: {
- device_id: req.body.deviceId || 'huayan_arm'
+ device_id: req.deviceId
}
};
- const grpcClient = createARMGrpcClient(req.body.ip)
+ const grpcClient = createARMGrpcClient(req.robotAddress)
const resp = await new Promise((resolve, reject) => {
grpcClient.getPose(request, (err, res) => {
@@ -345,11 +363,11 @@ app.post('/api/arm/getPose', async (req, res) => {
app.post('/api/arm/getJointState', async (req, res) => {
const request = {
header: {
- device_id: req.body.deviceId || 'huayan_arm'
+ device_id: req.deviceId
}
};
- const grpcClient = createARMGrpcClient(req.body.ip)
+ const grpcClient = createARMGrpcClient(req.robotAddress)
const resp = await new Promise((resolve, reject) => {
grpcClient.getJointState(request, (err, res) => {
@@ -378,7 +396,7 @@ app.post('/api/arm/getJointState', async (req, res) => {
app.post('/api/arm/speedJ', async (req, res) => {
const request = {
header: {
- device_id: req.body.deviceId || 'huayan_arm'
+ device_id: req.deviceId
},
velocity: {
velocity: req.body.velocities
@@ -386,7 +404,7 @@ app.post('/api/arm/speedJ', async (req, res) => {
acceleration: req.body.acceleration,
duration: req.body.duration
};
- const grpcClient = createARMGrpcClient(req.body.ip)
+ const grpcClient = createARMGrpcClient(req.robotAddress)
const resp = await new Promise((resolve, reject) => {
grpcClient.speedJ(request, (err, res) => {
@@ -414,13 +432,13 @@ app.post('/api/arm/speedJ', async (req, res) => {
app.post('/api/arm/speedL', async (req, res) => {
const request = {
header: {
- device_id: req.body.deviceId || 'huayan_arm'
+ device_id: req.deviceId
},
velocity: req.body.velocity,
acceleration: req.body.acceleration,
duration: req.body.duration
};
- const grpcClient = createARMGrpcClient(req.body.ip)
+ const grpcClient = createARMGrpcClient(req.robotAddress)
const resp = await new Promise((resolve, reject) => {
grpcClient.speedL(request, (err, res) => {
@@ -449,10 +467,10 @@ app.post('/api/arm/speedL', async (req, res) => {
app.post('/api/arm/stopMotion', async (req, res) => {
const request = {
// header: {
- device_id: req.body.deviceId || 'huayan_arm',
+ device_id: req.deviceId,
// },
};
- const grpcClient = createARMGrpcClient(req.body.ip)
+ const grpcClient = createARMGrpcClient(req.robotAddress)
const resp = await new Promise((resolve, reject) => {
grpcClient.stopMotion(request, (err, res) => {
@@ -479,9 +497,9 @@ app.post('/api/arm/stopMotion', async (req, res) => {
app.post('/api/arm/torqueOn', async (req, res) => {
const request = {
- device_id: req.body.deviceId || 'huayan_arm',
+ device_id: req.deviceId,
};
- const grpcClient = createARMGrpcClient(req.body.ip)
+ const grpcClient = createARMGrpcClient(req.robotAddress)
const resp = await new Promise((resolve, reject) => {
grpcClient.torqueOn(request, (err, res) => {
@@ -551,7 +569,10 @@ if (httpsEnabled) {
httpServer = http.createServer(app);
}
-attachAudioWebSocket(httpServer)
+attachAudioWebSocket(httpServer, {
+ resolveRobotAddress: getRobotAddress,
+ resolveRobotDeviceId: getRobotDeviceId
+})
startQuicServer({ onEvent: consumeQuicEvent })
httpServer.listen(PORT, '0.0.0.0', () => {
diff --git a/server/robotRegistry.js b/server/robotRegistry.js
index b6a5462..09c9bdd 100644
--- a/server/robotRegistry.js
+++ b/server/robotRegistry.js
@@ -82,3 +82,12 @@ export function listRobots() {
return [...robots.values()].sort((a, b) => a.robotId.localeCompare(b.robotId))
}
+export function getRobotAddress(robotId) {
+ if (!robotId) return ''
+ return robots.get(robotId)?.ip || ''
+}
+
+export function getRobotDeviceId(robotId, kind) {
+ const devices = robots.get(robotId)?.devices?.[kind] || []
+ return (devices.find(device => device.enabled) || devices[0])?.deviceId || ''
+}
diff --git a/src/api/agv.js b/src/api/agv.js
index 29de072..62038e5 100644
--- a/src/api/agv.js
+++ b/src/api/agv.js
@@ -3,7 +3,7 @@ import request from '@/utils/request'
/**
* 机器人前往目标站点
* @param {Object} params
- * @param {string} [params.deviceId] - 设备ID,默认 agv_src1100
+ * robotId 由统一请求层从 Pinia 自动附加,设备 ID 由后端注册表解析。
*/
export function getRuntimeState(params) {
return request('/api/agv/getRuntimeState', params, 'POST')
@@ -23,4 +23,4 @@ export function moveRobot(params) {
export function stopRobot(params) {
return request('/api/agv/stopRobot', params, 'POST')
-}
\ No newline at end of file
+}
diff --git a/src/stores/robot.js b/src/stores/robot.js
index 106eac3..de73d26 100644
--- a/src/stores/robot.js
+++ b/src/stores/robot.js
@@ -3,13 +3,8 @@ import { defineStore } from 'pinia'
// 唯一id:robot
export const useRobotStore = defineStore('robot', {
state: () => ({
- ip: '192.168.0.28:50052',
+ robotId: '',
robotType: 'inspection',
- agvDeviceId:'src1100',
- almDeviceId: 'huayan_arm',
- spkDeviceId: 'spk1',
- micDeviceId: 'mic1',
- cameraDeviceId: 'real_cam1',
position: { x: 0, y: 0, theta: 0 },
battery: {
percentage: 0.99,
@@ -30,27 +25,12 @@ export const useRobotStore = defineStore('robot', {
}
},
actions: {
- setIp(str) {
- this.ip = str
+ setRobotId(str) {
+ this.robotId = str
},
setRobotType(str) {
this.robotType = str
},
- setAgvDeviceId(str) {
- this.agvDeviceId = str
- },
- setAlmDeviceId(str) {
- this.almDeviceId = str
- },
- setSpkDeviceId(str) {
- this.spkDeviceId = str
- },
- setMicDeviceId(str) {
- this.micDeviceId = str
- },
- setCameraDeviceId(str) {
- this.cameraDeviceId = str
- },
// 更新机器人位置
setPosition(data = {}) {
this.position = data
diff --git a/src/utils/request.js b/src/utils/request.js
index 10f0333..fc16fbf 100644
--- a/src/utils/request.js
+++ b/src/utils/request.js
@@ -1,4 +1,5 @@
import { ElMessage } from 'element-plus'
+import { useRobotStore } from '@/stores/robot'
const request = async (url, params = {}, method = 'GET', headers = { 'Content-Type': 'application/json' }) => {
const controller = new AbortController()
@@ -9,13 +10,15 @@ const request = async (url, params = {}, method = 'GET', headers = { 'Content-Ty
}, 5000)
try {
+ const robotId = useRobotStore().robotId
+ const requestParams = robotId && !params.robotId ? { ...params, robotId } : params
const options = {
method,
headers,
signal
}
if (!['GET', 'HEAD'].includes(method.toUpperCase())) {
- options.body = JSON.stringify(params)
+ options.body = JSON.stringify(requestParams)
}
const res = await fetch(url, options)
diff --git a/src/views/Address.vue b/src/views/Address.vue
index cdbc4b0..45757d0 100644
--- a/src/views/Address.vue
+++ b/src/views/Address.vue
@@ -16,7 +16,7 @@
@@ -28,30 +28,12 @@
-
-
-
-
进入上位机控制页面
@@ -74,7 +56,7 @@ const robotStore = useRobotStore()
const loading = ref(false)
const robotListLoading = ref(false)
const robots = ref([])
-const selectedRobotId = ref('')
+const selectedRobotId = ref(robotStore.robotId || '')
const selectedRobot = computed(() => robots.value.find(robot => robot.robotId === selectedRobotId.value))
const selectedDevices = computed(() => Object.entries(selectedRobot.value?.devices || {}).flatMap(
([kind, devices]) => devices.map(device => ({ kind, ...device }))
@@ -82,51 +64,19 @@ const selectedDevices = computed(() => Object.entries(selectedRobot.value?.devic
let refreshTimer
const ruleFormRef = ref()
const ruleForm = ref({
- ip: '',
robotType: 'inspection',
- // agvDeviceId:'src1100',
- // almDeviceId: 'huayan_arm',
- // spkDeviceId: 'spk1',
- // micDeviceId: 'mic1',
- // cameraDeviceId: 'real_cam1'
})
const rules = ref({
- ip: [
- { required: true, message: '请输入机器人IP和端口', trigger: 'blur' }
- ],
robotType: [
{ required: true, message: '请选择机器人类型', trigger: 'blur' }
],
- // agvDeviceId: [
- // { required: true, message: '请输入底盘设备ID', trigger: 'blur' }
- // ],
- // almDeviceId: [
- // { required: true, message: '请输入机械臂设备ID', trigger: 'blur' }
- // ],
- // spkDeviceId: [
- // { required: true, message: '请输入扬声器设备ID', trigger: 'blur' }
- // ],
- // micDeviceId: [
- // { required: true, message: '请输入麦克风设备ID', trigger: 'blur' }
- // ],
- // cameraDeviceId: [
- // { required: true, message: '请输入相机设备ID', trigger: 'blur' }
- // ],
})
-const firstDeviceId = (robot, kind, fallback) => robot?.devices?.[kind]?.[0]?.deviceId || fallback
-
const selectRobot = () => {
const robot = selectedRobot.value
if (!robot) return
- ruleForm.value.ip = robot.ip
- robotStore.setIp(robot.ip)
- robotStore.setAgvDeviceId(firstDeviceId(robot, 'agv', 'src1100'))
- robotStore.setAlmDeviceId(firstDeviceId(robot, 'arm', 'huayan_arm'))
- robotStore.setSpkDeviceId(firstDeviceId(robot, 'speaker', 'spk1'))
- robotStore.setMicDeviceId(firstDeviceId(robot, 'microphone', 'mic1'))
- robotStore.setCameraDeviceId(firstDeviceId(robot, 'camera', 'real_cam1'))
+ robotStore.setRobotId(robot.robotId)
}
const loadRobots = async () => {
@@ -147,32 +97,19 @@ onMounted(() => {
onUnmounted(() => clearInterval(refreshTimer))
const testConnect = async () => {
+ if (!selectedRobot.value) {
+ ElMessage.warning('请先选择已连接机器人')
+ return
+ }
const valid = await ruleFormRef.value.validate();
if (valid) {
loading.value = true
- robotStore.setIp(ruleForm.value.ip)
+ robotStore.setRobotId(selectedRobot.value.robotId)
robotStore.setRobotType(ruleForm.value.robotType)
- if (selectedRobot.value) {
- selectRobot()
- } else if (ruleForm.value.robotType === 'inspection') {
- robotStore.setAgvDeviceId('src1100')
- robotStore.setAlmDeviceId('huayan_arm')
- robotStore.setSpkDeviceId('spk1')
- robotStore.setMicDeviceId('mic1')
- robotStore.setCameraDeviceId('real_cam1')
- } else if (ruleForm.value.robotType === 'explanation') {
- robotStore.setAgvDeviceId('src1100')
- robotStore.setAlmDeviceId('huayan_arm')
- robotStore.setSpkDeviceId('spk1')
- robotStore.setMicDeviceId('mic1')
- robotStore.setCameraDeviceId('real_cam1')
- }
+ selectRobot()
try {
- const result = await getRuntimeState({
- ip: robotStore.ip,
- deviceId: robotStore.agvDeviceId
- })
+ const result = await getRuntimeState()
loading.value = false
if (result.code === 200) {
robotStore.setPosition(result.data.pose)
diff --git a/src/views/arm/MechanicalArm.vue b/src/views/arm/MechanicalArm.vue
index 83fecb8..c48d3d4 100644
--- a/src/views/arm/MechanicalArm.vue
+++ b/src/views/arm/MechanicalArm.vue
@@ -303,7 +303,6 @@ import { Remove, CirclePlus } from '@element-plus/icons-vue'
import { useRobotStore } from '@/stores/robot'
const robotStore = useRobotStore()
-const deviceId = robotStore.almDeviceId
const urdfViewerRef = ref()
@@ -343,17 +342,11 @@ const tcp = ref({
})
const torqueOn = async () => {
- await torqueOnApi({
- ip: robotStore.ip,
- deviceId: deviceId
- })
+ await torqueOnApi()
}
const getPose = async () => {
- const res = await getPoseApi({
- ip: robotStore.ip,
- deviceId: deviceId
- })
+ const res = await getPoseApi()
if (res.code === 200) {
const { x, y, z, rx, ry, rz } = res.data
tcp.value = { x, y, z, rx, ry, rz }
@@ -375,10 +368,7 @@ const jointNamsMap = {
*/
const getJointState = async (robot) => {
try {
- const res = await getJointStateApi({
- deviceId: deviceId,
- ip: robotStore.ip,
- })
+ const res = await getJointStateApi()
if (res.code === 200) {
setTimeout(() => {
const names = res.data.name
@@ -404,8 +394,6 @@ const updateJoint = async (jointName, _dir) => {
const index = jointControls.value.findIndex(joint => joint.name === jointName)
velocities[index] = jointSpeed.value * (_dir === '+' ? 1 : -1)
const res = await speedJApi({
- deviceId: deviceId,
- ip: robotStore.ip,
acceleration: jointSpeed.value * (_dir === '+' ? 1 : -1) + 0.1,
duration: 60,
velocities: velocities
@@ -475,8 +463,6 @@ const move = async (axis, direction, type) => {
}
speedLApi({
- deviceId: deviceId,
- ip: robotStore.ip,
duration: 60,
acceleration: type === 'posture' ? postureSpeed.value + 0.1 : endSpeed.value + 0.1,
velocity: {
@@ -489,10 +475,7 @@ const move = async (axis, direction, type) => {
* 停止机械臂移动
*/
const stop = async () => {
- await stopMotionApi({
- deviceId: deviceId,
- ip: robotStore.ip
- })
+ await stopMotionApi()
}
const activePointerIds = new Set()
diff --git a/src/views/camera/VoiceConversation.vue b/src/views/camera/VoiceConversation.vue
index cdad6d3..693a383 100644
--- a/src/views/camera/VoiceConversation.vue
+++ b/src/views/camera/VoiceConversation.vue
@@ -151,14 +151,11 @@ const statusMeta = computed(() => {
})
function microphoneVolumeRequestParams() {
- return {
- ip: robotStore.ip,
- deviceId: robotStore.micDeviceId
- }
+ return {}
}
async function loadMicrophoneVolume({ silent = false } = {}) {
- if (!robotStore.ip || !robotStore.micDeviceId) return
+ if (!robotStore.robotId) return
isMicrophoneVolumeLoading.value = true
try {
const response = await getMicrophoneVolume(microphoneVolumeRequestParams())
@@ -194,14 +191,11 @@ async function updateMicrophoneVolume(volume) {
}
function speakerVolumeRequestParams() {
- return {
- ip: robotStore.ip,
- deviceId: robotStore.spkDeviceId
- }
+ return {}
}
async function loadSpeakerVolume({ silent = false } = {}) {
- if (!robotStore.ip || !robotStore.spkDeviceId) return
+ if (!robotStore.robotId) return
isSpeakerVolumeLoading.value = true
try {
const response = await getSpeakerVolume(speakerVolumeRequestParams())
@@ -391,9 +385,7 @@ function connectAudioServer(sessionToken) {
const timeout = window.setTimeout(() => reject(new Error('连接音频服务超时')), JOIN_TIMEOUT)
socket.onopen = () => sendControlMessage({
type: 'init',
- microphoneId: robotStore.micDeviceId,
- speakerId: robotStore.spkDeviceId,
- robotAddress: robotStore.ip
+ robotId: robotStore.robotId
})
socket.onmessage = (event) => {
if (typeof event.data !== 'string') {
@@ -455,7 +447,7 @@ async function startCall() {
errorMessage.value = ''
const sessionToken = ++callSessionId
try {
- if (!robotStore.ip || !robotStore.micDeviceId || !robotStore.spkDeviceId) {
+ if (!robotStore.robotId) {
throw new Error('请先配置机器人地址、麦克风 ID 和扬声器 ID')
}
// 必须在按钮点击的用户手势中创建,以符合浏览器自动播放策略。
diff --git a/src/views/camera/index.vue b/src/views/camera/index.vue
index 8975598..7d4a90d 100644
--- a/src/views/camera/index.vue
+++ b/src/views/camera/index.vue
@@ -14,20 +14,10 @@ import VoiceConversation from './VoiceConversation.vue';
import { computed } from 'vue';
import { useRobotStore } from '@/stores/robot';
-const VIDEO_SERVER_HOST = import.meta.env.VITE_VIDEO_SERVER_HOST || 'http://localhost:8080/'
-const TerminalId = import.meta.env.VITE_TERMINAL_ID || 'c2f8a06826baf03843925c1a2a13bcfd'
-
const robotStore = useRobotStore()
-const videoUrl = `${VIDEO_SERVER_HOST}/api/edge/camera/rgb-stream/public?terminalId=${TerminalId}&deviceId=${robotStore.cameraDeviceId}`
-
-// const videoUrl = computed(() => {
-// if (!robotStore.ip || !robotStore.cameraDeviceId) return ''
-// const params = new URLSearchParams({
-// ip: robotStore.ip,
-// deviceId: robotStore.cameraDeviceId
-// })
-// return `/api/camera/video?${params}`
-// })
+const videoUrl = computed(() => robotStore.robotId
+ ? `/api/camera/video?robotId=${encodeURIComponent(robotStore.robotId)}`
+ : '')