feat: 增加机器人扬声器和麦克风音量的控制
This commit is contained in:
parent
b1186e5922
commit
43ca0b0122
@ -12,5 +12,8 @@ VITE_WS_URL = ws://192.168.0.222:13080/ws
|
|||||||
|
|
||||||
# explanation
|
# explanation
|
||||||
VITE_INSPECTION_TYPE = "inspection"
|
VITE_INSPECTION_TYPE = "inspection"
|
||||||
VITE_INSPECTION_ARM_DEVICEID = "huayan_arm"
|
VITE_INSPECTION_ARM_DEVICE_ID = "huayan_arm"
|
||||||
VITE_INSPECTION_AGV_DEVICEID = "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"
|
||||||
@ -55,3 +55,43 @@ export function speedJApi(data) {
|
|||||||
data: data
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -135,8 +135,8 @@
|
|||||||
|
|
||||||
<div class="speed-container">
|
<div class="speed-container">
|
||||||
<div class="label">速度:</div>
|
<div class="label">速度:</div>
|
||||||
<el-slider v-model="speed" :min="0.1" :step="0.1" :max="2" />
|
<el-slider v-model="speed" :min="0.01" :step="0.01" :max="1" />
|
||||||
<div class="proportion">{{( speed / 2 * 100).toFixed(0) }} %</div>
|
<div class="proportion">{{( speed / 1 * 100).toFixed(0) }} %</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -174,7 +174,7 @@ const errorNum = ref(0)
|
|||||||
const getPose = async (robot) => {
|
const getPose = async (robot) => {
|
||||||
try {
|
try {
|
||||||
const res = await getPoseApi({
|
const res = await getPoseApi({
|
||||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||||
terminalId: robot.terminalId
|
terminalId: robot.terminalId
|
||||||
})
|
})
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
@ -249,7 +249,7 @@ const move = async (axis, direction) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
speedLApi({
|
speedLApi({
|
||||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||||
terminalId: props.robot.terminalId,
|
terminalId: props.robot.terminalId,
|
||||||
duration: 60,
|
duration: 60,
|
||||||
acceleration: speed.value + 0.1,
|
acceleration: speed.value + 0.1,
|
||||||
@ -262,7 +262,7 @@ const move = async (axis, direction) => {
|
|||||||
*/
|
*/
|
||||||
const stop = async () => {
|
const stop = async () => {
|
||||||
await stopMotionApi({
|
await stopMotionApi({
|
||||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||||
terminalId: props.robot.terminalId
|
terminalId: props.robot.terminalId
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,6 +52,34 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</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">
|
<section class="status-card">
|
||||||
<div class="status-copy">
|
<div class="status-copy">
|
||||||
<p>当前状态:<strong>{{ statusMeta.label }}</strong></p>
|
<p>当前状态:<strong>{{ statusMeta.label }}</strong></p>
|
||||||
@ -72,12 +100,13 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onBeforeUnmount, ref } from 'vue'
|
import { computed, onBeforeUnmount, ref } from 'vue'
|
||||||
import { ElMessage, ElNotification } from 'element-plus'
|
import { ElMessage, ElNotification } from 'element-plus'
|
||||||
|
import { setMicVolume, getMicVolume, setSpeakerVolume, getSpeakerVolume } from '@/api/inspection/cockpit'
|
||||||
|
|
||||||
// WebSocket 只承载控制 JSON 和二进制 PCM,不再使用 WebRTC、SDP 或 ICE。
|
// 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 TERMINAL_ID = 'c2f8a06826baf03843925c1a2a13bcfd'
|
||||||
const DEVICE_ID = '1234'
|
const speakerDeviceId = import.meta.env.VITE_SPEAKER_DEVICE_ID
|
||||||
const OPERATOR_ID = 'user001'
|
const micDeviceId = import.meta.env.VITE_MIC_DEVICE_ID
|
||||||
|
|
||||||
// 后端约定的 PCM 格式:S16LE、48kHz、单声道、10ms。
|
// 后端约定的 PCM 格式:S16LE、48kHz、单声道、10ms。
|
||||||
const PCM_SAMPLE_RATE = 48000
|
const PCM_SAMPLE_RATE = 48000
|
||||||
@ -296,8 +325,8 @@ function connectAudioServer(sessionToken) {
|
|||||||
sendControlMessage({
|
sendControlMessage({
|
||||||
type: 'join',
|
type: 'join',
|
||||||
terminalId: TERMINAL_ID,
|
terminalId: TERMINAL_ID,
|
||||||
deviceId: DEVICE_ID,
|
speakerDeviceId: speakerDeviceId,
|
||||||
operatorId: OPERATOR_ID
|
micDeviceId: micDeviceId
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,6 +642,96 @@ function endCall() {
|
|||||||
ElMessage.success('通话已结束')
|
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。
|
// 离开页面时释放麦克风、AudioWorklet 和 WebSocket。
|
||||||
onBeforeUnmount(cleanupResources)
|
onBeforeUnmount(cleanupResources)
|
||||||
</script>
|
</script>
|
||||||
@ -843,6 +962,30 @@ $panel-border: rgb(112 192 255 / 24%);
|
|||||||
:deep(.el-button + .el-button) { margin-left: 0; }
|
: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) {
|
:deep(.call-button) {
|
||||||
width: 178px;
|
width: 178px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
|
|||||||
@ -82,8 +82,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="speed-container">
|
<div class="speed-container">
|
||||||
<div class="label">速度:</div>
|
<div class="label">速度:</div>
|
||||||
<el-slider v-model="jointSpeed" :min="0.1" :step="0.1" :max="3" />
|
<el-slider v-model="jointSpeed" :min="0.01" :step="0.01" :max="1" />
|
||||||
<div class="proportion">{{( jointSpeed / 3 * 100).toFixed(0) }} %</div>
|
<div class="proportion">{{( jointSpeed / 1 * 100).toFixed(0) }} %</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -119,7 +119,7 @@ import UrdfViewer from './UrdfView.vue'
|
|||||||
import DirectionControl from './DirectionControl.vue'
|
import DirectionControl from './DirectionControl.vue'
|
||||||
import RoboticArm from "./RoboticArm.vue";
|
import RoboticArm from "./RoboticArm.vue";
|
||||||
import { getRobotList } from '@/api/inspection/robot'
|
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 { Remove, CirclePlus } from '@element-plus/icons-vue'
|
||||||
import VoiceConversation from "./VoiceConversation.vue";
|
import VoiceConversation from "./VoiceConversation.vue";
|
||||||
import IPlayer from "@/components/IPlayer/index.vue";
|
import IPlayer from "@/components/IPlayer/index.vue";
|
||||||
@ -178,8 +178,14 @@ const handlerController = (value) => {
|
|||||||
if (value === 2) {
|
if (value === 2) {
|
||||||
// 开启机械臂使能
|
// 开启机械臂使能
|
||||||
torqueOnApi({
|
torqueOnApi({
|
||||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||||
terminalId: activeBotData.value.terminalId
|
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
|
jointControls.value = urdfViewerRef.value.jointControls
|
||||||
if (animationId.value) {
|
if (animationId.value) {
|
||||||
@ -188,6 +194,10 @@ const handlerController = (value) => {
|
|||||||
animationId.value = setInterval(() => {
|
animationId.value = setInterval(() => {
|
||||||
getJointState(activeBotData.value)
|
getJointState(activeBotData.value)
|
||||||
}, 100)
|
}, 100)
|
||||||
|
} else {
|
||||||
|
if (animationId.value) {
|
||||||
|
clearInterval(animationId.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +219,7 @@ const errCount = ref(0)
|
|||||||
const getJointState = async (robot) => {
|
const getJointState = async (robot) => {
|
||||||
try {
|
try {
|
||||||
const res = await getJointStateApi({
|
const res = await getJointStateApi({
|
||||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||||
terminalId: robot.terminalId
|
terminalId: robot.terminalId
|
||||||
})
|
})
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
@ -246,7 +256,7 @@ const updateJoint = async (jointName, _dir) => {
|
|||||||
const index = jointControls.value.findIndex(joint => joint.name === jointName)
|
const index = jointControls.value.findIndex(joint => joint.name === jointName)
|
||||||
velocities[index] = jointSpeed.value * (_dir === '+' ? 1 : -1)
|
velocities[index] = jointSpeed.value * (_dir === '+' ? 1 : -1)
|
||||||
const res = await speedJApi({
|
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,
|
terminalId: activeBotData.value.terminalId,
|
||||||
acceleration: jointSpeed.value + 0.1,
|
acceleration: jointSpeed.value + 0.1,
|
||||||
duration: 60,
|
duration: 60,
|
||||||
@ -259,7 +269,7 @@ const updateJoint = async (jointName, _dir) => {
|
|||||||
*/
|
*/
|
||||||
const stop = async () => {
|
const stop = async () => {
|
||||||
await stopMotionApi({
|
await stopMotionApi({
|
||||||
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICEID,
|
deviceId: import.meta.env.VITE_INSPECTION_ARM_DEVICE_ID,
|
||||||
terminalId: activeBotData.value.terminalId
|
terminalId: activeBotData.value.terminalId
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user