本章内容主要讲解工业仿真软件里面的装配站实体和拆卸站实体,首先看两者的定义
简介
装配站是什么
装配站是生产线上的一个特定工位,在这个工位上,操作工人和/或自动化设备将多个零件、部件或子系统按照设计要求组合、连接、安装在一起,最终形成一个功能更完整的产品或半成品。
拆卸站是什么
拆卸站是一个专门用于将成品、半成品或退回产品进行系统性分解,拆解成其组成部分的工位。
两者的区别
设计与开发
首先我们来看装配站
装配站设计思路
装配站是将多个产品结合成一个产品,假如是装配站前面只有一个设备加工站,那么装配站可以指定设备A必须传进来指定的产品数量,才能继续加工
如果装配站前面有多个设备,如下图
那么用户在使用装配站时,就必须指定设备ABC三台设备需要加工的,那么我们就需要在装配站里面维护一个设备加工数量映射表,类似于下面
设备A:A(n)
设备B:B(n)
设备C:C(n)
并且还需要再维护一个当前已传入产品的设备映射表
设备A:A(m)
设备B:B(m)
设备C:C(m)
到这一步,我们就可以梳理一个大致的加工逻辑
- 当有产品传入时,需要先判断是否需要这个产品
- 如果 m < n ,就表示可以接受该产品,负责就拒绝该产品
- 当接收到新产品后,在判断现有的条件是否满足加工条件
- 加工完毕后,进行派发产品,清空所有 m
接下来我们看代码实现
装配站代码实现
1. 属性值
processTime: randomTime // 加工时间
requiredInputs: RequiredInputMap // 每个来源站点需要的产品数量
bufferMap: SourceProductMap = {} // 当前装配站上已有产品的设备映射表
currentNewProduct: Product | null = null // 新的产品
productWidth: number // 新产品宽度
productHeight: number // 新产品高度
2. 接收产品方法
//判断是否可以接收上游传递的产品
public canReceiveProduct(name: string): boolean {
if (this.status !== 'idle') {
return false
}
if (this.bufferMap[name] === undefined) {
return true
}
if (this.bufferMap[name].length < this.requiredInputs[name]) {
return true
}
return false
}
//接受就绪产品
receiveReadyProduct(productId: string): void {
if (this.status === 'idle') {
this.readyProduct = productId
const product = getReadyProduct(productId)
if (!product) {
console.log(`[${currentTime}] ❌ ${productId} 没有发现`)
return
}
console.log(`[${currentTime}] ${product.id} 已到达 --> ${this.name}`)
this.onProductReceived(product)
} else {
console.log(`[${currentTime}] ${this.name} 不在空闲状态,无法接收产品 ${productId}`)
}
}
3. 合成产品
protected onProductReceived(product: Product): void {
const source = product.from || 'unknown'
product.setFrom(this.id)
console.log(`[${currentTime}] ${product.id} 到达装配站 ${this.name},来自 ${source}`)
messageTransfer('product', 'move', { targetId: this.id, productId: product.id })
// 将产品加入对应来源的缓存
if (!this.bufferMap[source]) {
this.bufferMap[source] = []
}
this.bufferMap[source].push(product)
// 检查是否满足所有来源的数量要求
this.tryAssemble()
}
//判断是否可以开始装配
private canAssemble(): boolean {
for (const [source, requiredCount] of Object.entries(this.requiredInputs)) {
if (
!this.bufferMap[source] ||
this.bufferMap[source].length === 0 ||
this.bufferMap[source].length < requiredCount
) {
return false
}
}
return true
}
private tryAssemble(): void {
if (!this.canAssemble()) return
this.setStatus('processing')
const parts: Product[] = []
for (const [source, count] of Object.entries(this.requiredInputs)) {
const group = this.bufferMap[source].splice(0, count)
parts.push(...group)
}
// 生成新的产品
const newProduct = new Product(generateUUID(), this.productWidth, this.productHeight)
this.currentNewProduct = newProduct
messageTransfer('product', 'generate', { targetId: this.id, productId: newProduct.id })
messageTransfer('product', 'startProcessing', { targetId: this.id, productId: newProduct.id })
this.currentNewProduct = newProduct
// 消除旧的产品
for (const p of parts) {
messageTransfer('product', 'recycle', {
targetId: this.id,
productId: p.id
})
}
messageTransfer('product', 'startProcessing', {
targetId: this.id,
productId: newProduct.id
})
const time = typeof this.processTime === 'function' ? this.processTime() : this.processTime
console.log(`[${currentTime}] 🛠️ ${this.name} 开始装配 ${newProduct.id}`)
schedule(time, () => this.finishAssemble(newProduct), `${this.id} 完成装配 ${newProduct.id}`)
}
private finishAssemble(newProduct: Product): void {
messageTransfer('product', 'finishProcessing', { targetId: this.id, productId: newProduct.id })
//当前产品添加到就绪产品队列中
addReadyProduct(newProduct)
//产品加工完毕,尝试派发产品
this.setStatus('block')
}
新产品在加工完毕后,会将状态改为block
此时 setStatus () 方法会触发设备调度器调度功能,自动寻找下一站空闲的设备
4. 派发产品
派发产品功能和加工站实体类一致,都是寻找下游空闲设备,然后将新产品派发给它
tryDispatchCurrentProduct(): void {
if (!this.currentNewProduct) return
const productId = this.currentNewProduct.id
for (const next of this.nextStations) {
if (next.canReceiveProduct(this.id, this.currentNewProduct)) {
this.currentNewProduct = null
next.receiveReadyProduct(productId)
//清空缓冲区
for (const key of Object.keys(this.bufferMap)) {
this.bufferMap[key] = []
}
this.setStatus('idle')
break
}
}
}
装配站仿真逻辑介绍到这,接下来介绍拆卸站
拆卸站设计思路
拆卸站是将一个产品拆成多个产品,如下图所示,拆卸站后面有三台设备,如果拆卸站的拆卸数量为4,则在拆卸时提示错误,【拆卸的数量不能多余下游设备数量】
若拆卸数量小于下游设备数量,例如拆卸数量为2,则下游三台设备将会有一台设备不会分的产品
并且只有在设备ABC 三台设备都处于空闲状态时,拆卸站才会将已拆好的产品派发给三台设备
拆卸站代码实现
1. 属性值
processTime: randomTime // 拆卸时间
dismantlingQuantity: number // 拆卸数量
private splitProduts: Product[] = [] // 拆卸后新产品的数组
productWidth: number // 新产品宽度
productHeight: number // 新产品高度
2. 接收产品
public canReceiveProduct(): boolean {
return this.status === 'idle'
}
protected onProductReceived(product: Product): void {
messageTransfer('product', 'move', { targetId: this.id, productId: product.id })
messageTransfer('product', 'startProcessing', { targetId: this.id, productId: product.id })
console.log(`[${currentTime}] ${product.id} 到达拆解站 --> ${this.name}`)
this.tryDisassamble(product)
}
private tryDisassamble(product: Product): void {
this.setStatus('processing')
const time = typeof this.processTime === 'function' ? this.processTime() : this.processTime
schedule(time, () => this.disassemble(product), `${this.id} 拆解 ${product.id}`)
}
3. 拆解产品
private disassemble(product: Product): void {
console.log(`[${currentTime}] ${this.name} 拆出 ${this.dismantlingQuantity} 个部件`)
messageTransfer('product', 'recycle', {
targetId: this.id,
productId: product.id
})
const parts: Product[] = []
for (let i = 0; i < this.dismantlingQuantity; i++) {
const newPart = new Product(generateUUID(), this.productWidth, this.productHeight)
newPart.setFrom(this.id)
parts.push(newPart)
messageTransfer('product', 'generate', { targetId: this.id, productId: newPart.id })
}
this.splitProduts = parts
this.setStatus('block')
}
4. 派发产品
public tryDispatchCurrentProduct(): void {
if (this.nextStations.length < this.dismantlingQuantity) {
console.warn(`[${currentTime}] ⚠️ ${this.id} 的下游站点数量不足`)
return
}
let mark = false
for (const next of this.nextStations) {
if (!next.canReceiveProduct(this.id, this.splitProduts[0])) {
mark = true
break
}
}
if (mark) {
console.log(`[${currentTime}] ⛔ ${this.name} 下游不空闲,等待中...`)
return
} else {
for (let i = 0; i < this.splitProduts.length; i++) {
const product = this.splitProduts[i]
const station = this.nextStations[i]
addReadyProduct(product)
station.receiveReadyProduct(product.id)
}
this.setStatus('idle')
}
}
装配站和拆卸站的仿真逻辑就讲到这里,谢谢大家