Browse Source

cl2 基于设备状态和任务状态分步生成设备任务消息

master
yuliang 6 months ago
parent
commit
ea2d1982ff
  1. 2
      src/core/base/BaseItemEntity.ts
  2. 22
      src/core/manager/EnvManager.ts
  3. 174
      src/core/manager/amr/AmrMessageDefine.ts
  4. 68
      src/core/manager/amr/AmrMessageManager.ts
  5. 40
      src/editor/propEditors/PtrController.vue
  6. 2
      src/editor/widgets/property/PropertyPanelConstant.ts
  7. 295
      src/modules/cl2/Cl23DGraphics.ts
  8. 475
      src/modules/cl2/Cl23dObject.ts
  9. 4
      src/modules/cl2/Cl2PropertySetter.ts

2
src/core/base/BaseItemEntity.ts

@ -10,7 +10,7 @@ import { getRenderer } from '@/core/manager/ModuleManager.ts'
* *
*/ */
export default abstract class BaseEntity implements EntityIf, Loadable, Carry, Walk, ForkArm, LiftingArm { export default abstract class BaseEntity implements EntityIf, Loadable, Carry, Walk, ForkArm, LiftingArm {
protected readonly viewport: Viewport public readonly viewport: Viewport
protected readonly taskQueue: TaskQueue = new TaskQueue() protected readonly taskQueue: TaskQueue = new TaskQueue()
readonly id: string readonly id: string
readonly item: ItemJson readonly item: ItemJson

22
src/core/manager/EnvManager.ts

@ -1,17 +1,23 @@
import type Viewport from '@/core/engine/Viewport.ts' import type Viewport from '@/core/engine/Viewport.ts'
import { worldModel } from '@/core/manager/WorldModel.ts' import { worldModel } from '@/core/manager/WorldModel.ts'
import mqtt, { type IConnackPacket, type IPublishPacket } from 'mqtt' import mqtt, { type IConnackPacket, type IPublishPacket } from 'mqtt'
import type { Cl2Task } from '@/modules/cl2/Cl23dObject.ts'
import type { ErrorWithReasonCode } from 'mqtt/src/lib/shared.ts' import type { ErrorWithReasonCode } from 'mqtt/src/lib/shared.ts'
import type Cl23dObject from '@/modules/cl2/Cl23dObject.ts' import type Cl23dObject from '@/modules/cl2/Cl23dObject.ts'
import { Request } from '@ease-forge/shared' import { Request } from '@ease-forge/shared'
import AmrMessageManager from "@/core/manager/amr/AmrMessageManager";
import {AmrMsg} from "@/core/manager/amr/AmrMessageDefine";
export default class EnvManager { export default class EnvManager {
private viewport: Viewport private viewport: Viewport
private client: mqtt.MqttClient = null private amrMessageManager: AmrMessageManager = null
public client: mqtt.MqttClient = null
init(viewport: Viewport): void { init(viewport: Viewport): void {
this.viewport = viewport this.viewport = viewport
if (!this.amrMessageManager) {
this.amrMessageManager = new AmrMessageManager()
}
this.amrMessageManager.viewport = viewport
} }
// 从后台读取所有车 // 从后台读取所有车
@ -92,10 +98,14 @@ export default class EnvManager {
} }
onMqttMessage = (topic: string, payload: Buffer, packet: IPublishPacket) => { onMqttMessage = (topic: string, payload: Buffer, packet: IPublishPacket) => {
console.log(`[${topic}] ${msg}`) console.log(`[${topic}]-> ${payload.toString()}`)
debugger if (topic.startsWith("/wcs_server/")) {
const a: Cl2Task = JSON.parse(msg.toString()) const message: AmrMsg<any> = JSON.parse(payload.toString())
this.handleMessage(a) this.amrMessageManager.handleMessage(topic, message)
} else {
}
} }
onMqttError = (error: Error | ErrorWithReasonCode) => { onMqttError = (error: Error | ErrorWithReasonCode) => {

174
src/core/manager/amr/AmrMessageDefine.ts

@ -0,0 +1,174 @@
import type Viewport from '@/core/engine/Viewport.ts'
type LogicDirection = 0 | 1 | 2 | 3 | 15
class AmrMsg<T> {
id: number
content: T
constructor<T>(content: T) {
if (content instanceof AmrMsg20020) {
this.id = 20020
} else if (content instanceof AmrMsg20050) {
this.id = 20050
} else if (content instanceof AmrMsg20149) {
this.id = 20149
} else if (content instanceof AmrMsg20250) {
this.id = 20250
}
this.content = content
}
}
class AmrMsg10010 {
SeqNo: number;
OperationType: 0 | 1 | 2 | 3 | 4 | 5 | 135 | 136;
UseBriefLocation: boolean;
StartX: number;
StartY: number;
EndX: number;
EndY: number;
EndDirection: 0 | 1 | 2 | 3 | 15;
// 0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作
PickMode: 0 | 1 | 2 | 3 | 4 | 5 | 6;
GoodsSlotHeight: number;
GoodsSlotDirection: 0 | 1 | 2 | 3 | 15;
GoodsId: string;
Link: {
// id: string; // 实际报文没有
X: number;
Y: number;
Speed: number;
}[]
}
class AmrMsg20000Base {
SeqNo: number
VehicleId: number
CreateTime: number
SendTime: number
CreateMonoTime: number
constructor() {
this.SeqNo = getAmrMsgSeqNo()
this.CreateTime = Date.now()
this.SendTime = Date.now()
}
}
class AmrMsg20020 extends AmrMsg20000Base {
CurDirection: LogicDirection
CurLogicX: number
CurLogicY: number
CurX: number
CurY: number
// 地标类型 二维码 1 默认
MarkerType: number = 1
CurOrientation: number = 0
X: number = 0
Y: number = 0
constructor() {
super()
}
}
class AmrMsg20050 extends AmrMsg20000Base {
constructor(seqNo: number, vehicleId: number) {
super()
this.SeqNo = seqNo
this.VehicleId = vehicleId
}
}
class AmrMsg20149 extends AmrMsg20000Base {
AGVFnModel: string
AGVModel: string
Battery: number
constructor() {
super()
}
}
class AmrMsg20250 extends AmrMsg20000Base {
// 异常持续时间 秒
Duration: number = 0
// 异常代码
ErrCode: number
// 异常代码 名称
ErrCodeName: string
// 异常事件类型 0:无 1:开始 2:更新 3:结束 4:开始并结束
ErrEvtType: number
// 异常等级 0:Undetermined 未确定 12:Info 信息 13:Warning 警告 14:Critical 严重 15:Fatal 致命
ErrLevel: number
// 异常生命周期 0:易变的 1:一次性 2:持续性 3:任务期间
ErrLifecycle: number
// 异常详情 根据不同的异常,字段不一样,比如针对ErrCode为2电量低的情况,ErrMsg中使用CurBattery标识当前电量;
ErrMsg: object
constructor() {
super()
}
// 地标异常
// {"content":{"CreateMonoTime":64489153,"CreateTime":1751337599272,"Duration":3,"ErrCode":5,"ErrCodeName":"kLocationMarkNotFound","ErrEvtType":1,"ErrLevel":14,"ErrLifecycle":2,"ErrMsg":{"ErrDesc":"无法在 (-1.00, -1.00) 位置使用扫描设备 kLocationMarkCamera(ID: 1) 找到码","ErrDescEn":"Unable to use scanner kLocationMarkCamera(id: 1) to find a mark at (-1.00, -1.00)","ErrPrivInfo":{"Camera":1,"CurLogicX":-1,"CurLogicY":-1,"ExpectCode":"","X":-1000.0,"Y":-1000.0}},"SendTime":1751337602101,"SeqNo":4,"VehicleId":3},"id":20250}
}
let __AmrMsgSeqNo__: number = 0
const getAmrMsgSeqNo = () => {
if (__AmrMsgSeqNo__ >= 0Xfffffff) {
__AmrMsgSeqNo__ = 0
} else {
__AmrMsgSeqNo__++
}
return __AmrMsgSeqNo__
}
export {AmrMsg, AmrMsg10010, AmrMsg20020, AmrMsg20050, AmrMsg20149, AmrMsg20250, AmrErrorCode, LogicDirection}
const AmrErrorCode = {
0: {
// 无异常
ErrCode: 0,
ErrCodeName: "",
ErrMsg: {}
},
5: {
// 未找到地面二维码 "ErrEvtType":1,"ErrLevel":14,"ErrLifecycle":2
ErrCode: 5,
ErrCodeName: "kLocationMarkNotFound",
ErrMsg: {
"ErrDesc": "无法在 (-1.00, -1.00) 位置使用扫描设备 kLocationMarkCamera(ID: 1) 找到码",
"ErrDescEn": "Unable to use scanner kLocationMarkCamera(id: 1) to find a mark at (-1.00, -1.00)",
"ErrPrivInfo": {"Camera": 1, "CurLogicX": -1, "CurLogicY": -1, "ExpectCode": "", "X": -1000.0, "Y": -1000.0}
}
},
15: {
// 未记录的地标码 "ErrEvtType":4,"ErrLevel":13,"ErrLifecycle":1
ErrCode: 15,
ErrCodeName: "kUnrecognizedMark",
ErrMsg: {
"ErrDesc": "在位置 (-799.00, -1004.00)(逻辑位置:(-1.00, -1.00))发现了一个未识别的码(224842)",
"ErrDescEn": "Found an unrecognized mark(224842) at location (-799.00, -1004.00)(logic location: (-1.00, -1.00))",
"ErrPrivInfo": {"CurLogicX": -1, "CurLogicY": -1, "MarkName": "224842", "X": -799.0, "Y": -1004.0}
}
},
67: {
// 障碍物检测功能异常 "ErrEvtType":1,"ErrLevel":14,"ErrLifecycle":2,
ErrCode: 67,
ErrCodeName: "kObstacleDetectionMalfunction",
ErrMsg: {"ErrDesc": "障碍物检测功能异常", "ErrDescEn": "Obstacle detection malfunction", "ErrPrivInfo": {"CurLogicX": 6, "CurLogicY": 2, "X": 10816.0, "Y": 2115.0}}
},
85: {
// 需要人工介入处理 "ErrEvtType":1,"ErrLevel":14,"ErrLifecycle":2
// 当设备遇到无法/不敢自动恢复的异常时,如果导致执行中断的异常结束了,则会报这个异常。比如行驶过程中防撞条被碰了一下而后马上松开了,由于防撞条触发很可能有撞击,所以检测到防撞条触发后车会停止不动,这种情况下需要人工介入检查处理。由于被撞物体与防撞条已经不接触了,所以防撞条触发异常(异常号8)会结束,结束的同时设备主动产生本异常,以提示人工介入。此异常消息中会包含一个字段,用以提示可能的导致异常的原因;由于异常过程可能伴随多种严重异常(比如碰撞到物体到停车过程可能伴随有失控、检测不到地标码等异常),这个字段所提示原因并不一定是确切的原因
ErrCode: 85,
ErrCodeName: "kRequestForIntervention",
ErrMsg: {"ErrDesc": "需要人工协助。无法恢复的原因:kLocationMarkNotFound(ID:5)", "ErrDescEn": "Manual assistance is required. Likely reason for my inability: kLocationMarkNotFound(id: 5)", "ErrPrivInfo": {"ReasonException": 5}}
}
}

68
src/core/manager/amr/AmrMessageManager.ts

@ -0,0 +1,68 @@
import {AmrMsg, AmrMsg10010, AmrMsg20050} from "@/core/manager/amr/AmrMessageDefine";
import Cl23dObject from "@/modules/cl2/Cl23dObject";
import Viewport from "@/core/engine/Viewport";
export default class AmrMessageManager {
public viewport: Viewport
handleMessage(topic, amrMsg: AmrMsg<any>) {
const vehicleId = parseInt(topic.replace("/wcs_server/", ""))
switch (amrMsg.id) {
// AMR作业指令 10010
case 10010:
const cl2 = this.viewport.entityManager.findObjectById(amrMsg.content.VehicleId + "") as Cl23dObject
cl2.handleMessage(amrMsg as AmrMsg<AmrMsg10010>)
break;
// 停止/解除 10040
case 10040:
break;
// 电文应答 10050
case 10050:
break;
// 配置信息 10060
case 10060:
break;
// 旋转货架 10080
case 10080:
break;
// 旋转车身 10081
case 10081:
break;
// 控制卷帘门 10082
case 10082:
break;
// 心跳 10100
case 10100:
break;
// 状态查询 10110
case 10110:
break;
// 取消已下发小车任务 10120
case 10120:
break;
// 设置小车坐标 10200
case 10200:
break;
// 等待就绪 19997
case 19997:
break;
}
if (amrMsg.id != 10050 && amrMsg.id != 10100) {
const seqNo = amrMsg.content.SeqNo;
this.sendAck(seqNo, vehicleId);
}
}
sendAck(seqNo: number, vehicleId: number) {
const msg20050 = new AmrMsg20050(seqNo, vehicleId)
const ack = new AmrMsg<AmrMsg20050>(msg20050)
this.sendMessage(ack)
}
sendMessage(amrMsg: AmrMsg<any>) {
this.viewport.envManager.client.publish('/agv_robot/status', JSON.stringify(amrMsg))
}
}

40
src/editor/propEditors/PtrController.vue

@ -0,0 +1,40 @@
<script setup lang="ts">
import lodash from "lodash";
import { computed, reactive } from "vue";
import { ElButton, ElDivider, ElFormItem, ElIcon, ElInputNumber, useFormItem } from "element-plus";
import { CopyDocument, Delete } from "@element-plus/icons-vue";
import { Typeof } from "@ease-forge/shared";
import type Viewport from "@/core/engine/Viewport";
import {BayEditorProps} from "@/editor/propEditors/BayEditor.vue";
import Cl23dObject from "@/modules/cl2/Cl23dObject";
defineOptions({
name: 'PtrController',
});
// props
const props = withDefaults(defineProps(), {});
function start() {
const viewport: Viewport = window['viewport']
// viewport.envManager.client.publish('/agv_robot/status', '')
const item = viewport.state.selectedItem
const object3D: Cl23dObject = viewport.state.selectedObject as Cl23dObject
console.log(item, object3D)
object3D.boot()
}
</script>
<template>
<div class="ptr-controller">
<el-button @click="start">启动</el-button>
</div>
</template>
<style scoped>
.ptr-controller {
width: 100%;
user-select: none;
}
</style>

2
src/editor/widgets/property/PropertyPanelConstant.ts

@ -5,6 +5,7 @@ import { dataFormInputComponents } from "@/components/data-form/DataFormConstant
import TransformEditor from "@/editor/propEditors/TransformEditor.vue"; import TransformEditor from "@/editor/propEditors/TransformEditor.vue";
import InOutCenterEditor from "@/editor/propEditors/InOutCenterEditor.vue"; import InOutCenterEditor from "@/editor/propEditors/InOutCenterEditor.vue";
import BayEditor from "@/editor/propEditors/BayEditor.vue"; import BayEditor from "@/editor/propEditors/BayEditor.vue";
import PtrController from "@/editor/propEditors/PtrController.vue";
const defDataFormProps: DataFormProps = { const defDataFormProps: DataFormProps = {
columnCount: 1, columnCount: 1,
@ -16,6 +17,7 @@ const defDataFormProps: DataFormProps = {
dataFormInputComponents.TransformEditor = markRaw<any>(TransformEditor); dataFormInputComponents.TransformEditor = markRaw<any>(TransformEditor);
dataFormInputComponents.InOutCenterEditor = markRaw<any>(InOutCenterEditor); dataFormInputComponents.InOutCenterEditor = markRaw<any>(InOutCenterEditor);
dataFormInputComponents.BayEditor = markRaw<any>(BayEditor); dataFormInputComponents.BayEditor = markRaw<any>(BayEditor);
dataFormInputComponents.PtrController = markRaw<any>(PtrController);
const basicFieldsSetter: Array<PropertyFieldSetter> = [ const basicFieldsSetter: Array<PropertyFieldSetter> = [
{ {

295
src/modules/cl2/Cl23DGraphics.ts

@ -0,0 +1,295 @@
import * as THREE from "three";
import {CSG} from "three-csg-ts";
//@ts-ignore
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js'
export default class Cl23DGraphics {
// 创建ptr的底座
public static createPtrPedestal(): THREE.BufferGeometry {
// 参数配置
const radius = 0.8 // 圆半径
const lineDist = 0.75 // 切割线距离圆心距离
const segments = 64 // 圆的分段精度
// 计算切割线与圆的交点
const intersectY = Math.sqrt(radius * radius - lineDist * lineDist)
const startAngle = Math.asin(intersectY / radius)
const endAngle = Math.acos(intersectY / radius)
const shape = new THREE.Shape()
shape.moveTo(0, 0) // 起点在圆心
shape.absarc(0, 0, 0.8, startAngle, endAngle, false) // 从0到π绘制半圆
shape.absarc(0, 0, 0.8, startAngle + Math.PI / 2, endAngle + Math.PI / 2, false)
shape.absarc(0, 0, 0.8, startAngle + Math.PI, endAngle + Math.PI, false)
shape.absarc(0, 0, 0.8, startAngle + Math.PI / 2 * 3, endAngle + Math.PI / 2 * 3, false)
shape.lineTo(-0.5, -intersectY)
shape.lineTo(-0.5, -intersectY + 0.17)
shape.lineTo(0.75, -intersectY + 0.17)
shape.lineTo(0.75, intersectY - 0.17)
shape.lineTo(-0.5, intersectY - 0.17)
shape.lineTo(-0.5, intersectY)
shape.closePath() // 闭合路径
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.02, 0), new THREE.Vector3(0, 0.22, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelEnabled: false,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
const geometry = new THREE.ExtrudeGeometry(shape, options)
const material = new THREE.MeshBasicMaterial({color: 0xffdddbca})
const mesh = new THREE.Mesh(geometry, material)
mesh.updateMatrix()
// 倒角
const shapeD = new THREE.Shape()
shapeD.moveTo(-0.02, -0.02)
shapeD.lineTo(0.02, 0.02)
shapeD.lineTo(-0.02, 0.02)
shapeD.closePath()
const curveD = new THREE.EllipseCurve(
0, 0, radius, radius, 0, Math.PI * 2, false, 0
)
// 生成拉伸路径点
const pointsD = curveD.getPoints(segments).map(p =>
new THREE.Vector3(p.x, 0.20, p.y)
)
// 3. 挤出成型
const optionsD = {
steps: segments,
bevelEnabled: false,
// bevelSegments: 0.01,
extrudePath: new THREE.CatmullRomCurve3(pointsD)
}
const geometryD = new THREE.ExtrudeGeometry(shapeD, optionsD)
const meshD = new THREE.Mesh(geometryD, material)
meshD.updateMatrix()
// 布尔运算
const result = CSG.subtract(mesh, meshD)
return result.geometry
}
// 创建ptr的立柱
public static createPtrPillar(): THREE.BufferGeometry {
// 606.5
const width = 0.245
const depth = 0.716
const dd = 0.05
const shape = new THREE.Shape()
shape.moveTo(-0.728, -0.358 + dd)
shape.lineTo(-0.728 + dd, -0.358)
shape.lineTo(-0.728 + width - dd, -0.358)
shape.lineTo(-0.728 + width, -0.358 + dd)
shape.lineTo(-0.728 + width, -0.28)
shape.lineTo(-0.728 + width - 0.08, -0.28)
shape.lineTo(-0.728 + width - 0.08, 0.28)
shape.lineTo(-0.728 + width, 0.28)
shape.lineTo(-0.728 + width, -0.358 + depth - dd)
shape.lineTo(-0.728 + width - dd, -0.358 + depth)
shape.lineTo(-0.728 + dd, -0.358 + depth)
shape.lineTo(-0.728, -0.358 + depth - dd)
// shape.lineTo(-0.728, -0.358 + dd);
// shape.closePath()
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.22, 0), new THREE.Vector3(0, 1.872, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
let geometry = new THREE.ExtrudeGeometry(shape, options)
const fd = 0.03
const shapeBf = new THREE.Shape()
shapeBf.moveTo(-0.728 + width - 0.08, -0.28)
shapeBf.lineTo(-0.728 + width + 0.02, -0.28)
shapeBf.lineTo(-0.728 + width + 0.02, -0.25)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130 - fd, -0.25)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130, -0.25 + fd)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130, -0.14 - fd)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130 - fd, -0.14)
shapeBf.lineTo(-0.728 + width + 0.02, -0.14)
shapeBf.lineTo(-0.728 + width + 0.02, 0.14)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130 - fd, 0.14)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130, 0.14 + fd)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130, 0.25 - fd)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130 - fd, 0.25)
shapeBf.lineTo(-0.728 + width + 0.02, 0.25)
shapeBf.lineTo(-0.728 + width + 0.02, 0.28)
shapeBf.lineTo(-0.728 + width - 0.08, 0.28)
shapeBf.closePath()
// 拉伸轨迹线
const curveBf = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.02, 0), new THREE.Vector3(0, 0.06, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const optionsBf = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curveBf // 设置挤出轨迹
}
// 创建挤出几何体
const geometryBf = new THREE.ExtrudeGeometry(shapeBf, optionsBf)
geometry = mergeGeometries([geometry, geometryBf])
const material = new THREE.MeshBasicMaterial({color: 0xffdddbca})
const mesh = new THREE.Mesh(geometry, material)
const shapeD = new THREE.Shape()
shapeD.moveTo(-0.3, -0.25)
shapeD.lineTo(-0.3, 0.25)
shapeD.lineTo(0.3, 0.25)
shapeD.lineTo(0.3, -0.25)
shapeD.closePath()
const curveD = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 1.45, -1), new THREE.Vector3(0, 1.45, 1)],
false, // 闭合曲线
'catmullrom',
0
)
const optionsD = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curveD // 设置挤出轨迹
}
const geometryD = new THREE.ExtrudeGeometry(shapeD, optionsD)
const meshD = new THREE.Mesh(geometryD, material)
mesh.updateMatrix()
meshD.updateMatrix()
const result = CSG.subtract(mesh, meshD)
return result.geometry
}
// 创建ptr的立柱
public static createPtrFork(): THREE.BufferGeometry {
// 606.5
const width = 0.245
const depth = 0.716
const dd = 0.05
const fd = 0.03
const shape = new THREE.Shape()
shape.moveTo(-0.728 + width - 0.08, -0.28)
shape.lineTo(-0.728 + width + 0.02, -0.28)
shape.lineTo(-0.728 + width + 0.02, -0.27)
shape.lineTo(-0.728 + width + 0.02 + 1.130 - fd, -0.27)
shape.lineTo(-0.728 + width + 0.02 + 1.130, -0.27 + fd)
shape.lineTo(-0.728 + width + 0.02 + 1.130, -0.12 - fd)
shape.lineTo(-0.728 + width + 0.02 + 1.130 - fd, -0.12)
shape.lineTo(-0.728 + width + 0.02, -0.12)
shape.lineTo(-0.728 + width + 0.02, 0.12)
shape.lineTo(-0.728 + width + 0.02 + 1.130 - fd, 0.12)
shape.lineTo(-0.728 + width + 0.02 + 1.130, 0.12 + fd)
shape.lineTo(-0.728 + width + 0.02 + 1.130, 0.27 - fd)
shape.lineTo(-0.728 + width + 0.02 + 1.130 - fd, 0.27)
shape.lineTo(-0.728 + width + 0.02, 0.27)
shape.lineTo(-0.728 + width + 0.02, 0.28)
shape.lineTo(-0.728 + width - 0.08, 0.28)
shape.closePath()
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.02, 0), new THREE.Vector3(0, 0.482, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
const geometry = new THREE.ExtrudeGeometry(shape, options)
const material = new THREE.MeshBasicMaterial({color: 0xffdddbca})
const mesh = new THREE.Mesh(geometry, material)
mesh.updateMatrix()
const shapeD = new THREE.Shape()
shapeD.moveTo(-0.728 + width + 0.02, -0.3)
shapeD.lineTo(-0.728 + width + 0.02 + 1.2, -0.3)
shapeD.lineTo(-0.728 + width + 0.02 + 1.2, 0.3)
shapeD.lineTo(-0.728 + width + 0.02, 0.3)
shape.closePath()
// 拉伸轨迹线
const curveD = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.07, 0), new THREE.Vector3(0, 0.482, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const optionsD = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curveD // 设置挤出轨迹
}
// 创建挤出几何体
const geometryD = new THREE.ExtrudeGeometry(shapeD, optionsD)
const meshD = new THREE.Mesh(geometryD, material)
meshD.updateMatrix()
// 布尔运算
const result = CSG.subtract(mesh, meshD)
return result.geometry
}
public static ptrPedestalGeometry: THREE.BufferGeometry = null
public static ptrPillarGeometry: THREE.BufferGeometry = null
public static ptrForkGeometry: THREE.BufferGeometry = null
}

475
src/modules/cl2/Cl23dObject.ts

@ -1,37 +1,12 @@
import * as THREE from 'three' import * as THREE from 'three'
import { CSG } from 'three-csg-ts' import { CSG } from 'three-csg-ts'
//@ts-ignore
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js'
import gsap from 'gsap' import gsap from 'gsap'
import mqtt from 'mqtt' import mqtt from 'mqtt'
import { Euler } from 'three/src/math/Euler' import { Euler } from 'three/src/math/Euler'
import Cl2Entity from '@/modules/cl2/Cl2Entity' import Cl2Entity from '@/modules/cl2/Cl2Entity'
import Cl23DGraphics from "@/modules/cl2/Cl23DGraphics"
import {AmrErrorCode, AmrMsg, AmrMsg10010, AmrMsg20020, AmrMsg20149, AmrMsg20250, type LogicDirection} from "@/core/manager/amr/AmrMessageDefine";
export interface Cl2Task {
// 0:运输 1:接货 2:卸货 3:充电 4:提升移栽取货或卸货 5:滚筒取货或卸货(双向作业) 135:旋转货架 136:旋转车身
id: number;
content: {
SeqNo: number;
OperationType: 0 | 1 | 2 | 3 | 4 | 5 | 135 | 136;
UseBriefLocation: boolean;
StartX: number;
StartY: number;
EndX: number;
EndY: number;
EndDirection: 0 | 1 | 2 | 3 | 15;
// 0:不控制(无动作) 1:从货架上取货 2:将货物放到货架上 3:仅调整托盘高度(不进行取放货操作) 4:调整车身货物(仅供调试,RCS勿发送此命令) 5:仅调整载货台到取货高度,但是不动作 6:仅调整载货台到放货高度,但是不动作
PickMode: 0 | 1 | 2 | 3 | 4 | 5 | 6;
GoodsSlotHeight: number;
GoodsSlotDirection: 0 | 1 | 2 | 3 | 15;
GoodsId: string;
Link: {
// id: string; // 实际报文没有
X: number;
Y: number;
Speed: number;
}[]
}
}
interface Task { interface Task {
SeqNo: number; SeqNo: number;
@ -46,293 +21,6 @@ interface Task {
export default class Cl23dObject extends THREE.Object3D { export default class Cl23dObject extends THREE.Object3D {
// 创建ptr的底座
private static createPtrPedestal(): THREE.BufferGeometry {
// 参数配置
const radius = 0.8 // 圆半径
const lineDist = 0.75 // 切割线距离圆心距离
const segments = 64 // 圆的分段精度
// 计算切割线与圆的交点
const intersectY = Math.sqrt(radius * radius - lineDist * lineDist)
const startAngle = Math.asin(intersectY / radius)
const endAngle = Math.acos(intersectY / radius)
const shape = new THREE.Shape()
shape.moveTo(0, 0) // 起点在圆心
shape.absarc(0, 0, 0.8, startAngle, endAngle, false) // 从0到π绘制半圆
shape.absarc(0, 0, 0.8, startAngle + Math.PI / 2, endAngle + Math.PI / 2, false)
shape.absarc(0, 0, 0.8, startAngle + Math.PI, endAngle + Math.PI, false)
shape.absarc(0, 0, 0.8, startAngle + Math.PI / 2 * 3, endAngle + Math.PI / 2 * 3, false)
shape.lineTo(-0.5, -intersectY)
shape.lineTo(-0.5, -intersectY + 0.17)
shape.lineTo(0.75, -intersectY + 0.17)
shape.lineTo(0.75, intersectY - 0.17)
shape.lineTo(-0.5, intersectY - 0.17)
shape.lineTo(-0.5, intersectY)
shape.closePath() // 闭合路径
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.02, 0), new THREE.Vector3(0, 0.22, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelEnabled: false,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
const geometry = new THREE.ExtrudeGeometry(shape, options)
const material = new THREE.MeshBasicMaterial({ color: 0xffdddbca })
const mesh = new THREE.Mesh(geometry, material)
mesh.updateMatrix()
// 倒角
const shapeD = new THREE.Shape()
shapeD.moveTo(-0.02, -0.02)
shapeD.lineTo(0.02, 0.02)
shapeD.lineTo(-0.02, 0.02)
shapeD.closePath()
const curveD = new THREE.EllipseCurve(
0, 0, radius, radius, 0, Math.PI * 2, false, 0
)
// 生成拉伸路径点
const pointsD = curveD.getPoints(segments).map(p =>
new THREE.Vector3(p.x, 0.20, p.y)
)
// 3. 挤出成型
const optionsD = {
steps: segments,
bevelEnabled: false,
// bevelSegments: 0.01,
extrudePath: new THREE.CatmullRomCurve3(pointsD)
}
const geometryD = new THREE.ExtrudeGeometry(shapeD, optionsD)
const meshD = new THREE.Mesh(geometryD, material)
meshD.updateMatrix()
// 布尔运算
const result = CSG.subtract(mesh, meshD)
return result.geometry
}
// 创建ptr的立柱
private static createPtrPillar(): THREE.BufferGeometry {
// 606.5
const width = 0.245
const depth = 0.716
const dd = 0.05
const shape = new THREE.Shape()
shape.moveTo(-0.728, -0.358 + dd)
shape.lineTo(-0.728 + dd, -0.358)
shape.lineTo(-0.728 + width - dd, -0.358)
shape.lineTo(-0.728 + width, -0.358 + dd)
shape.lineTo(-0.728 + width, -0.28)
shape.lineTo(-0.728 + width - 0.08, -0.28)
shape.lineTo(-0.728 + width - 0.08, 0.28)
shape.lineTo(-0.728 + width, 0.28)
shape.lineTo(-0.728 + width, -0.358 + depth - dd)
shape.lineTo(-0.728 + width - dd, -0.358 + depth)
shape.lineTo(-0.728 + dd, -0.358 + depth)
shape.lineTo(-0.728, -0.358 + depth - dd)
// shape.lineTo(-0.728, -0.358 + dd);
// shape.closePath()
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.22, 0), new THREE.Vector3(0, 1.872, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
let geometry = new THREE.ExtrudeGeometry(shape, options)
const fd = 0.03
const shapeBf = new THREE.Shape()
shapeBf.moveTo(-0.728 + width - 0.08, -0.28)
shapeBf.lineTo(-0.728 + width + 0.02, -0.28)
shapeBf.lineTo(-0.728 + width + 0.02, -0.25)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130 - fd, -0.25)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130, -0.25 + fd)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130, -0.14 - fd)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130 - fd, -0.14)
shapeBf.lineTo(-0.728 + width + 0.02, -0.14)
shapeBf.lineTo(-0.728 + width + 0.02, 0.14)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130 - fd, 0.14)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130, 0.14 + fd)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130, 0.25 - fd)
shapeBf.lineTo(-0.728 + width + 0.02 + 1.130 - fd, 0.25)
shapeBf.lineTo(-0.728 + width + 0.02, 0.25)
shapeBf.lineTo(-0.728 + width + 0.02, 0.28)
shapeBf.lineTo(-0.728 + width - 0.08, 0.28)
shapeBf.closePath()
// 拉伸轨迹线
const curveBf = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.02, 0), new THREE.Vector3(0, 0.06, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const optionsBf = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curveBf // 设置挤出轨迹
}
// 创建挤出几何体
const geometryBf = new THREE.ExtrudeGeometry(shapeBf, optionsBf)
geometry = mergeGeometries([geometry, geometryBf])
const material = new THREE.MeshBasicMaterial({ color: 0xffdddbca })
const mesh = new THREE.Mesh(geometry, material)
const shapeD = new THREE.Shape()
shapeD.moveTo(-0.3, -0.25)
shapeD.lineTo(-0.3, 0.25)
shapeD.lineTo(0.3, 0.25)
shapeD.lineTo(0.3, -0.25)
shapeD.closePath()
const curveD = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 1.45, -1), new THREE.Vector3(0, 1.45, 1)],
false, // 闭合曲线
'catmullrom',
0
)
const optionsD = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curveD // 设置挤出轨迹
}
const geometryD = new THREE.ExtrudeGeometry(shapeD, optionsD)
const meshD = new THREE.Mesh(geometryD, material)
mesh.updateMatrix()
meshD.updateMatrix()
const result = CSG.subtract(mesh, meshD)
return result.geometry
}
// 创建ptr的立柱
private static createPtrFork(): THREE.BufferGeometry {
// 606.5
const width = 0.245
const depth = 0.716
const dd = 0.05
const fd = 0.03
const shape = new THREE.Shape()
shape.moveTo(-0.728 + width - 0.08, -0.28)
shape.lineTo(-0.728 + width + 0.02, -0.28)
shape.lineTo(-0.728 + width + 0.02, -0.27)
shape.lineTo(-0.728 + width + 0.02 + 1.130 - fd, -0.27)
shape.lineTo(-0.728 + width + 0.02 + 1.130, -0.27 + fd)
shape.lineTo(-0.728 + width + 0.02 + 1.130, -0.12 - fd)
shape.lineTo(-0.728 + width + 0.02 + 1.130 - fd, -0.12)
shape.lineTo(-0.728 + width + 0.02, -0.12)
shape.lineTo(-0.728 + width + 0.02, 0.12)
shape.lineTo(-0.728 + width + 0.02 + 1.130 - fd, 0.12)
shape.lineTo(-0.728 + width + 0.02 + 1.130, 0.12 + fd)
shape.lineTo(-0.728 + width + 0.02 + 1.130, 0.27 - fd)
shape.lineTo(-0.728 + width + 0.02 + 1.130 - fd, 0.27)
shape.lineTo(-0.728 + width + 0.02, 0.27)
shape.lineTo(-0.728 + width + 0.02, 0.28)
shape.lineTo(-0.728 + width - 0.08, 0.28)
shape.closePath()
// 拉伸轨迹线
const curve = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.02, 0), new THREE.Vector3(0, 0.482, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const options = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curve // 设置挤出轨迹
}
// 创建挤出几何体
const geometry = new THREE.ExtrudeGeometry(shape, options)
const material = new THREE.MeshBasicMaterial({ color: 0xffdddbca })
const mesh = new THREE.Mesh(geometry, material)
mesh.updateMatrix()
const shapeD = new THREE.Shape()
shapeD.moveTo(-0.728 + width + 0.02, -0.3)
shapeD.lineTo(-0.728 + width + 0.02 + 1.2, -0.3)
shapeD.lineTo(-0.728 + width + 0.02 + 1.2, 0.3)
shapeD.lineTo(-0.728 + width + 0.02, 0.3)
shape.closePath()
// 拉伸轨迹线
const curveD = new THREE.CatmullRomCurve3(
[new THREE.Vector3(0, 0.07, 0), new THREE.Vector3(0, 0.482, 0)],
false, // 闭合曲线
'catmullrom',
0
)
// 挤出几何图形 参数
const optionsD = {
steps: 1,
bevelSegments: 0.05,
bevelEnabled: true,
extrudePath: curveD // 设置挤出轨迹
}
// 创建挤出几何体
const geometryD = new THREE.ExtrudeGeometry(shapeD, optionsD)
const meshD = new THREE.Mesh(geometryD, material)
meshD.updateMatrix()
// 布尔运算
const result = CSG.subtract(mesh, meshD)
return result.geometry
}
private static ptrPedestalGeometry: THREE.BufferGeometry = null
private static ptrPillarGeometry: THREE.BufferGeometry = null
private static ptrForkGeometry: THREE.BufferGeometry = null
private item: ItemJson private item: ItemJson
private _cl2Entity: Cl2Entity = null private _cl2Entity: Cl2Entity = null
@ -345,8 +33,11 @@ export default class Cl23dObject extends THREE.Object3D {
private riseAnimation: core.Tween = null private riseAnimation: core.Tween = null
private stretchAnimation: core.Tween = null private stretchAnimation: core.Tween = null
private currentAnimation: core.Tween = null private currentAnimation: core.Tween = null
private currentDirection: number = 15 private currentDirection: LogicDirection = 15
private bootTime: number = 0
private seqNoName: string = ""
public get cl2Entity(): Cl2Entity { public get cl2Entity(): Cl2Entity {
if (!this._cl2Entity) { if (!this._cl2Entity) {
@ -362,26 +53,26 @@ export default class Cl23dObject extends THREE.Object3D {
super() super()
console.log('time', this.clock.getElapsedTime()) console.log('time', this.clock.getElapsedTime())
this.item = item this.item = item
if (!Cl23dObject.ptrPedestalGeometry) { if (!Cl23DGraphics.ptrPedestalGeometry) {
Cl23dObject.ptrPedestalGeometry = Cl23dObject.createPtrPedestal() Cl23DGraphics.ptrPedestalGeometry = Cl23DGraphics.createPtrPedestal()
} }
const ptrPedestalGeometry = Cl23dObject.ptrPedestalGeometry const ptrPedestalGeometry = Cl23DGraphics.ptrPedestalGeometry
const ptrPedestalMaterial = new THREE.MeshPhongMaterial({ color: 0xffdddbca }) const ptrPedestalMaterial = new THREE.MeshPhongMaterial({ color: 0xffdddbca })
const ptrPedestalMesh = new THREE.Mesh(ptrPedestalGeometry, ptrPedestalMaterial) const ptrPedestalMesh = new THREE.Mesh(ptrPedestalGeometry, ptrPedestalMaterial)
ptrPedestalMesh.name = 'ptrPedestal' ptrPedestalMesh.name = 'ptrPedestal'
if (!Cl23dObject.ptrPillarGeometry) { if (!Cl23DGraphics.ptrPillarGeometry) {
Cl23dObject.ptrPillarGeometry = Cl23dObject.createPtrPillar() Cl23DGraphics.ptrPillarGeometry = Cl23DGraphics.createPtrPillar()
} }
const ptrPillarGeometry = Cl23dObject.ptrPillarGeometry const ptrPillarGeometry = Cl23DGraphics.ptrPillarGeometry
const ptrPillarMaterial = new THREE.MeshPhongMaterial({ color: 0xff6c6956 }) const ptrPillarMaterial = new THREE.MeshPhongMaterial({ color: 0xff6c6956 })
const ptrPillarMesh = new THREE.Mesh(ptrPillarGeometry, ptrPillarMaterial) const ptrPillarMesh = new THREE.Mesh(ptrPillarGeometry, ptrPillarMaterial)
if (!Cl23dObject.ptrForkGeometry) { if (!Cl23DGraphics.ptrForkGeometry) {
Cl23dObject.ptrForkGeometry = Cl23dObject.createPtrFork() Cl23DGraphics.ptrForkGeometry = Cl23DGraphics.createPtrFork()
} }
const ptrForkGeometry = Cl23dObject.ptrForkGeometry const ptrForkGeometry = Cl23DGraphics.ptrForkGeometry
const ptrForkMaterial = new THREE.MeshPhongMaterial({ color: 0xff444444 }) const ptrForkMaterial = new THREE.MeshPhongMaterial({ color: 0xff444444 })
const ptrForkMesh = new THREE.Mesh(ptrForkGeometry, ptrForkMaterial) const ptrForkMesh = new THREE.Mesh(ptrForkGeometry, ptrForkMaterial)
ptrForkMesh.name = 'ptrFork' ptrForkMesh.name = 'ptrFork'
@ -393,48 +84,82 @@ export default class Cl23dObject extends THREE.Object3D {
groupPillar.add(ptrForkMesh) groupPillar.add(ptrForkMesh)
this.add(groupPillar) this.add(groupPillar)
try { this.seqNoName = 'CL2' + this.cl2Entity.id
// 安全连接配置
// const client = mqtt.connect('mqtt://127.0.0.1:9001', {
// path: '/mqtt',
// clientId: 'virtual-' + item.id,
// clean: true,
// connectTimeout: 10000,
// username: 'user',
// password: 'user',
// unixSocket: true,
// keepalive: 60
// })
const client = {
on() {
}
}
// debugger
/*
// 事件绑定
client.on('connect', () => {
console.log('Connected')
client.subscribe(['/wcs_server/' + item.id], { qos: 0 })
client.publish('/agv_robot/status', JSON.stringify(m20020), { retain: true })
})
client.on('message', (topic, msg) => { }
console.log(`[${topic}] ${msg}`)
const a: Cl2Task = JSON.parse(msg.toString())
this.handleMessage(a)
}) private AGVModel = "CYBER-LIFT-A_V1.0"
private AGVFnModel = "FITBOTS-CYBER-LIFT-1000_V1.0"
client.on('error', (error) => {
console.error('Error:', error) // 开机
}) boot() {
*/ this.bootTime = Date.now();
} catch (e) { this.computeLogicDirection();
console.error(e) this.subscribeMessage('/wcs_server/' + this.cl2Entity.id)
setTimeout(()=>{
this.send20149()
// 检查当前所在位置和方向 根据车当前所在的xz坐标获取地标
setTimeout(()=>{
this.sendCurrentPositionAndDirection()
}, 1000)
}, 2000)
}
// 关机
shutdown() {
}
// 主程序启动上报
send20149() {
const content = new AmrMsg20149()
content.AGVModel = this.AGVModel
content.AGVFnModel = this.AGVFnModel
// 电量
content.Battery = 100
content.CreateMonoTime = Date.now() - this.bootTime
content.VehicleId = parseInt(this.cl2Entity.id)
const m20149 = new AmrMsg<AmrMsg20149>(content)
this.sendMessage(m20149)
}
// 上报当前位姿,地标和方向
sendCurrentPositionAndDirection() {
const pointItem = Model.getItemByXYZ(this.position.x, this.position.y, this.position.z)
if (!pointItem || !pointItem.logicX || !pointItem.logicY) {
// 当前车辆所在位置未找到
const content = new AmrMsg20250()
content.Duration = 0
content.ErrCode = 5
content.ErrCodeName = AmrErrorCode[5].ErrCodeName
content.ErrEvtType = 1
content.ErrLevel = 14
content.ErrLifecycle = 2
content.CreateMonoTime = Date.now() - this.bootTime
content.VehicleId = parseInt(this.cl2Entity.id)
const m20250 = new AmrMsg<AmrMsg20250>(content)
this.sendMessage(m20250)
} else {
// 发送正常地标信息
const content = new AmrMsg20020()
content.CurDirection = this.currentDirection
content.CurLogicX = pointItem.logicX
content.CurLogicY = pointItem.logicY
content.CurX = pointItem.logicX
content.CurY = pointItem.logicY
content.CreateMonoTime = Date.now() - this.bootTime
content.VehicleId = parseInt(this.cl2Entity.id)
const m20020 = new AmrMsg<AmrMsg20020>(content)
this.sendMessage(m20020)
} }
} }
subscribeMessage(topic: string) {
this.cl2Entity.viewport.envManager.client.subscribe(topic, { qos: 0 })
}
sendMessage(msg: AmrMsg<any>) {
this.cl2Entity.viewport.envManager.client.publish('/agv_robot/status', JSON.stringify(msg))
}
/*==========消息处理============*/ /*==========消息处理============*/
@ -463,7 +188,7 @@ export default class Cl23dObject extends THREE.Object3D {
client.publish('/agv_robot/status', JSON.stringify(m20020), { retain: true }) client.publish('/agv_robot/status', JSON.stringify(m20020), { retain: true })
} }
handleMessage(data: Cl2Task) { handleMessage(data: AmrMsg<AmrMsg10010>) {
return return
if (data.id === 10010) { if (data.id === 10010) {
@ -535,6 +260,32 @@ export default class Cl23dObject extends THREE.Object3D {
} }
} }
// 计算逻辑方向
computeLogicDirection() {
let ra = this.rotation.y
while (ra > Math.PI * 2) {
ra -= Math.PI * 2
}
while (ra < 0) {
ra += Math.PI * 2
}
const ddra = Math.PI/8
if (ra >= ddra * 7 || ra < ddra) {
this.currentDirection = 0;
} else if (ra >= ddra && ra < ddra * 3) {
this.currentDirection = 3;
} else if (ra >= ddra * 3 && ra < ddra * 5) {
this.currentDirection = 2;
} else if (ra >= ddra * 5 && ra < ddra * 7) {
this.currentDirection = 1;
} else {
this.currentDirection = 15;
}
}
executeTask() { executeTask() {
if (this.currentAnimation) { if (this.currentAnimation) {
@ -720,3 +471,5 @@ export default class Cl23dObject extends THREE.Object3D {
// }, 2000) // }, 2000)
} }

4
src/modules/cl2/Cl2PropertySetter.ts

@ -13,6 +13,10 @@ const propertySetter: PropertySetter = {
dataPath: 'dt.palletDepth', label: '托盘深度', input: 'InputNumber', dataPath: 'dt.palletDepth', label: '托盘深度', input: 'InputNumber',
inputProps: {}, inputProps: {},
}, },
{
dataPath: 'state', label: 'ptr控制', input: 'PtrController',
inputProps: {},
},
], ],
}, },
}; };

Loading…
Cancel
Save