-- ============================================================================ -- 新架构全配置化流程引擎 - 配方种子数据 -- 版本: v3.0 -- 说明: 两个工艺路线(缸体/配油盘)的完整 recipe 配置 -- 磨床交互采用一步换料工艺:磨床有成品+机器人持毛坯 → 直接换料(M2050/M2059),磨床不停机 -- 所有业务逻辑通过 recipe_step 子表配置驱动,引擎无硬编码 step_type -- -- 磨床换料核心设计(配置驱动,引擎零业务字符串): -- 1. OP15_DECIDE 决策:磨床 done → 换料(OP20_EXCHANGE);磨床 empty → 放料(OP20_LOAD) -- 2. OP20_EXCHANGE 一步换料:acquire_mode='any' 抢占前任工件 done 槽位(记录前任 job), -- PLC 一次完成 取成品+放毛坯;COMPLETE 阶段 handover 把 robot/temp_slot 锁转移给前任 job -- 并推进其去清洗(成品由前任 job 带走) -- 3. OP20_WAIT 磨床等待加工:hold_until_handover=true,完成后进入 holding 等下一件换料交接, -- fallback_next_step='OP20_FALLBACK_UNLOAD'(最后一件无后继时自行取料收尾) -- ============================================================================ -- 清理新引擎表数据 DELETE FROM recipe_step_decision; DELETE FROM recipe_step_action; DELETE FROM recipe_step_signal; DELETE FROM recipe_step_resource; DELETE FROM recipe_step; DELETE FROM recipe WHERE id IN (1, 2); -- ============================================================================ -- 一、工艺路线 -- ============================================================================ INSERT INTO recipe (id, name, code, version, is_active, "desc") VALUES (1, '缸体工艺', 'GRINDER-RND', 1, true, '缸体标准工艺流程:接驳台取料→磨床决策→磨床换料/放料→等待加工(挂起交接)→最后一件自行取料→清洗→决策→全检/缓存→接驳台下料'), (2, '配油盘工艺', 'GRINDER-SQR', 1, true, '配油盘标准工艺流程:接驳台取料→转换台换向→磨床决策→磨床换料/放料→等待加工(挂起交接)→最后一件自行取料→清洗→决策→全检/缓存→接驳台下料'); -- ============================================================================ -- 二、缸体工艺 (recipe_id=1) 步骤定义 -- 步骤索引顺序即流程顺序;OP20_WAIT(25) 之前的步骤 = 磨床前步骤(后继工件会来换料) -- ============================================================================ -- OP10_LOAD: 接驳台取料(机器人持毛坯,准备去磨床) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (1, 1, 'OP10_LOAD', '接驳台取料', 10, '', '', 'OP15_DECIDE', 2, -1, FALSE, '', '从接驳台取毛坯:机器人+缓存槽+DOCK occupied槽位'); -- OP15_DECIDE: 磨床状态决策(done→换料,empty→放料,加工中→等待) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (2, 1, 'OP15_DECIDE', '磨床状态决策', 15, '', '', 'OP20_LOAD', 2, -1, FALSE, '', '决策:磨床有加工完成的槽位→换料;磨床空→放料;加工中→等待'); -- OP20_EXCHANGE: 磨床一步换料(取成品+放毛坯,磨床不停机) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (3, 1, 'OP20_EXCHANGE', '磨床换料', 20, '', '', 'OP20_WAIT', 2, -1, FALSE, '', '一步换料:acquire_mode=any 抢占前任工件done槽位,M2050一次取成品+放毛坯,handover交接成品给前任job'); -- OP20_LOAD: 磨床放料(磨床空闲时直接放毛坯) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (4, 1, 'OP20_LOAD', '磨床放料', 22, '', '', 'OP20_WAIT', 2, -1, FALSE, '', '放料到磨床空槽位:机器人+GRINDER empty'); -- OP20_WAIT: 磨床等待加工(完成后进入 holding,等下一件换料交接;最后一件走 fallback 自行取料) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (5, 1, 'OP20_WAIT', '磨床等待加工', 25, '', '', 'OP30_LOAD', 2, -1, TRUE, 'OP20_FALLBACK_UNLOAD', '等待 M3600 加工完成,GRINDER→done,进入 holding 挂起等下一件换料交接(handover 推进去清洗);最后一件走 fallback 自行取料'); -- OP20_FALLBACK_UNLOAD: 最后一件自行取料(无后继工件换料时收尾) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (6, 1, 'OP20_FALLBACK_UNLOAD', '磨床取料收尾', 28, '', '', 'OP30_LOAD', 1, -1, FALSE, '', '最后一件:从磨床 done 槽位自行取料,成品落缓存槽释放 robot,清洗步骤重新 acquire 去清洗'); -- OP30_LOAD: 清洗(robot/temp_slot 由 handover 转移或 fallback 取得后重新 acquire) -- 注:清洗模型 = 持料模型——机器人夹持工件在气吹机构(AirBlow-01)工位吹洗(气吹机构无放料位置), -- M2139 完成时机器人仍持料不释放,carry 去 OP35 决策后的下一步(全检/缓存/换料), -- 由放料步骤(OP40_LOAD/OP50_LOAD/OP60_EXCHANGE_LOAD)完成时释放 robot; -- acquire AIR_BLOW empty 保证单工位互斥(其他工件不能同时清洗),清洗期间槽位被本 job 持有 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (7, 1, 'OP30_LOAD', '清洗', 40, '', '', 'OP35_DECIDE', 2, -1, FALSE, '', '机器人持料至气吹机构清洗:完成时只释放 temp_slot,robot 不释放(持料模型,生产科室定),carry 去 OP35 决策后的取料/放料步骤'); -- OP35_DECIDE: 全检台容量判断(done→换料优先;空位→放料;满→缓存;全满无done→等待) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (8, 1, 'OP35_DECIDE', '全检台容量判断', 45, '', '', 'OP40_LOAD', 2, -1, FALSE, '', '决策步骤:全检台有检测完成(done)→OP40_EXCHANGE换料;有空位→OP40全检;已满→OP50缓存'); -- OP50_LOAD: 缓存暂存(全检台满时) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (9, 1, 'OP50_LOAD', '缓存暂存', 50, '', '', 'OP50_UNLOAD', 4, -1, FALSE, '', '全检台满时暂存到缓存台,完成后取料回全检'); -- OP50_UNLOAD: 缓存取料回流 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (10, 1, 'OP50_UNLOAD', '缓存取料', 55, '', '', 'OP40_LOAD', 4, -1, FALSE, 'OP40_BATCH_DECIDE', '全检台有空位时从缓存台取料,随后放全检台;被代做跳过时(handover_proxy)直接推进到批次请求决策'); -- OP40_LOAD: 全检台放料(释放 robot/temp_slot;M2102 改由满槽或工单最后一件时在 OP40_BATCH_DECIDE/OP40_REQ 发送) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (11, 1, 'OP40_LOAD', '全检台放料', 60, '', '', 'OP40_BATCH_DECIDE', 3, -1, FALSE, '', '放料到全检台空槽位,不逐件发送 M2102(满槽或收尾时才请求检验)'); -- OP40_BATCH_DECIDE: 全检批次请求决策(满槽或工单最后一件 → 发 M2102 请求检验;否则 → 等待批次检测完成) -- 注:必须保留 occupied<2 → OP40_WAIT 分支——它承担中间件进入等待的关键职责: -- 满槽(=2)或收尾(remaining=0)由前两条分支处理;未满槽且未收尾时进入 OP40_WAIT -- 等 M2098 批次广播(由满槽件/最后一件发 M2102 触发),否则中间件决策等待永不被唤醒(死锁)。 -- 不能用恒真分支(occupied>=0):恒真分支触发恒真 warn 且掩盖后续分支不可达的配置错误。 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (31, 1, 'OP40_BATCH_DECIDE', '全检批次请求决策', 61, '', '', 'OP40_WAIT', 3, -1, FALSE, '', '决策:全检台2槽全满(都是待检)或工单最后一件 → OP40_REQ 发M2102;未满槽且未收尾 → OP40_WAIT 等批次检测完成'); -- OP40_EXCHANGE: 全检台一步换料(M2080:机器人从气吹机构取待检件,到全检台取 done 成品+放待检,一次动作) -- 触发:OP35_DECIDE 检测到全检台有 done 槽位(M2098 已到达)→ 换料,避免成品滞 留、减少机器人空跑 -- 交接:acquire_mode='any' 抢占前任 done 槽位记录 PrevJobID,COMPLETE 时 handover 收尾前任 job -- (成品由本 job 取走并 carry 去 OP60_EXCHANGE_LOAD 下料,锁不转移) -- 后续:next_step_default=OP60_EXCHANGE_LOAD——先放下前任成品并释放 robot/temp_slot, -- 再回 OP40_BATCH_DECIDE 参与批次请求决策(最后一件走换料时必须发 M2102 收尾批次, -- 否则全检台残留 done 工件永远无人取走,形成死锁) -- 注意:禁止直接 next=OP40_BATCH_DECIDE——换料 job 持前任成品+robot 锁进决策会锁死全线 -- (决策/等待期间 robot 无法释放,其他 job 全部饿死),必须先下料再决策 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (35, 1, 'OP40_EXCHANGE', '全检台换料', 63, '', '', 'OP60_EXCHANGE_LOAD', 3, -1, FALSE, '', '全检台一步换料:气吹机构取待检件→M2080取done成品+放待检(原位),handover收尾前任job,成品carry去接驳台下料;下料后回批次请求决策'); -- OP40_REQ: 发送 M2102 请求检验,等 M2098 批次检测完成 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (32, 1, 'OP40_REQ', '全检批次请求检验', 62, '', '', 'OP40_UNLOAD', 3, -1, FALSE, '', '满槽或工单最后一件时发送 M2102 请求检验,等 M2098 批次检测完成(广播)'); -- OP40_WAIT: 全检台等待检测 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (12, 1, 'OP40_WAIT', '全检台等待检测', 65, '', '', 'OP40_UNLOAD', 2, -1, FALSE, '', '等待 M2098 批次检测完成信号(广播)'); -- OP40_UNLOAD: 全检台取料 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (13, 1, 'OP40_UNLOAD', '全检台取料', 70, '', '', 'OP60_LOAD', 3, -1, FALSE, '', '从全检台 done 槽位取料:机器人+temp_slot+FULL_CHECK done'); -- OP60_EXCHANGE_LOAD: 换料成品接驳台下料(OP40_EXCHANGE 的专属下一步) -- 场景:换料完成后机器人夹爪上拿着前任 job 的成品(锁不转移,本 job 持有 robot/temp_slot), -- 必须先放回接驳台并释放 robot/temp_slot,再回 OP40_BATCH_DECIDE 参与批次决策—— -- 否则持料进决策/等待会锁死 robot 导致全线死锁(2026-08-13 线上 M2089 后全线卡死事故)。 -- 资源/信号/action 与 OP60_LOAD (14) 完全一致,仅 next_step_default 不同(回决策 vs 流程结束) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (37, 1, 'OP60_EXCHANGE_LOAD', '换料成品接驳台下料', 75, '', '', 'OP61_DECIDE', 4, -1, FALSE, '', '换料后把前任成品放回接驳台空槽位,释放 robot/temp_slot;完成后回 OP61_DECIDE 判断缓存台是否需代取二次换料'); -- OP61_DECIDE: 换料下料后缓存回流决策(换料 job 连续代做的入口) -- 场景:换料 job 把前任成品放接驳台后,缓存台若有待回流件(另一 job 暂存的), -- 顺路代取并去全检台 2 号位二次换料(放缓存件+换下第二个检测完成件), -- 一趟机器人完成两次换料两次下料,避免空跑。恒有出路:occupied>=1 → 代取;<1 → 直接回批次决策。 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (39, 1, 'OP61_DECIDE', '换料后缓存回流决策', 64, '', '', 'OP40_BATCH_DECIDE', 3, -1, FALSE, '', '决策:缓存台有待回流件→代取后全检台2号位二次换料;无→直接回批次请求决策'); -- OP50_EXCHANGE_TAKE: 缓存代取(换料 job 代做另一 job 的缓存回流取料) -- acquire_mode='proxy' 抢占缓存台 occupied 槽位并记录被代做 job(ProxyJobID), -- 供 OP40_EXCHANGE_2ND 的 handover_proxy 交接(槽位归属转移+推进被代做 job) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (40, 1, 'OP50_EXCHANGE_TAKE', '缓存代取', 66, '', '', 'OP40_EXCHANGE_2ND', 4, -1, FALSE, '', '代取缓存台待回流件:M2110取料,acquire_mode=proxy记录被代做job,robot持料carry去二次换料'); -- OP40_EXCHANGE_2ND: 全检台二次换料(缓存件放2号位 + 换下第二个检测完成件) -- 完成时 handover 收尾第二个成品 job + handover_proxy 交接被代做 job(槽位归属转移+跳过其缓存取料步骤) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (41, 1, 'OP40_EXCHANGE_2ND', '全检台二次换料', 67, '', '', 'OP60_LOAD_2ND', 3, -1, FALSE, '', '缓存件放全检台2号位(原位换下检测完成件):M2080换料,handover收尾成品job+handover_proxy归属转移给被代做job'); -- OP60_LOAD_2ND: 二次换料成品下料(放 job2 回接驳台,释放锁后回批次决策) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (42, 1, 'OP60_LOAD_2ND', '二次换料成品下料', 68, '', '', 'OP40_BATCH_DECIDE', 4, -1, FALSE, '', '把二次换料换下的成品放回接驳台空槽位,释放 robot/temp_slot;完成后回 OP40_BATCH_DECIDE 发待检信号'); -- OP60_LOAD: 接驳台下料(流程结束) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (14, 1, 'OP60_LOAD', '接驳台下料', 80, '', '', '', 4, -1, FALSE, '', '成品放回接驳台空槽位,next_step_default='''' 表示流程结束'); -- ============================================================================ -- 三、配油盘工艺 (recipe_id=2) 步骤定义 -- ============================================================================ -- OP10_LOAD: 接驳台取料 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (15, 2, 'OP10_LOAD', '接驳台取料', 10, '', '', 'OP25_TURN_LOAD', 2, -1, FALSE, '', '从接驳台取毛坯'); -- OP25_TURN_LOAD: 转换台放料+旋转(PLC自动旋转,M2079含旋转完成) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (16, 2, 'OP25_TURN_LOAD', '转换台放料+旋转', 20, '', '', 'OP25_TURN_UNLOAD', 2, -1, FALSE, '', '放料到转换台,PLC自动旋转,M2079到达后直接取料'); -- OP25_TURN_UNLOAD: 转换台取料 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (17, 2, 'OP25_TURN_UNLOAD', '转换台取料', 30, '', '', 'OP15_DECIDE', 2, -1, FALSE, '', '从转换台 occupied 槽位取料'); -- OP15_DECIDE: 磨床状态决策 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (18, 2, 'OP15_DECIDE', '磨床状态决策', 35, '', '', 'OP20_LOAD', 2, -1, FALSE, '', '决策:磨床 done→换料;磨床 empty→放料;加工中→等待'); -- OP20_EXCHANGE: 磨床一步换料 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (19, 2, 'OP20_EXCHANGE', '磨床换料', 40, '', '', 'OP20_WAIT', 2, -1, FALSE, '', '一步换料:acquire_mode=any 抢占前任工件done槽位,M2050取成品+放毛坯,handover交接'); -- OP20_LOAD: 磨床放料 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (20, 2, 'OP20_LOAD', '磨床放料', 45, '', '', 'OP20_WAIT', 2, -1, FALSE, '', '放料到磨床空槽位'); -- OP20_WAIT: 磨床等待加工(holding + fallback) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (21, 2, 'OP20_WAIT', '磨床等待加工', 50, '', '', 'OP30_LOAD', 2, -1, TRUE, 'OP20_FALLBACK_UNLOAD', '等待 M3600 加工完成,进入 holding 等交接;最后一件走 fallback 自行取料'); -- OP20_FALLBACK_UNLOAD: 最后一件自行取料 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (22, 2, 'OP20_FALLBACK_UNLOAD', '磨床取料收尾', 53, '', '', 'OP30_LOAD', 1, -1, FALSE, '', '最后一件:从磨床 done 槽位自行取料,成品落缓存槽释放 robot,清洗步骤重新 acquire 去清洗'); -- OP30_LOAD: 清洗(同缸体:持料模型,机器人夹持工件吹洗,acquire AIR_BLOW empty 单工位互斥) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (23, 2, 'OP30_LOAD', '清洗', 60, '', '', 'OP35_DECIDE', 2, -1, FALSE, '', '机器人持料至气吹机构清洗:完成时只释放 temp_slot,robot 不释放(持料模型,生产科室定),carry 去 OP35 决策后的取料/放料步骤'); -- OP35_DECIDE: 全检台容量判断(同缸体) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (24, 2, 'OP35_DECIDE', '全检台容量判断', 65, '', '', 'OP40_LOAD', 2, -1, FALSE, '', '决策步骤:全检台有检测完成(done)→OP40_EXCHANGE换料;有空位→OP40全检;已满→OP50缓存'); -- OP50_LOAD: 缓存暂存 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (25, 2, 'OP50_LOAD', '缓存暂存', 70, '', '', 'OP50_UNLOAD', 4, -1, FALSE, '', '全检台满时暂存到缓存台'); -- OP50_UNLOAD: 缓存取料回流 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (26, 2, 'OP50_UNLOAD', '缓存取料', 75, '', '', 'OP40_LOAD', 4, -1, FALSE, 'OP40_BATCH_DECIDE', '全检台有空位时从缓存台取料;被代做跳过时(handover_proxy)直接推进到批次请求决策'); -- OP40_LOAD: 全检台放料 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (27, 2, 'OP40_LOAD', '全检台放料', 80, '', '', 'OP40_BATCH_DECIDE', 3, -1, FALSE, '', '放料到全检台空槽位,不逐件发送 M2102(满槽或收尾时才请求检验)'); -- OP40_BATCH_DECIDE: 全检批次请求决策(满槽或工单最后一件 → 发 M2102 请求检验;否则 → 等待批次检测完成) -- 注:必须保留 occupied<2 → OP40_WAIT 分支——它承担中间件进入等待的关键职责: -- 满槽(=2)或收尾(remaining=0)由前两条分支处理;未满槽且未收尾时进入 OP40_WAIT -- 等 M2098 批次广播(由满槽件/最后一件发 M2102 触发),否则中间件决策等待永不被唤醒(死锁)。 -- 不能用恒真分支(occupied>=0):恒真分支触发恒真 warn 且掩盖后续分支不可达的配置错误。 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (33, 2, 'OP40_BATCH_DECIDE', '全检批次请求决策', 81, '', '', 'OP40_WAIT', 3, -1, FALSE, '', '决策:全检台2槽全满(都是待检)或工单最后一件 → OP40_REQ 发M2102;未满槽且未收尾 → OP40_WAIT 等批次检测完成'); -- OP40_EXCHANGE: 全检台一步换料(配油盘,同缸体;先下料再回批次请求决策,逻辑同缸体) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (36, 2, 'OP40_EXCHANGE', '全检台换料', 83, '', '', 'OP60_EXCHANGE_LOAD', 3, -1, FALSE, '', '全检台一步换料:气吹机构取待检件→M2080取done成品+放待检(原位),handover收尾前任job,成品carry去接驳台下料;下料后回批次请求决策'); -- OP40_REQ: 发送 M2102 请求检验,等 M2098 批次检测完成 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (34, 2, 'OP40_REQ', '全检批次请求检验', 82, '', '', 'OP40_UNLOAD', 3, -1, FALSE, '', '满槽或工单最后一件时发送 M2102 请求检验,等 M2098 批次检测完成(广播)'); -- OP40_WAIT: 全检台等待检测 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (28, 2, 'OP40_WAIT', '全检台等待检测', 85, '', '', 'OP40_UNLOAD', 2, -1, FALSE, '', '等待 M2098 批次检测完成信号(广播)'); -- OP40_UNLOAD: 全检台取料 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (29, 2, 'OP40_UNLOAD', '全检台取料', 90, '', '', 'OP60_LOAD', 3, -1, FALSE, '', '从全检台 done 槽位取料'); -- OP60_EXCHANGE_LOAD: 换料成品接驳台下料(配油盘,同缸体;回 OP40_BATCH_DECIDE 参与批次决策) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (38, 2, 'OP60_EXCHANGE_LOAD', '换料成品接驳台下料', 95, '', '', 'OP61_DECIDE', 4, -1, FALSE, '', '换料后把前任成品放回接驳台空槽位,释放 robot/temp_slot;完成后回 OP61_DECIDE 判断缓存台是否需代取二次换料'); -- OP61_DECIDE: 换料下料后缓存回流决策(配油盘,同缸体) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (43, 2, 'OP61_DECIDE', '换料后缓存回流决策', 84, '', '', 'OP40_BATCH_DECIDE', 3, -1, FALSE, '', '决策:缓存台有待回流件→代取后全检台2号位二次换料;无→直接回批次请求决策'); -- OP50_EXCHANGE_TAKE: 缓存代取(配油盘,同缸体) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (44, 2, 'OP50_EXCHANGE_TAKE', '缓存代取', 86, '', '', 'OP40_EXCHANGE_2ND', 4, -1, FALSE, '', '代取缓存台待回流件:M2110取料,acquire_mode=proxy记录被代做job,robot持料carry去二次换料'); -- OP40_EXCHANGE_2ND: 全检台二次换料(配油盘,同缸体) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (45, 2, 'OP40_EXCHANGE_2ND', '全检台二次换料', 87, '', '', 'OP60_LOAD_2ND', 3, -1, FALSE, '', '缓存件放全检台2号位(原位换下检测完成件):M2080换料,handover收尾成品job+handover_proxy归属转移给被代做job'); -- OP60_LOAD_2ND: 二次换料成品下料(配油盘,同缸体) INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (46, 2, 'OP60_LOAD_2ND', '二次换料成品下料', 88, '', '', 'OP40_BATCH_DECIDE', 4, -1, FALSE, '', '把二次换料换下的成品放回接驳台空槽位,释放 robot/temp_slot;完成后回 OP40_BATCH_DECIDE 发待检信号'); -- OP60_LOAD: 接驳台下料 INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES (30, 2, 'OP60_LOAD', '接驳台下料', 100, '', '', '', 4, -1, FALSE, '', '成品放回 接驳台'); -- ============================================================================ -- 四、缸体工艺 - 资源需求 (recipe_step_resource) -- acquire_mode: 'self'=仅本job自持(默认);'any'=可跨job抢占(换料取前任done槽位) -- ============================================================================ -- OP10_LOAD (1): 接驳台取料 - robot + temp_slot + DOCK occupied -- 注:去掉旧配方的 GRINDER empty check——换料设计下磨床 done 时也必须取料去换料, -- check 会阻断换料路径;且换料死锁由 handover 机制解决(不再需要该防死锁 check)。 INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (1, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (1, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (1, 'equipment_slot', 'acquire', 'DOCK', 'occupied', 1, 'self', '接驳台有工件可取的槽位'); -- OP15_DECIDE (2): 决策步骤 - 无固定资源需求(由 decision 表驱动) -- OP20_EXCHANGE (3): 磨床换料 - robot + temp_slot(自持) + GRINDER done(跨job抢占) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (3, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (3, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '工件在缓存槽(本job毛坯,自持)'), (3, 'equipment_slot', 'acquire', 'GRINDER', 'done', 1, 'any', '磨床加工完成的槽位(跨job抢占前任工件,记录前任job供handover交接)'); -- OP20_LOAD (4): 磨床放料 - robot + GRINDER empty INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (4, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (4, 'equipment_slot', 'acquire', 'GRINDER', 'empty', 1, 'self', '磨床空槽位'); -- OP20_WAIT (5): 磨床等待加工 - check GRINDER occupied(本job槽位) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (5, 'equipment_slot', 'check', 'GRINDER', 'occupied', 1, 'self', '确认工件在磨床上'); -- OP20_FALLBACK_UNLOAD (6): 最后一件取料 - robot + temp_slot + GRINDER done(自持) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (6, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (6, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (6, 'equipment_slot', 'acquire', 'GRINDER', 'done', 1, 'self', '本工件磨床加工完成的槽位'); -- OP30_LOAD (7): 清洗 - acquire robot + temp_slot occupied + AIR_BLOW empty -- 注:robot 在 acquire 列表内(清洗开始前重新 acquire)——handover 换料交接后成品落缓存槽、robot 已释放, -- 此处重新 acquire 取缓存槽成品去清洗;acquire 失败(AIR_BLOW 忙)时事务回滚即释放 robot, -- 避免"等气吹空位时持料"占用 robot 导致其他 job 无法取料(死锁);fallback 路径 robot 自持有幂等通过。 -- 清洗完成后为持料模型:robot 不释放,carry 去下一步(见 recipe_step_action)。 -- acquire AIR_BLOW empty 保证气吹机构单工位互斥;清洗期间槽位被本 job 持有(OCCUPIED+self), -- 后续取料步骤(OP40/OP50/OP40_EXCHANGE)再取走并释放 INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (7, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲(从缓存槽取成品去清洗)'), (7, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '工件在缓存槽/机器人 手上(robot 由上一环节持有,carry 延续)'), (7, 'equipment_slot', 'acquire', 'AIR_BLOW', 'empty', 1, 'self', '气吹机构空闲(单工位互斥,清洗期间槽位被本job持有)'); -- OP35_DECIDE (8): 决策步骤 - 无资源 -- OP50_LOAD (9): 缓存暂存 - robot + AIR_BLOW(自持) + CACHE empty(直连暂存,不经缓存槽,不占 temp_slot) -- 注:temp_slot 在 OP30_LOAD 已释放;robot 清洗完成后 carry 持料(自持有幂等直接通过);AIR_BLOW occupied 自持确认 -- 工件在气吹机构(仅 OP35_DECIDE 来源),放料后释放气吹机构槽位 INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (9, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (9, 'equipment_slot', 'acquire', 'AIR_BLOW', 'occupied', 1, 'self', '工件在气吹 机构(清洗完成待取,自持确认)'), (9, 'equipment_slot', 'acquire', 'CACHE', 'empty', 1, 'self', '缓存台空槽位'); -- OP50_UNLOAD (10): 缓存取料 - robot + temp_slot + FULL_CHECK(empty check) + CACHE(occupied 自持) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (10, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (10, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (10, 'equipment_slot', 'check', 'FULL_CHECK', 'empty', 1, 'self', '全检台有空位才取料'), (10, 'equipment_slot', 'acquire', 'CACHE', 'occupied', 1, 'self', '本工件在缓存台的槽位'); -- OP40_LOAD (11): 全检台放料 - robot + FULL_CHECK empty(直连放料,不经缓存槽,不占用 temp_slot) -- 注:清洗完成后机器人持料 carry(持料模型),放件全程机器人手上无缓存需求, -- 无需 acquire temp_slot;避免与"持料等待"的 job(成品在缓存槽)互抢单把 temp_slot 锁形成死锁。 -- temp_slot 在 OP30_LOAD 已释放;robot 清洗完成后 carry 持料,自持有幂等直接通过 INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (11, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (11, 'equipment_slot', 'acquire', 'FULL_CHECK', 'empty', 1, 'self', '全检台空槽 位'); -- OP40_WAIT (12): 全检台等待检测 - acquire FULL_CHECK occupied(自持待检槽位) -- 注:必须用 acquire 而非 check——换料路径(OP40_EXCHANGE→OP60_EXCHANGE_LOAD)后 job 最近一次 acquire -- 是 DOCK 下料槽位,check 步骤无分配记录,set_resource {allocated} 兜底会误把 DOCK 置 done; -- acquire 记录本 job 待检槽位分配,{allocated} 精确定位(acquire 幂等标记占用,不改变槽位归属) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (12, 'equipment_slot', 'acquire', 'FULL_CHECK', 'occupied', 1, 'self', '自持本 job 待检槽位(供 set_resource {allocated} 定位)'); -- OP40_REQ (32): 全检批次请求检验 - acquire FULL_CHECK occupied(自持待检槽位,理由同 OP40_WAIT) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (32, 'equipment_slot', 'acquire', 'FULL_CHECK', 'occupied', 1, 'self', '自持本 job 待检槽位(供 set_resource {allocated} 定位)'); -- OP40_EXCHANGE (35): 全检台换料 - robot + temp_slot + AIR_BLOW(自持) + FULL_CHECK done(跨job抢占) -- 注:工件在气吹机构(OP35_DECIDE 来源),acquire AIR_BLOW occupied 自持确认; -- 抢占 done 槽位记录 PrevJobID,COMPLETE 时 handover 收尾前任 job(成品由本 job 带走下料) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (35, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (35, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (35, 'equipment_slot', 'acquire', 'AIR_BLOW', 'occupied', 1, 'self', '工件在气吹机构(待检件,自持确认)'), (35, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'any', '全检台检测完成的槽位(跨job抢占前任工件,记录前任job供handover收尾)'); -- OP40_EXCHANGE (36): 全检台换料(配油盘,同缸体) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (36, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (36, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (36, 'equipment_slot', 'acquire', 'AIR_BLOW', 'occupied', 1, 'self', '工件在气吹机构(待检件,自持确认)'), (36, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'any', '全检台检测完成的槽位(跨job抢占前任工件,记录前任job供handover收尾)'); -- OP40_UNLOAD (13): 全检台取料 - robot + temp_slot + FULL_CHECK done INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (13, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (13, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (13, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'self', '全检台检测完成的槽位'); -- OP60_LOAD (14): 接驳台下料 - temp_slot occupied(自持) + DOCK empty -- 注:robot 不 acquire——OP40_UNLOAD 取料后机器人持料 carry 延续(同 OP30_LOAD/OP40_LOAD 模式), -- 此时 robot 锁为 busy(本job持有),acquire idle 会自锁;完成动作后由 action 释放 robot。 INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (14, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '成品在缓存槽'), (14, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位'); -- OP60_EXCHANGE_LOAD (37): 换料成品接驳台下料 - temp_slot occupied(自持) + DOCK empty(同 OP60_LOAD) -- 注:robot 不 acquire——OP40_EXCHANGE 换料后机器人持前任成品 carry 延续(锁不转移); -- 完成动作后由 action 释放 robot,解除全线 robot 死锁。 INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (37, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '前任成品在缓存槽(换料后锁转移至本job)'), (37, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位'); -- OP61_DECIDE (39): 决策步骤 - 无资源 -- OP50_EXCHANGE_TAKE (40): 缓存代取 - robot + temp_slot + CACHE occupied(跨job代取) -- acquire_mode='proxy':抢占缓存台 occupied 槽位(其他 job 的待回流件), -- 记录被代做 job(ProxyJobID)供 OP40_EXCHANGE_2ND 的 handover_proxy 交接 INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (40, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (40, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (40, 'equipment_slot', 'acquire', 'CACHE', 'occupied', 1, 'proxy', '缓存台待回流件(跨job代取,记录被代做job)'); -- OP40_EXCHANGE_2ND (41): 全检台二次换料 - robot(自持) + temp_slot occupied(自持) + FULL_CHECK done(跨job抢占) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (41, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲(代取后 carry 延续,自持幂等)'), (41, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '缓存件在机器人手上(自持)'), (41, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'any', '全检台检测完成的槽位(跨job抢占第二个成品job,记录前任供handover收尾)'); -- OP60_LOAD_2ND (42): 二次换料成品下料 - temp_slot occupied(自持) + DOCK empty(同 OP60_EXCHANGE_LOAD) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (42, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '二次换料成品在缓存槽(自持)'), (42, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位'); -- ============================================================================ -- 五、配油盘工艺 - 资源需求 -- ============================================================================ -- OP10_LOAD (15): 同缸体(无 GRINDER check) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (15, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (15, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (15, 'equipment_slot', 'acquire', 'DOCK', 'occupied', 1, 'self', '接驳台有工件'); -- OP25_TURN_LOAD (16): 转换台放料+旋转 - robot + TURN_TABLE empty INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (16, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (16, 'equipment_slot', 'acquire', 'TURN_TABLE', 'empty', 1, 'self', '转换台空槽位'); -- OP25_TURN_UNLOAD (17): 转换台取料 - robot + temp_slot(自持) + TURN_TABLE occupied INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (17, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (17, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '缓存槽有料(转台事务期间本job保留)'), (17, 'equipment_slot', 'acquire', 'TURN_TABLE', 'occupied', 1, 'self', '转换台有工件可取'); -- OP15_DECIDE (18): 决策步骤 - 无资源 -- OP20_EXCHANGE (19): 磨床换料 - temp_slot(自持) + GRINDER done(跨job抢占) -- 注:robot 不 acquire——OP25_TURN_UNLOAD 取料后机器人持毛坯 carry 延续(同缸体 OP30/OP40 模式), -- 此时 robot 锁为 busy(本job持有),acquire idle 会自锁;换料后由 handover 把锁转移给前任job。 INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (19, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '工件在缓存槽(本job毛坯,自持)'), (19, 'equipment_slot', 'acquire', 'GRINDER', 'done', 1, 'any', '磨床加工完成的槽位(跨job抢占,记录前任job)'); -- OP20_LOAD (20): 磨床放料 - GRINDER empty(robot 不 acquire,carry 延续,完成后由 action 释放 robot) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (20, 'equipment_slot', 'acquire', 'GRINDER', 'empty', 1, 'self', '磨床空槽位'); -- OP20_WAIT (21): 磨床等待加工 - check GRINDER occupied INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (21, 'equipment_slot', 'check', 'GRINDER', 'occupied', 1, 'self', '确认工件在磨床上'); -- OP20_FALLBACK_UNLOAD (22): 最后一件取料 INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (22, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (22, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (22, 'equipment_slot', 'acquire', 'GRINDER', 'done', 1, 'self', '本工件磨床加工完成的槽位'); -- OP30_LOAD (23): 清洗 - acquire robot + temp_slot occupied + AIR_BLOW empty(同缸体:清洗完成后持料模型,robot 不释放) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (23, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲(从缓存槽取成品去清洗)'), (23, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '工件在缓存槽/机器人手上'), (23, 'equipment_slot', 'acquire', 'AIR_BLOW', 'empty', 1, 'self', '气吹机构空闲 (单工位互斥,清洗期间槽位被本job持有)'); -- OP35_DECIDE (24): 决策步骤 - 无资源 -- OP50_LOAD (25): 缓存暂存 - robot + AIR_BLOW(自持) + CACHE empty(同缸体,直连暂存不占 temp_slot) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (25, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (25, 'equipment_slot', 'acquire', 'AIR_BLOW', 'occupied', 1, 'self', '工件在气吹机构(清洗完成待取,自持确认)'), (25, 'equipment_slot', 'acquire', 'CACHE', 'empty', 1, 'self', '缓存台空槽位'); -- OP50_UNLOAD (26): 缓存取料 INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (26, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (26, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (26, 'equipment_slot', 'check', 'FULL_CHECK', 'empty', 1, 'self', '全检台有空位才取料'), (26, 'equipment_slot', 'acquire', 'CACHE', 'occupied', 1, 'self', '本工件在缓存台的槽位'); -- OP40_LOAD (27): 全检台放料 - robot + FULL_CHECK empty(同缸体,直连放料不占 temp_slot) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (27, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (27, 'equipment_slot', 'acquire', 'FULL_CHECK', 'empty', 1, 'self', '全检台空槽 位'); -- OP40_WAIT (28): 全检台等待检测 - acquire FULL_CHECK occupied(自持待检槽位,理由同缸体 OP40_WAIT) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (28, 'equipment_slot', 'acquire', 'FULL_CHECK', 'occupied', 1, 'self', '自持本 job 待检槽位(供 set_resource {allocated} 定位)'); -- OP40_REQ (34): 全检批次请求检验 - acquire FULL_CHECK occupied(自持待检槽位,理由同缸体 OP40_REQ) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (34, 'equipment_slot', 'acquire', 'FULL_CHECK', 'occupied', 1, 'self', '自持本 job 待检槽位(供 set_resource {allocated} 定位)'); -- OP40_UNLOAD (29): 全检台取料 INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (29, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (29, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (29, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'self', '全检台检测完成'); -- OP60_LOAD (30): 接驳台下料 - temp_slot occupied(自持) + DOCK empty(robot 不 acquire,carry 延续,同缸体) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (30, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '成品在缓存槽'), (30, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位'); -- OP60_EXCHANGE_LOAD (38): 换料成品接驳台下料(配油盘,同缸体) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (38, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '前任成品在缓存槽(换料后锁转移至本job)'), (38, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位'); -- OP61_DECIDE (43): 决策步骤 - 无资源 -- OP50_EXCHANGE_TAKE (44): 缓存代取(配油盘,同缸体) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (44, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'), (44, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'), (44, 'equipment_slot', 'acquire', 'CACHE', 'occupied', 1, 'proxy', '缓存台待回流件(跨job代取,记录被代做job)'); -- OP40_EXCHANGE_2ND (45): 全检台二次换料(配油盘,同缸体) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (45, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲(代取后 carry 延续,自持幂等)'), (45, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '缓存件在机器人手上(自持)'), (45, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'any', '全检台检测完成的槽位(跨job抢占第二个成品job,记录前任供handover收尾)'); -- OP60_LOAD_2ND (46): 二次换料成品下料(配油盘,同缸体) INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES (46, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '二次换料成品在缓存槽(自持)'), (46, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位'); -- ============================================================================ -- 六、缸体工艺 - 信号序列 (recipe_step_signal) -- ============================================================================ -- OP10_LOAD (1): M2022参数 → M2001位置 → M2002号 → M2000取料请求 → 等M2009取料完成 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (1, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型 byte'), (1, 'DockFetchPos', 'param', '{dock_slot}', 2, 0, 'M2001 接驳台位置号'), (1, 'DockFetchTray', 'param', '{dock_no}', 3, 1000, 'M2002 接驳台号'), (1, 'DockFetchReq', 'req', '', 4, 0, 'M2000 取料请求'), (1, 'DockFetchDone', 'done', '', 0, 0, 'M2009 取料完成 byte'); -- OP15_DECIDE (2): 决策步骤,无信号 -- OP20_EXCHANGE (3): M2022参数 → M2050换料请求 → 等M2059换料完成(PLC一次取成品+放毛坯) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (3, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022 工件类型'), (3, 'GrinderExchangeReq', 'req', '', 2, 0, 'M2050 换料请求(取成品+放毛坯一步完成)'), (3, 'GrinderExchangeDone', 'done', '', 0, 0, 'M2059 换料完成 byte'); -- OP20_LOAD (4): M2022参数 → M2040放料请求 → 等M2049放料完成 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (4, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022 工件类型'), (4, 'GrinderPlaceReq', 'req', '', 2, 0, 'M2040 放料请求'), (4, 'GrinderPlaceDone', 'done', '', 0, 0, 'M2049 放料完成 byte'); -- OP20_WAIT (5): 只等 M3600.0,不发任何请求 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (5, 'GrinderMachiningDone', 'done', '', 0, 0, 'M3600.0 加工完成 bool'); -- OP20_FALLBACK_UNLOAD (6): M2022参数 → M2030取料请求 → 等M2039取料完成 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (6, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022 工件类型'), (6, 'GrinderFetchReq', 'req', '', 2, 0, 'M2030 取料请求'), (6, 'GrinderFetchDone', 'done', '', 0, 0, 'M2039 取料完成 byte'); -- OP30_LOAD (7): M2022参数 → M2130清洗请求 → 等M2139清洗完成 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (7, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022 工件类型'), (7, 'WashStartReq', 'req', '', 2, 0, 'M2130 清洗请求'), (7, 'AirBlowCompleteDone', 'done', '', 0, 0, 'M2139 清洗完成 byte'); -- OP35_DECIDE (8): 决策步骤,无信号 -- OP50_LOAD (9): M2022→M2121位置→M2120放料→等M2129放料完成 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (9, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (9, 'CachePlacePos', 'param', '{allocated_slot}', 2, 1000, 'M2121 缓存台位置号'), (9, 'CachePlaceReq', 'req', '', 3, 0, 'M2120 放料请求'), (9, 'CachePlaceDone', 'done', '', 0, 0, 'M2129 放料完成 byte'); -- OP50_UNLOAD (10): M2022→M2111位置→M2110取料→等M2119取料完成 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (10, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (10, 'CacheFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2111 缓存台取料位置号'), (10, 'CacheFetchReq', 'req', '', 3, 0, 'M2110 取料请求'), (10, 'CacheFetchDone', 'done', '', 0, 0, 'M2119 取料完成 byte'); -- OP40_LOAD (11): M2022参数 → M2101位置 → M2100放料请求 → 等M2109放料完成 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (11, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'), (11, 'FullCheckPlacePos', 'param', '{allocated_slot}', 2, 1000, 'M2101 全检台放位置号'), (11, 'FullCheckPlaceReq', 'req', '', 3, 0, 'M2100 放料请求'), (11, 'FullCheckPlaceDone', 'done', '', 0, 0, 'M2109 放料完成 byte'); -- OP40_WAIT (12): 只等 M2098 检测完成(广播:一批多件同时完成) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, broadcast, description) VALUES (12, 'FullCheckInspectDone', 'done', '', 0, 0, TRUE, 'M2098 检测完成 byte(广播:一批多件同时完成)'); -- OP40_REQ (32): 满槽或工单最后一件时发送 M2102 请求检验,等 M2098 批次检测完成(广播) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, broadcast, description) VALUES (32, 'CameraWorkType', 'param', '{product_type}', 1, 1000, FALSE, 'M2022 工件类型'), (32, 'FullCheckPlaceDoneRequestInspect', 'req', '', 2, 0, FALSE, 'M2102 软件_待检放料完成请求检验(满槽或工单最后一件时发送)'), (32, 'FullCheckInspectDone', 'done', '', 0, 0, TRUE, 'M2098 批次检测完成(广播)'); -- OP40_EXCHANGE (35): M2022参数 → M2081取位置(原位) → M2082放位置(原位) → M2080换料请求 → 等M2089换料完成 -- 注:M2081/M2082 均写 {allocated_slot}(抢占的 done 槽位)→ 原位换料:取 done 成品后放待检到同一槽位 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (35, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'), (35, 'FullCheckExchangeFetchPos', 'param', '{allocated_slot}', 2, 0, 'M2081 全检台取位置号(done 槽位)'), (35, 'FullCheckExchangePlacePos', 'param', '{allocated_slot}', 3, 1000, 'M2082 全检台放位置号(原位)'), (35, 'FullCheckExchangeReq', 'req', '', 4, 0, 'M2080 换料请求'), (35, 'FullCheckExchangeDone', 'done', '', 0, 0, 'M2089 换料完成 byte'); -- OP40_EXCHANGE (36): 全检台换料(配油盘,同缸体) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (36, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'), (36, 'FullCheckExchangeFetchPos', 'param', '{allocated_slot}', 2, 0, 'M2081 全检台取位置号(done 槽位)'), (36, 'FullCheckExchangePlacePos', 'param', '{allocated_slot}', 3, 1000, 'M2082 全检台放位置号(原位)'), (36, 'FullCheckExchangeReq', 'req', '', 4, 0, 'M2080 换料请求'), (36, 'FullCheckExchangeDone', 'done', '', 0, 0, 'M2089 换料完成 byte'); -- OP40_UNLOAD (13): M2022参数 → M2090取料请求+M2091位置 → 等M2099取料完成 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (13, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'), (13, 'FullCheckFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2091 全检台取料位置号'), (13, 'FullCheckFetchReq', 'req', '', 3, 0, 'M2090 取料请求'), (13, 'FullCheckFetchDone', 'done', '', 0, 0, 'M2099 取料完成 byte'); -- OP60_LOAD (14): M2022参数 → M2011位置 → M2012号 → M2010放料请求 → 等M2019放料完成 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (14, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'), (14, 'DockPlacePos', 'param', '{dock_slot}', 2, 0, 'M2011 接驳台位置号'), (14, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012 接驳台号'), (14, 'DockPlaceReq', 'req', '', 4, 0, 'M2010 放料请求'), (14, 'DockPlaceDone', 'done', '', 0, 0, 'M2019 放料完成 byte'); -- OP60_EXCHANGE_LOAD (37): 换料成品接驳台下料,信号序列同 OP60_LOAD(M2022→M2011→M2012→M2010→等M2019) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (37, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'), (37, 'DockPlacePos', 'param', '{allocated_slot}', 2, 0, 'M2011 接驳台位置号(实际分配槽位,与 acquire 一致)'), (37, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012 接驳台号'), (37, 'DockPlaceReq', 'req', '', 4, 0, 'M2010 放料请求'), (37, 'DockPlaceDone', 'done', '', 0, 0, 'M2019 放料完成 byte'); -- OP61_DECIDE (39): 决策步骤,无信号 -- OP50_EXCHANGE_TAKE (40): 缓存代取 - M2022→M2111位置→M2110取料→等M2119(同 OP50_UNLOAD) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (40, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (40, 'CacheFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2111 缓存台取料位置号'), (40, 'CacheFetchReq', 'req', '', 3, 0, 'M2110 取料请求'), (40, 'CacheFetchDone', 'done', '', 0, 0, 'M2119 取料完成 byte'); -- OP40_EXCHANGE_2ND (41): M2022→M2081取位置→M2082放位置→M2080换料→等M2089(同 OP40_EXCHANGE,原位换料) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (41, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'), (41, 'FullCheckExchangeFetchPos', 'param', '{allocated_slot}', 2, 0, 'M2081 全检台取位置号(done 槽位)'), (41, 'FullCheckExchangePlacePos', 'param', '{allocated_slot}', 3, 1000, 'M2082 全检台放位置号(原位)'), (41, 'FullCheckExchangeReq', 'req', '', 4, 0, 'M2080 换料请求'), (41, 'FullCheckExchangeDone', 'done', '', 0, 0, 'M2089 换料完成 byte'); -- OP60_LOAD_2ND (42): 信号序列同 OP60_EXCHANGE_LOAD(M2022→M2011→M2012→M2010→等M2019) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (42, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'), (42, 'DockPlacePos', 'param', '{allocated_slot}', 2, 0, 'M2011 接驳台位置号(实际分配槽位,与 acquire 一致)'), (42, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012 接驳台号'), (42, 'DockPlaceReq', 'req', '', 4, 0, 'M2010 放料请求'), (42, 'DockPlaceDone', 'done', '', 0, 0, 'M2019 放料完成 byte'); -- ============================================================================ -- 七、配油盘工艺 - 信号序列 -- ============================================================================ -- OP10_LOAD (15): 同缸体 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (15, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (15, 'DockFetchPos', 'param', '{dock_slot}', 2, 0, 'M2001'), (15, 'DockFetchTray', 'param', '{dock_no}', 3, 1000, 'M2002'), (15, 'DockFetchReq', 'req', '', 4, 0, 'M2000'), (15, 'DockFetchDone', 'done', '', 0, 0, 'M2009'); -- OP25_TURN_LOAD (16): 转换台放料+旋转 - M2022→M2070→等M2079(含旋转完成) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (16, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'), (16, 'TurnTablePlaceReq', 'req', '', 2, 0, 'M2070 放料请求,PLC自动旋转'), (16, 'TurnTablePlaceDone', 'done', '', 0, 0, 'M2079 放料+旋转完成 byte'); -- OP25_TURN_UNLOAD (17): 转换台取料 - M2022→M2060→等M2069 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (17, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'), (17, 'TurnTableFetchReq', 'req', '', 2, 0, 'M2060 取料请求'), (17, 'TurnTableFetchDone', 'done', '', 0, 0, 'M2069 取料完成 byte'); -- OP15_DECIDE (18): 决策步骤,无信号 -- OP20_EXCHANGE (19): M2022→M2050换料→等M2059 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (19, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'), (19, 'GrinderExchangeReq', 'req', '', 2, 0, 'M2050 换料请求(取成品+放毛坯一步完成)'), (19, 'GrinderExchangeDone', 'done', '', 0, 0, 'M2059 换料完成 byte'); -- OP20_LOAD (20): 磨床放料 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (20, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'), (20, 'GrinderPlaceReq', 'req', '', 2, 0, 'M2040'), (20, 'GrinderPlaceDone', 'done', '', 0, 0, 'M2049'); -- OP20_WAIT (21): 等 M3600 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (21, 'GrinderMachiningDone', 'done', '', 0, 0, 'M3600.0'); -- OP20_FALLBACK_UNLOAD (22): 磨床取料收尾 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (22, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'), (22, 'GrinderFetchReq', 'req', '', 2, 0, 'M2030'), (22, 'GrinderFetchDone', 'done', '', 0, 0, 'M2039'); -- OP30_LOAD (23): 清洗 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (23, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'), (23, 'WashStartReq', 'req', '', 2, 0, 'M2130'), (23, 'AirBlowCompleteDone', 'done', '', 0, 0, 'M2139'); -- OP35_DECIDE (24): 决策步骤,无信号 -- OP50_LOAD (25): 缓存暂存 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (25, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (25, 'CachePlacePos', 'param', '{allocated_slot}', 2, 1000, 'M2121'), (25, 'CachePlaceReq', 'req', '', 3, 0, 'M2120'), (25, 'CachePlaceDone', 'done', '', 0, 0, 'M2129'); -- OP50_UNLOAD (26): 缓存取料 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (26, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (26, 'CacheFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2111'), (26, 'CacheFetchReq', 'req', '', 3, 0, 'M2110'), (26, 'CacheFetchDone', 'done', '', 0, 0, 'M2119'); -- OP40_LOAD (27): 全检台放料 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (27, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (27, 'FullCheckPlacePos', 'param', '{allocated_slot}', 2, 1000, 'M2101'), (27, 'FullCheckPlaceReq', 'req', '', 3, 0, 'M2100'), (27, 'FullCheckPlaceDone', 'done', '', 0, 0, 'M2109'); -- OP40_WAIT (28): 等 M2098(广播:一批多件同时完成) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, broadcast, description) VALUES (28, 'FullCheckInspectDone', 'done', '', 0, 0, TRUE, 'M2098(广播:一批多件同时完成)'); -- OP40_REQ (34): 满槽或工单最后一件时发送 M2102 请求检验,等 M2098 批次检测完成(广播) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, broadcast, description) VALUES (34, 'CameraWorkType', 'param', '{product_type}', 1, 1000, FALSE, 'M2022'), (34, 'FullCheckPlaceDoneRequestInspect', 'req', '', 2, 0, FALSE, 'M2102 软件_待检放料完成请求检验(满槽或工单最后一件时发送)'), (34, 'FullCheckInspectDone', 'done', '', 0, 0, TRUE, 'M2098 批次检测完成(广播)'); -- OP40_UNLOAD (29): 全检台取料 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (29, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (29, 'FullCheckFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2091'), (29, 'FullCheckFetchReq', 'req', '', 3, 0, 'M2090'), (29, 'FullCheckFetchDone', 'done', '', 0, 0, 'M2099'); -- OP60_LOAD (30): 接驳台下料 INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (30, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (30, 'DockPlacePos', 'param', '{dock_slot}', 2, 0, 'M2011'), (30, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012'), (30, 'DockPlaceReq', 'req', '', 4, 0, 'M2010'), (30, 'DockPlaceDone', 'done', '', 0, 0, 'M2019'); -- OP60_EXCHANGE_LOAD (38): 换料成品接驳台下料(配油盘,信号序列同 OP60_LOAD) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (38, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (38, 'DockPlacePos', 'param', '{allocated_slot}', 2, 0, 'M2011'), (38, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012'), (38, 'DockPlaceReq', 'req', '', 4, 0, 'M2010'), (38, 'DockPlaceDone', 'done', '', 0, 0, 'M2019'); -- OP61_DECIDE (43): 决策步骤,无信号 -- OP50_EXCHANGE_TAKE (44): 缓存代取(配油盘,同缸体) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (44, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (44, 'CacheFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2111 缓存台取料位置号'), (44, 'CacheFetchReq', 'req', '', 3, 0, 'M2110 取料请求'), (44, 'CacheFetchDone', 'done', '', 0, 0, 'M2119 取料完成 byte'); -- OP40_EXCHANGE_2ND (45): 全检台二次换料(配油盘,同缸体) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (45, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'), (45, 'FullCheckExchangeFetchPos', 'param', '{allocated_slot}', 2, 0, 'M2081 全检台取位置号(done 槽位)'), (45, 'FullCheckExchangePlacePos', 'param', '{allocated_slot}', 3, 1000, 'M2082 全检台放位置号(原位)'), (45, 'FullCheckExchangeReq', 'req', '', 4, 0, 'M2080 换料请求'), (45, 'FullCheckExchangeDone', 'done', '', 0, 0, 'M2089 换料完成 byte'); -- OP60_LOAD_2ND (46): 信号序列同 OP60_EXCHANGE_LOAD(配油盘) INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES (46, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'), (46, 'DockPlacePos', 'param', '{allocated_slot}', 2, 0, 'M2011'), (46, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012'), (46, 'DockPlaceReq', 'req', '', 4, 0, 'M2010'), (46, 'DockPlaceDone', 'done', '', 0, 0, 'M2019'); -- ============================================================================ -- 八、缸体工艺 - 后置操作 (recipe_step_action) -- ============================================================================ -- OP10_LOAD (1): 取料完成 → 释放 robot + temp_slot→occupied + DOCK→empty INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (1, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'), (1, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 2, '缓存槽→occupied(工件在缓存槽)'), (1, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 3, 'DOCK槽位→empty(取走工件)'); -- OP15_DECIDE (2): 决策步骤 - 由 recipe_step_decision 驱动跳转,action 留空 -- OP20_EXCHANGE (3): 换料完成 → GRINDER→occupied(本job毛坯上磨床) + handover(锁转移+推进前任去清洗)+ 释放 robot -- 注:GRINDER done 槽位已被 acquire 置 OCCUPIED/current_job_id=本job,set_resource 幂等确认; -- handover 只把 temp_slot 锁转移给前任 job(成品落缓存槽),robot 随即释放归位—— -- 前任 job 的清洗步骤(OP30_LOAD)自行 acquire robot,避免"持料空等"占用 robot 导致其他 job 无法取料(死锁)。 INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (3, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'GRINDER→occupied(本job毛坯已上磨床加工)'), (3, 'handover', '', '', '', 2, '换料交接:temp_slot 锁转移给前任job(成品落缓存槽),推进其去清洗'), (3, 'release_resource', 'robot', 'robot', '', 3, '释放机器人(成品已在缓存槽,机器人归位)'); -- OP20_LOAD (4): 放料完成 → 释放 robot + temp_slot + GRINDER→occupied INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (4, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'), (4, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽(工件在磨床上)'), (4, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'GRINDER→occupied(工件在磨床加工中)'); -- OP20_WAIT (5): M3600 到达 → GRINDER→done(进入 holding 等交接/收尾) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (5, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'GRINDER→done(加工完成,等待换料交接)'); -- OP20_FALLBACK_UNLOAD (6): 取料完成 → temp_slot→occupied + GRINDER→empty + 释放 robot(成品落缓存槽,机器人归位) -- 注:成品放下后 robot 释放,清洗步骤(OP30_LOAD)自行 acquire robot; -- 避免最后一件持料空等 AIR_BLOW 时占用 robot,导致其他 job 无法取料(死锁)。 INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (6, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(成品在缓存槽/机器人手上)'), (6, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'GRINDER→empty (成品已取出,磨床空)'), (6, 'release_resource', 'robot', 'robot', '', 3, '释放机器人(成品已在缓存槽,机器人归位)'); -- OP30_LOAD (7): 清洗完成 → 只释放 temp_slot(持料模型:气吹时机器人持料不放,无放料位置; -- robot 由放料步骤 OP40_LOAD/OP50_LOAD/OP60_EXCHANGE_LOAD 完成时释放,carry 模式自持有幂等) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (7, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽(清洗后释放,后续步骤重新 acquire)'); -- OP50_LOAD (9): 缓存暂存完成 → 释放 robot + CACHE→occupied + 气吹机构→empty(工件已取走) -- 注:release temp_slot 为尽力清理(本步骤不 acquire,回流/直连双路径持有状态不同), -- 锁空闲或他人持有时引擎均跳过不报错,由真正持有者释放 INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (9, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'), (9, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽(工件在缓存台)'), (9, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'CACHE→occupied(工件暂存在缓存台)'), (9, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 4, '气吹机构→empty(工件已从气吹机构取走)'); -- OP50_UNLOAD (10): 缓存取料完成 → temp_slot→occupied + CACHE→empty(robot 持料去全检) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (10, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(工件在机器人手上)'), (10, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'CACHE→empty(工件已取走)'); -- OP40_LOAD (11): 全检放料完成 → 释放 robot + FULL_CHECK→occupied + 气吹机构→empty -- 注:不再逐件发送 M2102——请求检验改由 OP40_BATCH_DECIDE 决策(满槽或工单收尾)后由 OP40_REQ 发送; -- 回流路径(OP50_UNLOAD 来源)工件在机器人手上,气吹机构本就 empty,set empty 幂等无害; -- release temp_slot 为尽力清理(直连路径不持有,回流路径 carry 持有,引擎对非持有跳过不报错) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (11, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'), (11, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽(工件在全检台)'), (11, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'FULL_CHECK→occupied(工件待检测)'), (11, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 4, '气吹机构→empty(工件已从气吹机构取走)'); -- OP40_WAIT (12): M2098 到达 → FULL_CHECK→done INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (12, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'FULL_CHECK→done(检测完成,等待取料)'); -- OP40_REQ (32): M2098 批次检测完成到达 → FULL_CHECK→done(本工件检测完成,等待取料) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (32, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'FULL_CHECK→done(本工件检测完成,等待取料)'); -- OP40_EXCHANGE (35): 换料完成 → FULL_CHECK→occupied(待检件已放) + 气吹机构→empty + handover(收尾前任 job) -- 注:不释放 robot/temp_slot——成品在机器人手上 carry 去 OP60_LOAD 下料; -- handover 分支 3 收尾前任 job(跳过取料,成品由本 job 负责下料) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (35, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'FULL_CHECK→occupied(本job待检件已放,原位)'), (35, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 2, '气吹机构→empty(待检件已取走)'), (35, 'handover', '', '', '', 3, '换料交接:前任job跳过取料直接收尾(成品由本job带去下料,锁不转移)'); -- OP40_EXCHANGE (36): 全检台换料(配油盘,同缸体) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (36, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'FULL_CHECK→occupied(本job待检件已放,原位)'), (36, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 2, '气吹机构→empty(待检件已取走)'), (36, 'handover', '', '', '', 3, '换料交接:前任job跳过取料直接收尾(成品由本job带去下料,锁不转移)'); -- OP40_UNLOAD (13): 全检取料完成 → temp_slot→occupied + FULL_CHECK→empty(robot 持料去下料) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (13, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(成品在机器人手上)'), (13, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'FULL_CHECK→empty(工件已取走)'); -- OP60_LOAD (14): 下料完成 → 释放 robot + temp_slot + DOCK→occupied(流程结束) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (14, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'), (14, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'), (14, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(成品已放回接驳台,流程结束)'); -- OP60_EXCHANGE_LOAD (37): 换料下料完成 → 释放 robot + temp_slot + DOCK→occupied(回 OP40_BATCH_DECIDE 参与批次决策) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (37, 'release_resource', 'robot', 'robot', '', 1, '释放机器人(解除全线 robot 死锁)'), (37, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'), (37, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(前任成品已放回接驳台)'); -- OP61_DECIDE (39): 决策步骤 - action 留空 -- OP50_EXCHANGE_TAKE (40): 缓存代取完成 → temp_slot→occupied + CACHE→empty(robot 持料去二次换料) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (40, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(缓存件在机器人手上)'), (40, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'CACHE→empty(缓存件已代取走)'); -- OP40_EXCHANGE_2ND (41): 二次换料完成 → FULL_CHECK→occupied + handover(收尾第二个成品job)+ handover_proxy(归属转移给被代做job) -- 注:不释放 robot/temp_slot——成品在机器人手上 carry 去 OP60_LOAD_2ND 下料; -- handover 分支 3 收尾成品 job(跳过取料,成品由本 job 负责下料); -- handover_proxy 把 2 号位槽位归属改为被代做 job 并推进其跳过缓存取料步骤 INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (41, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'FULL_CHECK→occupied(缓存件已放2号位,原位)'), (41, 'handover', '', '', '', 2, '换料交接:第二个成品job跳过取料直接收尾(成品由本job带去下料,锁不转移)'), (41, 'handover_proxy', '', '', '', 3, '代做交接:槽位归属转移给被代做job并推进其跳过缓存取料步骤'); -- OP60_LOAD_2ND (42): 二次换料下料完成 → 释放 robot + temp_slot + DOCK→occupied(回 OP40_BATCH_DECIDE 发待检信号) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (42, 'release_resource', 'robot', 'robot', '', 1, '释放机器人(解除全线 robot 死锁)'), (42, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'), (42, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(二次换料成品已放回接驳台)'); -- ============================================================================ -- 九、配油盘工艺 - 后置操作 (recipe_step_action) -- ============================================================================ -- OP10_LOAD (15): 同缸体 INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (15, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'), (15, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 2, '缓存槽→occupied'), (15, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 3, 'DOCK槽位→empty'); -- OP25_TURN_LOAD (16): 放料+旋转完成 → 释放 robot + TURN_TABLE→occupied -- 注:temp_slot 不释放——转台单槽位,旋转期间本工件必须保留缓存槽(机器人手位)占有, -- 防止其他工件抢占 temp_slot 后等待转台空位,与转台持有者形成循环等待死锁(与缸体从上料到磨床一直持有 temp_slot 同理)。 INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (16, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'), (16, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 2, 'TURN_TABLE→occupied(工件已旋转)'); -- OP25_TURN_UNLOAD (17): 转换台取料完成 → temp_slot→occupied + TURN_TABLE→empty(robot 持料去磨床) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (17, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(工件在机器人手上)'), (17, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'TURN_TABLE→empty(工件已取走)'); -- OP20_EXCHANGE (19): 换料完成 → GRINDER→occupied + handover(temp_slot 转移)+ 释放 robot(同缸体) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (19, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'GRINDER→occupied(本job毛坯已上磨床加工)'), (19, 'handover', '', '', '', 2, '换料交接:temp_slot 锁转移给前任job(成品落缓存槽),推进其去清洗'), (19, 'release_resource', 'robot', 'robot', '', 3, '释放机器人(成品已在缓存槽,机器人归位)'); -- OP20_LOAD (20): 放料完成 → 释放 robot + temp_slot + GRINDER→occupied INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (20, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'), (20, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'), (20, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'GRINDER→occupied'); -- OP20_WAIT (21): M3600 到达 → GRINDER→done(进入 holding) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (21, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'GRINDER→done(加工完成,等待换料交接)'); -- OP20_FALLBACK_UNLOAD (22): 取料完成 → temp_slot→occupied + GRINDER→empty + 释放 robot(同缸体) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (22, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied'), (22, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'GRINDER→empty'), (22, 'release_resource', 'robot', 'robot', '', 3, '释放机器人(成品已在缓存槽,机器人归位)'); -- OP30_LOAD (23): 清洗完成 → 只释放 temp_slot(气吹时机器人持料不放,无放料位置; -- robot 由放料步骤 OP40_LOAD/OP50_LOAD/OP60_EXCHANGE_LOAD 完成时释放,carry 模式自持有幂等) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (23, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽(清洗后释放,后续步骤重新 acquire)'); -- OP50_LOAD (25): 缓存暂存完成 → 释放 robot + CACHE→occupied + 气吹机构→empty(同缸体;release temp_slot 为尽力清理) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (25, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'), (25, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'), (25, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'CACHE→occupied'), (25, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 4, '气吹机构→empty(工件已取走)'); -- OP50_UNLOAD (26): 缓存取料完成 → temp_slot→occupied + CACHE→empty INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (26, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied'), (26, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'CACHE→empty'); -- OP40_LOAD (27): 全检放料完成 → 释放 robot + FULL_CHECK→occupied + 气吹机构→empty(同缸体;release temp_slot 为尽力清理) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (27, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'), (27, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'), (27, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'FULL_CHECK→occupied'), (27, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 4, '气吹机构→empty(工件已从气吹机构取走)'); -- OP40_WAIT (28): M2098 到达 → FULL_CHECK→done INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (28, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'FULL_CHECK→done'); -- OP40_REQ (34): M2098 批次检测完成到达 → FULL_CHECK→done(本工件检测完成,等待取料) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (34, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'FULL_CHECK→done(本工件检测完成,等待取料)'); -- OP40_UNLOAD (29): 全检取料完成 → temp_slot→occupied + FULL_CHECK→empty INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (29, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied'), (29, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'FULL_CHECK→empty'); -- OP60_LOAD (30): 下料完成 → 释放 robot + temp_slot + DOCK→occupied(流程结束) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (30, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'), (30, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'), (30, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(流程结束)'); -- OP60_EXCHANGE_LOAD (38): 换料下料完成 → 释放 robot + temp_slot + DOCK→occupied(配油盘,回 OP40_BATCH_DECIDE) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (38, 'release_resource', 'robot', 'robot', '', 1, '释放机器人(解除全线 robot 死锁)'), (38, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'), (38, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(前任成品已放回接驳台)'); -- OP61_DECIDE (43): 决策步骤 - action 留空 -- OP50_EXCHANGE_TAKE (44): 缓存代取完成 → temp_slot→occupied + CACHE→empty(配油盘,同缸体) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (44, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(缓存件在机器人手上)'), (44, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'CACHE→empty(缓存件已代取走)'); -- OP40_EXCHANGE_2ND (45): 二次换料完成 → FULL_CHECK→occupied + handover + handover_proxy(配油盘,同缸体) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (45, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'FULL_CHECK→occupied(缓存件已放2号位,原位)'), (45, 'handover', '', '', '', 2, '换料交接:第二个成品job跳过取料直接收尾(成品由本job带去下料,锁不转移)'), (45, 'handover_proxy', '', '', '', 3, '代做交接:槽位归属转移给被代做job并推进其跳过缓存取料步骤'); -- OP60_LOAD_2ND (46): 二次换料下料完成 → 释放 robot + temp_slot + DOCK→occupied(配油盘,同缸体) INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES (46, 'release_resource', 'robot', 'robot', '', 1, '释放机器人(解除全线 robot 死锁)'), (46, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'), (46, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(二次换料成品已放回接驳台)'); -- ============================================================================ -- 十、决策分支 (recipe_step_decision) -- ============================================================================ -- 缸体 OP15_DECIDE (2): 磨床有 done 槽位→换料;否则磨床空→放料;加工中→等待(不匹配任何分支时原地等待) INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES (2, 1, 'GRINDER', 'done', '>=', 1, 'OP20_EXCHANGE', '磨床有磨好的成品→一步换料(跨job交接)'), (2, 2, 'GRINDER', 'empty', '>=', 1, 'OP20_LOAD', '磨床空→直接放料'); -- 缸体 OP35_DECIDE (8): done→换料优先(避免成品滞留);空位→全检放料;全检台满→缓存暂存;全都不满足→等待 INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES (8, 1, 'FULL_CHECK', 'done', '>=', 1, 'OP40_EXCHANGE', '全检台有检测完成→一步换料(跨job交接:取done成品+放待检原位,避免成品滞留)'), (8, 2, 'FULL_CHECK', 'empty', '>=', 1, 'OP40_LOAD', '全检台有空位→全检放料'), (8, 3, 'CACHE', 'empty', '>=', 1, 'OP50_LOAD', '全检台满→缓存暂存'); -- 配油盘 OP15_DECIDE (18) INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES (18, 1, 'GRINDER', 'done', '>=', 1, 'OP20_EXCHANGE', '磨床有磨好的成品→一步换料'), (18, 2, 'GRINDER', 'empty', '>=', 1, 'OP20_LOAD', '磨床空→直接放料'); -- 配油盘 OP35_DECIDE (24): 同缸体(done→换料优先;空位→全检;满→缓存) INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES (24, 1, 'FULL_CHECK', 'done', '>=', 1, 'OP40_EXCHANGE', '全检台有检测完成→一步换料(跨job交接:取done成品+放待检原位,避免成品滞留)'), (24, 2, 'FULL_CHECK', 'empty', '>=', 1, 'OP40_LOAD', '全检台有空位→全检放料'), (24, 3, 'CACHE', 'empty', '>=', 1, 'OP50_LOAD', '全检台满→缓存暂存'); -- 缸体 OP40_BATCH_DECIDE (31): 满槽或工单最后一件 → OP40_REQ 发 M2102;未满槽且未收尾 → OP40_WAIT 等批次广播 -- 注:occupied<2 分支承担中间件进入等待的关键职责——不满批场景(件数<2)中间件决策等待 -- 永不被唤醒(occupied 永不达 2 且 remaining>0),必须经 OP40_WAIT 等 M2098 广播 -- (由满槽件/最后一件发 M2102 触发)。不能用恒真分支(occupied>=0):恒真触发恒真 warn -- 且掩盖后续分支不可达的配置错误;occupied==2 时 <2 为 false,本分支非恒真。 -- 等待唤醒闭环:第 2 件放料 set FULL_CHECK occupied → OnResourceReleased 精确唤醒 → occupied==2 匹配 -- → 跳 OP40_REQ 发 M2102;工单最后一件自身决策时 remaining==0 匹配;中间件在 OP40_WAIT 等 M2098 广播。 INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES (31, 1, 'FULL_CHECK', 'occupied', '==', 2, 'OP40_REQ', '全检台2槽全满(都是待检)→ 发送 M2102 请求检验'), (31, 2, 'JOB', 'remaining', '==', 0, 'OP40_REQ', '工单最后一件也到全检台(收尾)→ 发送 M2102 请求检验'), (31, 3, 'FULL_CHECK', 'occupied', '<', 2, 'OP40_WAIT', '未满槽且未收尾→OP40_WAIT 等 M2098 批次广播(由满槽件/最后一件发 M2102 触发)'); -- 缸体 OP61_DECIDE (39): 换料下料后缓存回流决策——全检台满2件→立即回批次决策发M2102(防死锁);缓存台有待回流件→代取后二次换料;无→直接回批次决策 -- 恒有出路:满2件/occupied>=1 与 <1 覆盖全部取值,任何时刻决策不挂起。 -- 满2件分支必须优先级最高:换料 job 放完第2个待检件后若全检台已满,先回批次决策发 M2102 启动检测, -- 否则所有 robot 等待方(缓存代取/全检台换料)互相等待形成死锁(2026-08-14 线上事故根因)。 INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES (39, 0, 'FULL_CHECK', 'occupied', '==', 2, 'OP40_BATCH_DECIDE', '全检台2槽全满(都是待检)→立即回批次请求决策(发M2102启动检测,防满件死锁)'), (39, 1, 'CACHE', 'occupied', '>=', 1, 'OP50_EXCHANGE_TAKE', '缓存台有待回流件→代取后全检台2号位二次换料(一趟机器人连续代做)'), (39, 2, 'CACHE', 'occupied', '<', 1, 'OP40_BATCH_DECIDE', '缓存台无料→直接回批次请求决策(发待检信号)'); -- 配油盘 OP40_BATCH_DECIDE (33): 同缸体(等待唤醒闭环同缸体) INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES (33, 1, 'FULL_CHECK', 'occupied', '==', 2, 'OP40_REQ', '全检台2槽全满(都是待检)→ 发送 M2102 请求检验'), (33, 2, 'JOB', 'remaining', '==', 0, 'OP40_REQ', '工单最后一件也到全检台(收尾)→ 发送 M2102 请求检验'), (33, 3, 'FULL_CHECK', 'occupied', '<', 2, 'OP40_WAIT', '未满槽且未收尾→OP40_WAIT 等 M2098 批次广播(由满槽件/最后一件发 M2102 触发)'); -- 配油盘 OP61_DECIDE (43): 换料下料后缓存回流决策(同缸体) -- 满2件分支必须优先级最高:换料 job 放完第2个待检件后若全检台已满,先回批次决策发 M2102 启动检测, -- 否则所有 robot 等待方(缓存代取/全检台换料)互相等待形成死锁(2026-08-14 线上事故根因)。 INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES (43, 0, 'FULL_CHECK', 'occupied', '==', 2, 'OP40_BATCH_DECIDE', '全检台2槽全满(都是待检)→立即回批次请求决策(发M2102启动检测,防满件死锁)'), (43, 1, 'CACHE', 'occupied', '>=', 1, 'OP50_EXCHANGE_TAKE', '缓存台有待回流件→代取后全检台2号位二次换料(一趟机器人连续代做)'), (43, 2, 'CACHE', 'occupied', '<', 1, 'OP40_BATCH_DECIDE', '缓存台无料→直接回批次请求决策(发待检信号)'); -- ============================================================================ -- 十一、产品类型绑定配方 -- ============================================================================ UPDATE product_type SET recipe_id = 1 WHERE id BETWEEN 1 AND 4; UPDATE product_type SET recipe_id = 2 WHERE id BETWEEN 5 AND 8; -- ============================================================================ -- 十二、DOCK 槽位参数引用({dock_slot} 表达式解析用) -- ============================================================================ UPDATE recipe_step_resource SET resource_key = '{dock_slot}' WHERE recipe_step_id IN (1, 14, 15, 30) AND resource_type = 'equipment_slot' AND equipment_type = 'DOCK'; -- 注:OP60_EXCHANGE_LOAD(37/38)与 OP60_LOAD_2ND(42/46)刻意不用 {dock_slot}—— -- 换料 job 一趟要下两次料(前任成品 + 二次换料成品),绑定槽位只有一个,两次都放绑定槽位会自锁死; -- 改用任意空槽位(引擎排除活跃 job 绑定槽位,不会抢其他 job 的接驳台槽位), -- 信号 DockPlacePos 写 {allocated_slot}(实际分配槽位),保证引擎记账与 PLC 参数一致。 -- ============================================================================ -- 十三、序列重置 -- ============================================================================ SELECT setval('recipe_id_seq', (SELECT MAX(id) FROM recipe)); SELECT setval('recipe_step_id_seq', (SELECT MAX(id) FROM recipe_step)); SELECT setval('recipe_step_resource_id_seq', (SELECT MAX(id) FROM recipe_step_resource)); SELECT setval('recipe_step_signal_id_seq', (SELECT MAX(id) FROM recipe_step_signal)); SELECT setval('recipe_step_action_id_seq', (SELECT MAX(id) FROM recipe_step_action)); SELECT setval('recipe_step_decision_id_seq', (SELECT MAX(id) FROM recipe_step_decision)); -- ============================================================================ -- 十四、资源锁种子(引擎运行时状态初始化) -- ============================================================================ -- resource_lock 唯一索引为部分索引(WHERE is_del=FALSE),ON CONFLICT 需带相同谓词。 INSERT INTO resource_lock (resource_type, resource_key, status, held_by_job_id) VALUES ('robot', 'robot', 'idle', 0), ('temp_slot', 'temp_slot', 'free', 0) ON CONFLICT (resource_type, resource_key) WHERE is_del = FALSE DO NOTHING; -- ============================================================================ -- 十五、机器人任务优先级配置种子(组合优先级,数值越小越优先) -- ============================================================================ -- 组合配置:from_type/to_type NULL=通配;UNLOAD+TURN_TABLE=5 为换向取料 -- (换向机构与磨床同链,优先供料磨床,高于普通卸料 10)。 -- 与代码内置默认一致;调整"磨床优先"等策略直接 UPDATE 本表。 INSERT INTO robot_task_priority (task_kind, from_type, to_type, priority) VALUES ('EXCHANGE', NULL, NULL, 0), ('UNLOAD', 'TURN_TABLE', NULL, 5), ('LOAD', NULL, NULL, 10), ('UNLOAD', NULL, NULL, 10), ('WASH', NULL, NULL, 10), ('RELOAD', NULL, NULL, 20), ('TRANSFER', NULL, NULL, 30) ON CONFLICT (task_kind, COALESCE(from_type, ''), COALESCE(to_type, '')) WHERE is_del = FALSE DO NOTHING;