feat: 巡检机器人
This commit is contained in:
parent
8d8bcb4e26
commit
d2130ffaf5
5
components.d.ts
vendored
5
components.d.ts
vendored
@ -12,7 +12,6 @@ export {}
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
@ -21,10 +20,10 @@ declare module 'vue' {
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSlider: typeof import('element-plus/es')['ElSlider']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTag: typeof import('element-plus/es')['ElTag']
|
||||
IPlayer: typeof import('./src/components/IPlayer/index.vue')['default']
|
||||
LandscapeGuard: typeof import('./src/components/LandscapeGuard.vue')['default']
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<!-- 主体内容区 -->
|
||||
<div class="main-wrap">
|
||||
<!-- 左侧数据面板 -->
|
||||
<div class="left-panel">
|
||||
<div class="left-panel" :class="{ 'left-panel--dual-arm': isExplanationRobot }">
|
||||
<!-- TCP 笛卡尔坐标 -->
|
||||
<div class="panel-card">
|
||||
<div class="row dual-row">
|
||||
@ -44,7 +44,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="joint-list">
|
||||
<div v-if="!isExplanationRobot" class="joint-list">
|
||||
<div class="title">关节控制</div>
|
||||
<div v-for="joint in jointControls" :key="joint.name" class="joint-item">
|
||||
<label :for="joint.name">{{ joint.name }}</label>
|
||||
@ -65,6 +65,34 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="joint-list joint-list--dual-arm">
|
||||
<div class="title">关节控制</div>
|
||||
<div class="arm-columns">
|
||||
<div v-for="arm in armJointGroups" :key="arm.key" class="arm-column">
|
||||
<div class="arm-title">{{ arm.title }}</div>
|
||||
<div v-for="joint in arm.joints" :key="joint.name" class="joint-item">
|
||||
<label :for="joint.name">{{ joint.name }}</label>
|
||||
<el-input v-model="joint.value" readonly>
|
||||
<template #prepend>
|
||||
<el-button class="press-control"
|
||||
@pointerdown="startPointerControl($event, () => updateJoint(joint.name, '-'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
-
|
||||
</el-button>
|
||||
</template>
|
||||
<template #append>
|
||||
<el-button class="press-control"
|
||||
@pointerdown="startPointerControl($event, () => updateJoint(joint.name, '+'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
+
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="speed-container">
|
||||
<div class="label">速度:</div>
|
||||
<div class="speed-slider" @mouseenter="hoveredSlider = 'joint'" @mouseleave="hoveredSlider = null">
|
||||
@ -78,7 +106,7 @@
|
||||
|
||||
<!-- 中间3D机械臂空白区域 -->
|
||||
<div class="center-view">
|
||||
<UrdfView ref="urdfViewerRef" />
|
||||
<UrdfView ref="urdfViewerRef" :modelPath="modelPath"/>
|
||||
<!-- 底部功能按钮 -->
|
||||
<!-- <div class="center-bottom-btns">
|
||||
<el-button type="success" size="large">零力示教</el-button>
|
||||
@ -91,6 +119,13 @@
|
||||
<div class="right-panel">
|
||||
<div class="controller">
|
||||
<div class="title">末端控制</div>
|
||||
<div v-if="isExplanationRobot" class="arm-selector">
|
||||
<div class="arm-selector__label">控制机械臂</div>
|
||||
<el-radio-group v-model="selectedEndArm" class="arm-selector__options">
|
||||
<el-radio-button value="left">左臂</el-radio-button>
|
||||
<el-radio-button value="right">右臂</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="axis-group">
|
||||
<!-- X Axis -->
|
||||
<div class="axis-row x">
|
||||
@ -171,6 +206,13 @@
|
||||
|
||||
<div class="controller">
|
||||
<div class="title">姿态控制</div>
|
||||
<div v-if="isExplanationRobot" class="arm-selector">
|
||||
<div class="arm-selector__label">控制机械臂</div>
|
||||
<el-radio-group v-model="selectedPostureArm" class="arm-selector__options">
|
||||
<el-radio-button value="left">左臂</el-radio-button>
|
||||
<el-radio-button value="right">右臂</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="axis-group">
|
||||
<!-- X Axis -->
|
||||
<div class="axis-row x">
|
||||
@ -254,7 +296,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
import UrdfView from './UrdfView.vue'
|
||||
import { getPoseApi, getJointStateApi, moveJApi, torqueOnApi, speedJApi, stopMotionApi, speedLApi } from '@/api/arm'
|
||||
import { Remove, CirclePlus } from '@element-plus/icons-vue'
|
||||
@ -264,7 +306,31 @@ const robotStore = useRobotStore()
|
||||
const deviceId = robotStore.almDeviceId
|
||||
|
||||
const urdfViewerRef = ref()
|
||||
const jointControls = ref()
|
||||
|
||||
const modelPath = computed(() => {
|
||||
if (isExplanationRobot.value) {
|
||||
return 'upper_body/robot.urdf'
|
||||
} else {
|
||||
return '/inspection/elfin10/elfin10.urdf.xacro'
|
||||
}
|
||||
})
|
||||
|
||||
const jointControls = ref([])
|
||||
const isExplanationRobot = computed(() => robotStore.robotType === 'explanation')
|
||||
const selectedEndArm = ref('left')
|
||||
const selectedPostureArm = ref('left')
|
||||
const armJointGroups = computed(() => [
|
||||
{
|
||||
key: 'left',
|
||||
title: '左臂',
|
||||
joints: jointControls.value.filter(joint => /^left_arm_/i.test(joint.name))
|
||||
},
|
||||
{
|
||||
key: 'right',
|
||||
title: '右臂',
|
||||
joints: jointControls.value.filter(joint => /^right_arm_/i.test(joint.name))
|
||||
}
|
||||
])
|
||||
|
||||
// TCP坐标数据
|
||||
const tcp = ref({
|
||||
@ -512,11 +578,16 @@ onUnmounted(() => {
|
||||
// 左侧面板
|
||||
.left-panel {
|
||||
width: 400px;
|
||||
flex-shrink: 0;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
background: $color-background-panel;
|
||||
border-right: 1px solid $color-accent-border;
|
||||
|
||||
&--dual-arm {
|
||||
width: 640px;
|
||||
}
|
||||
|
||||
.panel-card {
|
||||
padding: 12px;
|
||||
|
||||
@ -525,11 +596,27 @@ onUnmounted(() => {
|
||||
gap: 20px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.coord-item {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
|
||||
.key {
|
||||
width: 26px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.number {
|
||||
width: 170px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
border-radius: 5px;
|
||||
padding: 6px;
|
||||
background: $color-background-card;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -546,6 +633,19 @@ onUnmounted(() => {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.arm-columns {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.arm-title {
|
||||
margin-bottom: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.joint-item {
|
||||
display: flex;
|
||||
@ -607,6 +707,17 @@ onUnmounted(() => {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&--dual-arm {
|
||||
.joint-item {
|
||||
padding: 8px;
|
||||
|
||||
label {
|
||||
width: 82px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -625,6 +736,36 @@ onUnmounted(() => {
|
||||
background: $color-background-panel;
|
||||
border-left: 1px solid $color-accent-border;
|
||||
|
||||
.arm-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
padding: 12px 14px;
|
||||
border: 1px solid $color-accent-border;
|
||||
border-radius: 8px;
|
||||
background: $color-background-base;
|
||||
|
||||
&__label {
|
||||
flex-shrink: 0;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&__options {
|
||||
flex: 1;
|
||||
|
||||
:deep(.el-radio-button) {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
:deep(.el-radio-button__inner) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.controller {
|
||||
margin-bottom: 48px;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user