3. 工作站编排的核心对象建模

工作站编排系统要解决的第一个工程问题,不是“怎么调度”,而是“调度什么”。如果任务、动作、资源、物料、工位、设备状态和约束条件各自用一套私有数据结构描述,编排器就无法在统一语义下比较、排序和冲突消解。本节的目标是建立一套可落地的统一对象模型,让七类核心对象共享同一套标识、时间、状态和约束表达方式。

一、七类对象的职责边界

先明确每类对象“描述什么、不描述什么”,避免建模时职责重叠:

  • 任务(Task):面向业务目标的最小可调度单元,例如“完成工件A的装配”。任务本身不关心由谁执行,只声明目标、输入物料、期望产出和截止时间。
  • 动作(Action):任务分解后的可执行原子操作,例如“抓取”“拧紧”“拍照检测”。动作绑定具体设备能力,是编排器真正下发到控制器的粒度。
  • 资源(Resource):可被占用的执行能力,包括机器人、夹具、工具、AGV、相机等。资源有容量、可用时间窗和占用状态。
  • 物料(Material):被加工、搬运或检测的对象,具有批次、位置、工艺状态和追溯标识。
  • 工位(Station):物料停留和动作发生的物理位置,是资源与物料的交汇点,例如装配工位、检测工位、缓存位。
  • 设备状态(DeviceState):资源在某一时刻的运行态,如空闲、运行、故障、维护、离线。
  • 约束条件(Constraint):限制动作或任务可行性的规则,包括时序约束、资源互斥、工艺顺序、空间可达性和时间窗。

这七类对象不是并列孤立的,而是通过“任务—动作—资源—工位—物料”的执行链和“状态—约束”的可行性判定层耦合在一起。下图给出统一对象模型的关系结构:

任务 Task 目标 / 物料 / 截止时间 动作 Action 抓取 / 拧紧 / 检测 资源 Resource 机器人 / 夹具 / AGV 分解 绑定能力 工位 Station 装配位 / 检测位 / 缓存位 物料 Material 批次 / 位置 / 工艺状态 发生于 停留/流转 部署于 设备状态 DeviceState 空闲/运行/故障/维护 具有 约束条件 Constraint 时序约束 · 资源互斥 · 工艺顺序 · 空间可达性 · 时间窗 约束作用于任务、动作、资源、物料、工位之间的可行性判定 统一描述要素(所有对象共享) 全局唯一ID · 时间戳/时间窗 · 状态字段 · 约束引用 · 版本号 对象间通过ID引用,不嵌套复制,保证编排器可独立查询与更新

二、统一描述方法:共享字段与引用机制

统一建模的关键不是把所有对象塞进一个大结构体,而是让七类对象共享一组基础字段,并通过ID引用建立关系。建议每个对象至少包含以下公共字段:

字段含义示例
id全局唯一标识,前缀区分类型TASK-001、ACT-012、RES-RB02
type对象类型枚举task / action / resource / material / station / state / constraint
time_window有效时间窗或时间戳[t_start, t_end] 或单点时刻
status当前状态pending / ready / running / done / failed
constraints引用的约束ID列表[CON-003, CON-007]
version版本号,用于并发更新3

对象之间只存ID引用,不嵌套复制。例如动作对象中不直接写入机器人完整信息,只写 resource_ref: "RES-RB02";编排器需要时再查资源表。这样做的工程收益是:资源状态变化只需更新资源对象一处,所有引用它的动作自动获得最新状态,避免数据不一致。

三、约束条件的分类与表达

约束是统一模型中最容易被忽视、却最影响编排正确性的部分。按作用方式可分为四类:

  • 时序约束:动作A必须在动作B之前完成,表达为 predecessor: ACT-A, successor: ACT-B。
  • 资源互斥:同一资源同一时刻只能被一个动作占用,表达为资源容量 capacity: 1 加时间窗不重叠检查。
  • 工艺顺序:物料必须经过工位1→工位2→工位3,表达为物料工艺路线 route: [ST-01, ST-02, ST-03]。
  • 空间可达性:机器人只能作用于其工作空间内的工位,表达为资源—工位可达矩阵。

约束不直接修改对象状态,而是作为可行性判定函数参与编排决策。编排器在生成候选动作序列时,逐条检查约束是否满足,不满足则剪枝。

四、一个可运行的对象模型示例

下面给出一个装配工作站的简化对象模型片段,展示七类对象如何用统一格式描述。参数为教学示例,非实测数据:

{
  "task": {
    "id": "TASK-001", "type": "task",
    "goal": "完成工件A的螺栓装配",
    "material_ref": "MAT-A01",
    "deadline": 120.0,
    "constraints": ["CON-001", "CON-002"]
  },
  "action": {
    "id": "ACT-012", "type": "action",
    "name": "拧紧螺栓M6",
    "resource_ref": "RES-RB02",
    "station_ref": "ST-01",
    "duration": 8.5,
    "predecessor": "ACT-011",
    "constraints": ["CON-003"]
  },
  "resource": {
    "id": "RES-RB02", "type": "resource",
    "category": "robot",
    "capacity": 1,
    "reachable_stations": ["ST-01", "ST-02"],
    "state_ref": "STATE-RB02"
  },
  "material": {
    "id": "MAT-A01", "type": "material",
    "batch": "B2024-07",
    "location": "ST-01",
    "process_state": "待拧紧",
    "route": ["ST-01", "ST-02"]
  },
  "station": {
    "id": "ST-01", "type": "station",
    "name": "装配工位1",
    "resources": ["RES-RB02", "RES-FX01"],
    "capacity": 1
  },
  "device_state": {
    "id": "STATE-RB02", "type": "state",
    "resource_ref": "RES-RB02",
    "value": "idle",
    "timestamp": 45.2
  },
  "constraint": {
    "id": "CON-003", "type": "constraint",
    "kind": "resource_exclusive",
    "target": "RES-RB02",
    "expression": "no_overlap(time_window)"
  }
}

这个模型可以直接被编排器加载:任务声明目标,动作绑定资源与工位,物料携带工艺路线,设备状态提供实时可用性,约束提供可行性判定规则。编排器遍历动作图,检查约束,输出可执行序列。

五、建模时的常见陷阱

陷阱一:把状态写进资源对象本体。资源对象应只存静态属性(类别、容量、可达工位),动态状态单独用设备状态对象表达。否则每次状态变化都要改资源定义,版本管理会失控。

陷阱二:约束硬编码在动作里。约束应独立成对象,通过ID引用。这样同一条“资源互斥”约束可以复用于多个动作,修改时只改一处。

陷阱三:物料位置与工位状态不同步。物料位置字段和工位占用状态必须由同一事件驱动更新,否则会出现“物料显示在ST-01,但ST-01显示空闲”的矛盾。

实践建议:先用表格把七类对象的字段列全,再写JSON Schema校验。每次编排前跑一次模型一致性检查:所有引用ID是否存在、时间窗是否合法、约束表达式是否可解析。这一步能拦截大部分编排失败。

统一对象模型的价值在于:编排算法不需要为每类对象写特殊分支,只需要一套通用的“查询—检查约束—更新状态”接口。任务、动作、资源、物料、工位、设备状态和约束条件在同一语义空间中被描述和操作,后续的调度、冲突消解和异常恢复才能建立在可靠的数据基础之上。