Browse Source

LccMqttManager /

EnvManager 脱离 viewport 也能运行
master
修宁 6 months ago
parent
commit
b6e85fdc56
  1. 4
      src/core/engine/Viewport.ts
  2. 80
      src/core/manager/EnvManager.ts
  3. 9
      src/core/manager/LccMqttManager.ts
  4. 10
      src/core/manager/WorldModel.ts
  5. 42
      src/core/manager/amr/AmrMessageManager.ts
  6. 71
      src/core/script/LCCScript.ts
  7. 5
      src/core/script/ModelManager.ts
  8. 6
      src/core/script/RCSScript.ts
  9. 6
      src/editor/ModelMain.vue
  10. 16
      src/types/LCC.d.ts

4
src/core/engine/Viewport.ts

@ -52,8 +52,6 @@ export default class Viewport {
interactionManager = new InteractionManager()
modelManager = new ModelManager()
runtimeManager = new RuntimeManager()
lccMqttManager = new LccMqttManager()
envManager = new EnvManager()
// 状态管理器
stateManager: StateManager
@ -68,8 +66,6 @@ export default class Viewport {
markRaw(this.interactionManager),
markRaw(this.modelManager),
markRaw(this.runtimeManager),
markRaw(this.envManager),
markRaw(this.lccMqttManager)
]
registerFrameTimerCallBack: Map<string, ()=> void> = new Map()

80
src/core/manager/EnvManager.ts

@ -9,71 +9,9 @@ import { AmrMsg } from '@/core/manager/amr/AmrMessageDefine'
export default class EnvManager {
private viewport: Viewport
private amrMessageManager: AmrMessageManager = null
private amrMessageManager: AmrMessageManager = new AmrMessageManager()
public client: mqtt.MqttClient = null
init(viewport: Viewport): void {
this.viewport = viewport
if (!this.amrMessageManager) {
this.amrMessageManager = new AmrMessageManager()
}
this.amrMessageManager.viewport = viewport
}
// 从后台读取所有车
async loadExecutors() {
const res = await Request.request.post('/api/workbench/EnvController@getAllExecutor', {
projectUuid: worldModel.state.project_uuid,
catalogCode: worldModel.state.catalogCode,
envId: worldModel.state.runState.currentEnvId
})
for (const row of res.data) {
const executor_id = row.executor_id
const payload = JSON.parse(row.virtual_executor_payload)
// 车所在的标记位置,及方向 11_4:RIGHT
const [wayPointId, direction] = _.split(row.virtual_location_at, ':')
const point = Model.find(wayPointId)
if (!point) {
console.error(`Waypoint with ID ${wayPointId} not found for executor ${executor_id}.`)
continue
}
const item = _.cloneDeep(payload)
item.id = executor_id
item.tf[0] = _.cloneDeep(point.tf[0])
switch (_.toLower(direction)) {
// right=0/left=180/up=90/down=-90
case 'right':
item.tf[1][1] = 0 // 右侧
break
case 'left':
item.tf[1][1] = 180 // 左侧
break
case 'down':
item.tf[1][1] = -90 // 下方
break
case 'up':
item.tf[1][1] = 90 // 上方
break
}
Model.createExecutor(item)
}
}
appendExecutor(id) {
const obj = this.viewport.entityManager.findObjectById(id)
const item = this.viewport.entityManager.findItemById(id)
if (item.t == 'cl2' && obj.userData.t === 'cl2') {
debugger
const cl2 = obj as Cl23dObject
cl2.onMqttConnect(item, this.client)
// this.client.subscribe(['/wcs_server/' + cl2.id], { qos: 0 })
// this.client.publish('/agv_robot/status', JSON.stringify(m20020), { retain: true })
}
}
onMqttConnect = (packet: IConnackPacket) => {
console.log('Connected')
}
@ -86,7 +24,6 @@ export default class EnvManager {
} else {
}
}
onMqttError = (error: Error | ErrorWithReasonCode) => {
@ -102,10 +39,6 @@ export default class EnvManager {
system.showErrorDialog('WorldModel is not opened, cannot start EnvManager.')
return
}
if (!this.viewport) {
system.showErrorDialog('Viewport is not initialized, cannot start EnvManager.')
return
}
if (!worldModel.state.runState.currentEnvId) {
system.showErrorDialog('Current environment ID is not set, cannot start EnvManager.')
return
@ -129,8 +62,8 @@ export default class EnvManager {
worldModel.state.runState.isLoading = true
worldModel.state.runState.currentEnv = Object.freeze(env)
try {
await LCC.projectStart()
await this.loadExecutors()
await LCC.serverStart()
await LCC.loadExecutor()
await LCC.loadInv()
this.client = mqtt.connect(env.envConfig.mqtt.websocket, {
@ -144,7 +77,7 @@ export default class EnvManager {
keepalive: 60
})
this.viewport.lccMqttManager.start(env.envConfig.frontendMqtt)
await worldModel.lccMqttManager.start(env.envConfig.frontendMqtt)
this.client.on('connect', this.onMqttConnect)
this.client.on('message', this.onMqttMessage)
this.client.on('error', this.onMqttError)
@ -159,8 +92,8 @@ export default class EnvManager {
async stop() {
system.showLoading()
try {
if (LCC) {
await LCC.projectStop()
if (window['LCC']) {
await LCC.serverStop()
}
worldModel.state.runState.isRunning = false
if (this.client) {
@ -214,7 +147,6 @@ export default class EnvManager {
*
*/
dispose(): void {
this.viewport = null
this.stop()
}
}

9
src/core/manager/LccMqttManager.ts

@ -20,15 +20,12 @@ enum ConnectionStatus {
ERROR = 'error'
}
// 定义LCC MQTT管理器类
/**
*
*/
export default class LccMqttManager {
private client: mqtt.MqttClient | null = null
private handlers: Map<string, MqttMessageHandler[]> = new Map()
private viewport: Viewport
init(viewport: Viewport): void {
this.viewport = viewport
}
// 状态管理
public state = reactive({

10
src/core/manager/WorldModel.ts

@ -5,6 +5,10 @@ import EventBus from '@/runtime/EventBus'
import StateManager from '@/core/manager/StateManager.ts'
import { getQueryParams, setQueryParam } from '@/utils/webutils.ts'
import localforage from 'localforage'
import LccMqttManager from '@/core/manager/LccMqttManager.ts'
import EnvManager from '@/core/manager/EnvManager.ts'
import RCSScript from '@/core/script/RCSScript.ts'
import LCCScript from '@/core/script/LCCScript.ts'
export interface WorldModelState {
isOpened: boolean // 是否已打开世界模型
@ -36,6 +40,8 @@ export interface WorldModelState {
*/
export default class WorldModel {
currentStateManager: StateManager
lccMqttManager = new LccMqttManager()
envManager = new EnvManager()
/**
*
@ -56,7 +62,7 @@ export default class WorldModel {
isDraft: false, // 是否是草稿数据, 如果是草稿数据, 则不需要再从服务器加载数据
runState: {
currentEnvId: 0,
currentEnvId: null,
isLoading: false,
isRunning: false,
isVirtual: false,
@ -220,4 +226,6 @@ export default class WorldModel {
const worldModel = new WorldModel()
window['worldModel'] = worldModel
window['RCS'] = new RCSScript()
window['LCC'] = new LCCScript()
export { worldModel }

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

@ -1,61 +1,63 @@
import {AmrMsg, AmrMsg10010, AmrMsg10050, AmrMsg10060, AmrMsg10110, AmrMsg10120, AmrMsg20050} from "@/core/manager/amr/AmrMessageDefine";
import Cl23dObject from "@/modules/cl2/Cl23dObject";
import Viewport from "@/core/engine/Viewport";
import { AmrMsg, AmrMsg10010, AmrMsg10050, AmrMsg10060, AmrMsg10110, AmrMsg10120, 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
public get viewport(): Viewport {
return window['viewport']
}
handleMessage(topic, amrMsg: AmrMsg<any>) {
const vehicleId = parseInt(topic.replace("/wcs_server/", ""))
const amrItem = this.viewport.entityManager.findObjectById(vehicleId + "") as Cl23dObject
const vehicleId = parseInt(topic.replace('/wcs_server/', ''))
const amrItem = this.viewport.entityManager.findObjectById(vehicleId + '') as Cl23dObject
switch (amrMsg.id) {
// AMR作业指令 10010
case 10010:
amrItem.handle10010Message(amrMsg.content as AmrMsg10010)
break;
break
// 停止/解除 10040
case 10040:
break;
break
// 电文应答 10050
case 10050:
amrItem.handle10050Message(amrMsg as AmrMsg<AmrMsg10050>)
break;
break
// 配置信息 10060
case 10060:
amrItem.handle10060Message(amrMsg as AmrMsg<AmrMsg10060>)
break;
break
// 旋转货架 10080
case 10080:
break;
break
// 旋转车身 10081
case 10081:
break;
break
// 控制卷帘门 10082
case 10082:
break;
break
// 心跳 10100
case 10100:
break;
break
// 状态查询 10110
case 10110:
amrItem.handle10110Message(amrMsg as AmrMsg<AmrMsg10110>)
break;
break
// 取消已下发小车任务 10120
case 10120:
amrItem.handle10120Message(amrMsg as AmrMsg<AmrMsg10120>)
break;
break
// 设置小车坐标 10200
case 10200:
break;
break
// 等待就绪 19997
case 19997:
break;
break
}
if (amrMsg.id != 10050 && amrMsg.id != 10100) {
const seqNo = amrMsg.content.SeqNo;
amrItem.sendAck(seqNo, vehicleId);
const seqNo = amrMsg.content.SeqNo
amrItem.sendAck(seqNo, vehicleId)
}
}
}

71
src/core/script/LCCScript.ts

@ -6,43 +6,35 @@ import { Request } from '@ease-forge/shared'
* LCC API
*/
export default class LCCScript implements LCC {
private readonly viewport: Viewport
constructor(viewport: Viewport) {
this.viewport = viewport
}
async getAllProjects(): Promise<ServerResponse<LccProjectVo[]>> {
return Request.request.post('/api/workbench/LccController@getAllProjects', {
})
return Request.request.post('/api/workbench/LccController@getAllProjects', {})
}
async projectStart(): Promise<ServerResponse<boolean>> {
async serverStart(): Promise<ServerResponse<boolean>> {
if (!worldModel.state.project_uuid || !worldModel.state.runState.currentEnvId) {
return Promise.reject(new Error('Project UUID or Environment ID is not set.'))
}
return Request.request.post('/api/workbench/LccController@projectStart', {
return Request.request.post('/api/workbench/LccController@serverStart', {
projectUUID: worldModel.state.project_uuid,
envId: worldModel.state.runState.currentEnvId
})
}
async projectStop(): Promise<ServerResponse<boolean>> {
async serverStop(): Promise<ServerResponse<boolean>> {
if (!worldModel.state.project_uuid || !worldModel.state.runState.currentEnvId) {
return Promise.reject(new Error('Project UUID or Environment ID is not set.'))
}
return Request.request.post('/api/workbench/LccController@projectStop', {
return Request.request.post('/api/workbench/LccController@serverStop', {
projectUUID: worldModel.state.project_uuid,
envId: worldModel.state.runState.currentEnvId
})
}
// 从后台读取所有库存
async loadInv(): Promise<ServerResponse<InvVo>> {
const res = await Request.request.post('/api/workbench/LccController@getAllInv', {
const res = await Request.request.post('/api/workbench/LccController@loadInv', {
projectUuid: worldModel.state.project_uuid,
catalogCode: worldModel.state.catalogCode,
envId: worldModel.state.runState.currentEnvId
@ -55,8 +47,57 @@ export default class LCCScript implements LCC {
const lpn = row.lpn // : "LPN1"
const rack = row.rack // : "rack1"
const container_type = row.container_type // : "pallet"
Model.createInv(container_type, lpn, rack, bay, level, cell)
if (window['Model']) {
Model.createInv(container_type, lpn, rack, bay, level, cell)
}
}
return res.data
}
// 从后台读取所有车
async loadExecutor(): Promise<ServerResponse<ExecutorVo>> {
const res = await Request.request.post('/api/workbench/LccController@loadExecutor', {
projectUuid: worldModel.state.project_uuid,
envId: worldModel.state.runState.currentEnvId
})
for (const row of res.data) {
const executor_id = row.executor_id
const payload = JSON.parse(row.virtual_executor_payload)
// 车所在的标记位置,及方向 11_4:RIGHT
const [wayPointId, direction] = _.split(row.virtual_location_at, ':')
if (window['Model']) {
const point = Model.find(wayPointId)
if (!point) {
console.error(`Waypoint with ID ${wayPointId} not found for executor ${executor_id}.`)
continue
}
const item = _.cloneDeep(payload)
item.id = executor_id
item.tf[0] = _.cloneDeep(point.tf[0])
switch (_.toLower(direction)) {
// right=0/left=180/up=90/down=-90
case 'right':
item.tf[1][1] = 0 // 右侧
break
case 'left':
item.tf[1][1] = 180 // 左侧
break
case 'down':
item.tf[1][1] = -90 // 下方
break
case 'up':
item.tf[1][1] = 90 // 上方
break
}
if (row.virtual_floor_code === worldModel.state.catalogCode) {
Model.createExecutor(item)
}
}
}
return res.data
}
}

5
src/core/script/ModelManager.ts

@ -7,8 +7,6 @@ import TaskManager from '../manager/TaskManager.ts'
import Cl2Entity from '@/modules/cl2/Cl2Entity.ts'
import ClxEntity from '@/modules/clx/ClxEntity.ts'
import { getRenderer } from '@/core/manager/ModuleManager.ts'
import RCSScript from '@/core/script/RCSScript.ts'
import LCCScript from '@/core/script/LCCScript.ts'
export default class ModelManager implements IControls, Model {
private viewport: Viewport
@ -67,9 +65,6 @@ export default class ModelManager implements IControls, Model {
window['executestring'] = this.executestring.bind(this)
window['logger'] = this.logger
window['msg'] = this.msg
window['RCS'] = new RCSScript(this.viewport)
window['LCC'] = new LCCScript(this.viewport)
}
find(entityId: string): ItemJson {

6
src/core/script/RCSScript.ts

@ -3,12 +3,6 @@ import { Request } from '@ease-forge/shared'
import { worldModel } from '@/core/manager/WorldModel.ts'
export default class RCSScript implements RCS {
private readonly viewport: Viewport
constructor(viewport: Viewport) {
this.viewport = viewport
}
agvMove(agvId: string, targetWayPointId: string, targetDirection: '' | LLCDirection = '', option: AgvOptions = {}): Promise<ServerResponse<boolean>> {
return Request.request.post('/api/workbench/RcsController@agvMove', {
projectUUID: worldModel.state.project_uuid,

6
src/editor/ModelMain.vue

@ -13,7 +13,7 @@
</div>
<div v-if="isModelOpen" style="display: flex; flex-direction: row; align-items: center; margin-right: 10px;">
<div class="field-block" style="margin-right: 5px;">
<el-select style="width:180px;" placeholder="运行环境" :disabled="worldModelState.runState.currentEnvId && worldModelState.runState.isRunning"
<el-select style="width:180px;" placeholder="选择运行环境" :disabled="worldModelState.runState.currentEnvId && worldModelState.runState.isRunning"
v-model="currentEnvId">
<el-option v-for="env in envList" :key="env.envId" :label="env.envName" :value="env.envId"></el-option>
<template #footer>
@ -334,11 +334,11 @@ export default {
startEnv() {
const env = this.envList.find(env => env.envId === this.worldModelState.runState.currentEnvId)
if (env) {
this.currentViewport.envManager.start(env)
worldModel.envManager.start(env)
}
},
stopEnv() {
this.currentViewport.envManager.stop()
worldModel.envManager.stop()
},
createEnv() {
EnvManager.createEnv(this.worldModelState.project_uuid).then(() => {

16
src/types/LCC.d.ts

@ -10,17 +10,22 @@ declare interface LCC {
/**
*
*/
projectStart(): Promise<ServerResponse<boolean>>
serverStart(): Promise<ServerResponse<boolean>>
/**
*
*/
projectStop(): Promise<ServerResponse<boolean>>
serverStop(): Promise<ServerResponse<boolean>>
/**
* , Model
*/
loadInv(): Promise<ServerResponse<InvVo>>
/**
* Model
*/
loadExecutor(): Promise<ServerResponse<ExecutorVo>>
}
type ContainerT = 'pallet' | 'tote' | 'carton' | 'box'
@ -35,6 +40,13 @@ interface InvVo {
cell: number
}
interface ExecutorVo {
executor_id: string
virtual_floor_code: string
virtual_executor_payload: any
virtual_location_at: string
}
interface LccProjectVo {
projectUuid: string
projectLabel: string

Loading…
Cancel
Save