Compare commits
2 Commits
60a73b5264
...
43ca0b0122
| Author | SHA1 | Date | |
|---|---|---|---|
| 43ca0b0122 | |||
| b1186e5922 |
@ -12,5 +12,8 @@ VITE_WS_URL = ws://192.168.0.222:13080/ws
|
||||
|
||||
# explanation
|
||||
VITE_INSPECTION_TYPE = "inspection"
|
||||
VITE_INSPECTION_ARM_DEVICEID = "huayan_arm"
|
||||
VITE_INSPECTION_AGV_DEVICEID = "huayan_arm"
|
||||
VITE_INSPECTION_ARM_DEVICE_ID = "huayan_arm"
|
||||
VITE_INSPECTION_AGV_DEVICE_ID = "src1100"
|
||||
VITE_AUDIO_SERVER_URL = "ws://192.168.0.222:13080/ws/audio"
|
||||
VITE_SPEAKER_DEVICE_ID = "spk1"
|
||||
VITE_MIC_DEVICE_ID = "mic1"
|
||||
@ -54,4 +54,44 @@ export function speedJApi(data) {
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function clearFault(params) {
|
||||
return request({
|
||||
url: '/api/arm/clearFault',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function getMicVolume(params) {
|
||||
return request({
|
||||
url: '/api/Microphone/volume',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function setMicVolume(data) {
|
||||
return request({
|
||||
url: '/api/Microphone/volume',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function getSpeakerVolume(params) {
|
||||
return request({
|
||||
url: '/api/Speaker/volume',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function setSpeakerVolume(data) {
|
||||
return request({
|
||||
url: '/api/Speaker/volume',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
@ -11,7 +11,7 @@
|
||||
</el-button>
|
||||
</template>
|
||||
<div class="form__container">
|
||||
<el-button type="primary" v-if="['AGV_MOVE_TO_POINT', 'ALM'].includes(props.data.properties.action)" size="small" @click="openRobotForm(props.data.properties.action)">获取位置</el-button>
|
||||
<el-button type="primary" v-if="['AGV_MOVE_TO_POINT', 'ARM_MOVE_TO_POINT'].includes(props.data.properties.action)" size="small" @click="openRobotForm(props.data.properties.action)">获取位置</el-button>
|
||||
<el-form :inline="true" :model="formData" :rules="rules" ref="dynamicFormRef" label-position="top"
|
||||
label-width="auto">
|
||||
<div v-for="(property, index) in formData.nodeParams" :key="index">
|
||||
|
||||
@ -135,8 +135,8 @@
|
||||
|
||||
<div class="speed-container">
|
||||
<div class="label">速度:</div>
|
||||
<el-slider v-model="speed" :min="0.1" :step="0.1" :max="4" />
|
||||
<div class="proportion">{{( speed / 4 * 100).toFixed(0) }} %</div>
|
||||
<el-slider v-model="speed" :min="0.01" :step="0.01" :max="1" />
|
||||
<div class="proportion">{{( speed / 1 * 100).toFixed(0) }} %</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -174,7 +174,7 @@ const errorNum = ref(0)
|
||||
const getPose = async (robot) => {
|
||||
try {
|
||||
const res = await getPoseApi({
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||
terminalId: robot.terminalId
|
||||
})
|
||||
if (res.code === 200) {
|
||||
@ -249,7 +249,7 @@ const move = async (axis, direction) => {
|
||||
}
|
||||
|
||||
speedLApi({
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||
terminalId: props.robot.terminalId,
|
||||
duration: 60,
|
||||
acceleration: speed.value + 0.1,
|
||||
@ -262,7 +262,7 @@ const move = async (axis, direction) => {
|
||||
*/
|
||||
const stop = async () => {
|
||||
await stopMotionApi({
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||
terminalId: props.robot.terminalId
|
||||
})
|
||||
}
|
||||
|
||||
@ -52,6 +52,34 @@
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="robot-volume">
|
||||
<span class="robot-volume__label">机器人麦克风音量</span>
|
||||
<el-slider
|
||||
v-model="microphoneVolume"
|
||||
class="robot-volume__slider"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:disabled="isMicrophoneVolumeLoading"
|
||||
:show-tooltip="true"
|
||||
@change="updateMicrophoneVolume"
|
||||
/>
|
||||
<span class="robot-volume__value">{{ microphoneVolume }}%</span>
|
||||
</div>
|
||||
|
||||
<div class="robot-volume">
|
||||
<span class="robot-volume__label">机器人扬声器音量</span>
|
||||
<el-slider
|
||||
v-model="speakerVolume"
|
||||
class="robot-volume__slider"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:disabled="isSpeakerVolumeLoading"
|
||||
:show-tooltip="true"
|
||||
@change="updateSpeakerVolume"
|
||||
/>
|
||||
<span class="robot-volume__value">{{ speakerVolume }}%</span>
|
||||
</div>
|
||||
|
||||
<section class="status-card">
|
||||
<div class="status-copy">
|
||||
<p>当前状态:<strong>{{ statusMeta.label }}</strong></p>
|
||||
@ -72,12 +100,13 @@
|
||||
<script setup>
|
||||
import { computed, onBeforeUnmount, ref } from 'vue'
|
||||
import { ElMessage, ElNotification } from 'element-plus'
|
||||
import { setMicVolume, getMicVolume, setSpeakerVolume, getSpeakerVolume } from '@/api/inspection/cockpit'
|
||||
|
||||
// WebSocket 只承载控制 JSON 和二进制 PCM,不再使用 WebRTC、SDP 或 ICE。
|
||||
const AUDIO_SERVER_URL = 'ws://192.168.1.222:13080/ws/audio'
|
||||
const AUDIO_SERVER_URL = import.meta.env.VITE_AUDIO_SERVER_URL
|
||||
const TERMINAL_ID = 'c2f8a06826baf03843925c1a2a13bcfd'
|
||||
const DEVICE_ID = '1234'
|
||||
const OPERATOR_ID = 'user001'
|
||||
const speakerDeviceId = import.meta.env.VITE_SPEAKER_DEVICE_ID
|
||||
const micDeviceId = import.meta.env.VITE_MIC_DEVICE_ID
|
||||
|
||||
// 后端约定的 PCM 格式:S16LE、48kHz、单声道、10ms。
|
||||
const PCM_SAMPLE_RATE = 48000
|
||||
@ -296,8 +325,8 @@ function connectAudioServer(sessionToken) {
|
||||
sendControlMessage({
|
||||
type: 'join',
|
||||
terminalId: TERMINAL_ID,
|
||||
deviceId: DEVICE_ID,
|
||||
operatorId: OPERATOR_ID
|
||||
speakerDeviceId: speakerDeviceId,
|
||||
micDeviceId: micDeviceId
|
||||
})
|
||||
}
|
||||
|
||||
@ -613,6 +642,96 @@ function endCall() {
|
||||
ElMessage.success('通话已结束')
|
||||
}
|
||||
|
||||
const microphoneVolume = ref(50)
|
||||
const speakerVolume = ref(50)
|
||||
const isMicrophoneVolumeLoading = ref(false)
|
||||
const isSpeakerVolumeLoading = ref(false)
|
||||
let confirmedMicrophoneVolume = 50
|
||||
let confirmedSpeakerVolume = 50
|
||||
|
||||
async function updateMicrophoneVolume(volume) {
|
||||
const previousVolume = confirmedMicrophoneVolume
|
||||
isMicrophoneVolumeLoading.value = true
|
||||
try {
|
||||
const response = await setMicVolume({
|
||||
deviceId: micDeviceId,
|
||||
terminalId: TERMINAL_ID,
|
||||
volume: Math.round(volume)
|
||||
})
|
||||
if (response.code !== 200) throw new Error(response.message || '设置机器人音量失败')
|
||||
microphoneVolume.value = volume
|
||||
confirmedMicrophoneVolume = volume
|
||||
ElMessage.success(`机器人麦克风音量已设置为 ${volume}%`)
|
||||
} catch (error) {
|
||||
microphoneVolume.value = previousVolume
|
||||
ElMessage.error(error.message || '设置机器人音量失败')
|
||||
} finally {
|
||||
isMicrophoneVolumeLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function updateSpeakerVolume(volume) {
|
||||
const previousVolume = confirmedSpeakerVolume
|
||||
isSpeakerVolumeLoading.value = true
|
||||
try {
|
||||
const response = await setSpeakerVolume({
|
||||
deviceId: speakerDeviceId,
|
||||
terminalId: TERMINAL_ID,
|
||||
volume: Math.round(volume)
|
||||
})
|
||||
if (response.code !== 200) throw new Error(response.message || '设置扬声器音量失败')
|
||||
speakerVolume.value = volume
|
||||
confirmedSpeakerVolume = volume
|
||||
ElMessage.success(`机器人扬声器音量已设置为 ${volume}%`)
|
||||
} catch (error) {
|
||||
speakerVolume.value = previousVolume
|
||||
ElMessage.error(error.message || '设置扬声器音量失败')
|
||||
} finally {
|
||||
isSpeakerVolumeLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function loadMicrophoneVolume({ silent = false } = {}) {
|
||||
isMicrophoneVolumeLoading.value = true
|
||||
try {
|
||||
const response = await getMicVolume({
|
||||
deviceId: micDeviceId,
|
||||
terminalId: TERMINAL_ID
|
||||
})
|
||||
if (response.code !== 200) throw new Error(response.message || '获取机器人音量失败')
|
||||
const volume = Math.max(0, Math.min(100, Number(response.data) || 0))
|
||||
microphoneVolume.value = volume
|
||||
confirmedMicrophoneVolume = volume
|
||||
} catch (error) {
|
||||
if (!silent) ElMessage.error(error.message || '获取机器人音量失败')
|
||||
} finally {
|
||||
isMicrophoneVolumeLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSpeakerVolume({ silent = false } = {}) {
|
||||
isSpeakerVolumeLoading.value = true
|
||||
try {
|
||||
const response = await getSpeakerVolume({
|
||||
deviceId: speakerDeviceId,
|
||||
terminalId: TERMINAL_ID
|
||||
})
|
||||
if (response.code !== 200) throw new Error(response.message || '获取扬声器音量失败')
|
||||
const volume = Math.max(0, Math.min(100, Number(response.data) || 0))
|
||||
speakerVolume.value = volume
|
||||
confirmedSpeakerVolume = volume
|
||||
} catch (error) {
|
||||
if (!silent) ElMessage.error(error.message || '获取扬声器音量失败')
|
||||
} finally {
|
||||
isSpeakerVolumeLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadMicrophoneVolume()
|
||||
loadSpeakerVolume()
|
||||
})
|
||||
|
||||
// 离开页面时释放麦克风、AudioWorklet 和 WebSocket。
|
||||
onBeforeUnmount(cleanupResources)
|
||||
</script>
|
||||
@ -843,6 +962,30 @@ $panel-border: rgb(112 192 255 / 24%);
|
||||
:deep(.el-button + .el-button) { margin-left: 0; }
|
||||
}
|
||||
|
||||
.robot-volume {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(120px, 210px) 42px;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
width: min(100%, 430px);
|
||||
margin-top: 10px;
|
||||
color: #badeff;;
|
||||
font-size: 11px;
|
||||
|
||||
&__label { white-space: nowrap; }
|
||||
&__value { color: #fff; text-align: right; font-variant-numeric: tabular-nums; }
|
||||
|
||||
:deep(.el-slider__runway) { background-color: #dff7ff; }
|
||||
:deep(.el-slider__bar) { background: linear-gradient(90deg, #46c8ff, #936cff); }
|
||||
:deep(.el-slider__button) {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-color: #46c8ff;
|
||||
background: #dff7ff;
|
||||
box-shadow: 0 0 10px rgb(70 200 255 / 65%);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.call-button) {
|
||||
width: 178px;
|
||||
height: 34px;
|
||||
|
||||
@ -82,8 +82,8 @@
|
||||
</div>
|
||||
<div class="speed-container">
|
||||
<div class="label">速度:</div>
|
||||
<el-slider v-model="jointSpeed" :min="0.1" :step="0.1" :max="9" />
|
||||
<div class="proportion">{{( jointSpeed / 9 * 100).toFixed(0) }} %</div>
|
||||
<el-slider v-model="jointSpeed" :min="0.01" :step="0.01" :max="1" />
|
||||
<div class="proportion">{{( jointSpeed / 1 * 100).toFixed(0) }} %</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -119,7 +119,7 @@ import UrdfViewer from './UrdfView.vue'
|
||||
import DirectionControl from './DirectionControl.vue'
|
||||
import RoboticArm from "./RoboticArm.vue";
|
||||
import { getRobotList } from '@/api/inspection/robot'
|
||||
import { getJointStateApi, moveJApi, torqueOnApi, speedJApi, stopMotionApi } from '@/api/inspection/cockpit'
|
||||
import { getJointStateApi, moveJApi, torqueOnApi, speedJApi, stopMotionApi, clearFault } from '@/api/inspection/cockpit'
|
||||
import { Remove, CirclePlus } from '@element-plus/icons-vue'
|
||||
import VoiceConversation from "./VoiceConversation.vue";
|
||||
import IPlayer from "@/components/IPlayer/index.vue";
|
||||
@ -178,8 +178,14 @@ const handlerController = (value) => {
|
||||
if (value === 2) {
|
||||
// 开启机械臂使能
|
||||
torqueOnApi({
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||
terminalId: activeBotData.value.terminalId
|
||||
}).catch(error => {
|
||||
console.error('开启机械臂使能失败:', error)
|
||||
clearFault({
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||
terminalId: activeBotData.value.terminalId
|
||||
})
|
||||
})
|
||||
jointControls.value = urdfViewerRef.value.jointControls
|
||||
if (animationId.value) {
|
||||
@ -188,6 +194,10 @@ const handlerController = (value) => {
|
||||
animationId.value = setInterval(() => {
|
||||
getJointState(activeBotData.value)
|
||||
}, 100)
|
||||
} else {
|
||||
if (animationId.value) {
|
||||
clearInterval(animationId.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,7 +219,7 @@ const errCount = ref(0)
|
||||
const getJointState = async (robot) => {
|
||||
try {
|
||||
const res = await getJointStateApi({
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||
terminalId: robot.terminalId
|
||||
})
|
||||
if (res.code === 200) {
|
||||
@ -246,7 +256,7 @@ 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: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||
terminalId: activeBotData.value.terminalId,
|
||||
acceleration: jointSpeed.value + 0.1,
|
||||
duration: 60,
|
||||
@ -259,7 +269,7 @@ const updateJoint = async (jointName, _dir) => {
|
||||
*/
|
||||
const stop = async () => {
|
||||
await stopMotionApi({
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||
terminalId: activeBotData.value.terminalId
|
||||
})
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user