# 生产运行全流程与分支详解(对照 TeamAAS-2.0 在产实现) > 源码依据:`D:\Team\Program\TeamAAS-2.0\TeamAAS-VM\Services\RemoteCommandService.cs`(2125 行,生产核心调度)、 > `Services\CameraCalibrationService.cs`(标定动作)、`Services\CalibrationService.cs`(运行时坐标换算)、 > `Models\PickInfo.cs`(夹具模型)、`Team.FFFeederService`(供料器类库)。 > 兄弟文档:`DEVICE_FLOW.md`(设备对照表)、`ARCHITECTURE.md`、`EXPERIENCE.md`。 --- ## 一、总览:一次"视觉引导取料"的完整闭环 ``` 机械手到位(待拍位) ──TCP发触发命令──▶ 上位机 BgCommunicate(TcpService 监听) │ RemoteCommandService.ExecuteAsync(指令, 回调) ├─ 解析触发命令 → 找到对应视觉流程(Procedure) ├─ Feeder 拍照前动作(开背光/振动, 可选) ├─ 相机 Grab()(先应用配方曝光/增益) ├─ 运行视觉流程(ToolBlock) → 找到工件像素坐标 X,Y,U ├─ 标定换算 ConvertPixelToPosition → 机器人坐标 X,Y(,U) ▼ 机械手 ◀──TCP 回复"触发命令,OK,X,Y,U" ──┘ (机械手用坐标去抓;吸/夹 IO 由机器人程序按 CalibParame 预置的参数自持完成) ``` **核心思想**:上位机是"**应答式视觉服务器**"——机器人/PLC 发触发命令,上位机拍照算坐标回传; 拾放动作本身由机器人程序执行,上位机不逐步遥控。 --- ## 二、触发入口:指令-应答协议(RemoteCommandService.ExecuteAsync) 1. 外部(机器人/PLC/上位系统)通过 TCP 发来一行文本,逗号分割:`触发命令[,参数...]`; 2. `ExecuteAsync` 拆出 `triggerCommand` 与 `commandParams`; 3. **并发防重**:`TryEnterCommandExecution`——同一触发命令上一次没跑完,直接回 `触发命令,NG`; 4. `switch(triggerCommand)` 分发,主要内置命令: - `LoadProduct,{产品名}` —— 加载产品(读产品目录下流程/配方); - `GetProductName[,编号]` / `GetProductID[,产品名]` —— 产品查询; - `GetToolParam,{触发命令},{工具号}` / `GetProcessParam,{触发命令}` —— 取参数; - **视觉触发命令**(每个视觉流程在产品里配置了一个 `TriggerCommand`,如 `V1`)→ 走视觉任务; - 清料任务(编号制,可取消)。 5. 应答格式统一:`{触发命令},OK,{输出项}` 或 `{触发命令},NG,{原因}`。 --- ## 三、视觉引导分支(ExecuteVisionTaskAsync) 按优先级两条路: 1. **脚本优先**:流程目录存在脚本文件 → `ScriptHelper.ExecuteVisionScriptingAsync` (CS-Script/Roslyn 编译执行,整段流程逻辑可被工程师用 C# 接管); 2. **内置流程**(无脚本时): - 普通流程 → `ExecuteNormalVisionTaskAsync`; - **Feeder 视觉流程** → `ExecuteFeederVisionTaskAsync`(见第五节)。 `ExecuteNormalVisionTaskAsync` 步骤: 1. `SetLightBeforePhoto`:按流程配置开光源/背光(可带等待延时); 2. **拍照**:先应用产品配方的相机参数(曝光/增益;UVC 的亮度/对比度)→ `camera.Grab()`; 拍照失败按配置的重试上限重试; 3. **运行视觉流程**(VisionPro ToolBlock / OCR 等); 4. `GetVisionOutput`:按产品里配置的**输出项**收集结果—— - 普通项:直接输出值; - **点位项(IsPointTran)**:值格式 `"x,y,u; x,y,u; ..."`(分号分多个目标),**逐点** `ConvertPixelToPosition` 换算成机器人坐标(保留 3 位小数,附加字段原样带回去); **移动相机(MobileJ4/XY模组)必须携带机器人当前位姿** robotPos 参与换算,否则报 `RobotPositionNull`; 5. 回调应答:`{触发命令},OK,{输出1},{输出2}...`。 --- ## 四、相机安装方式分支(标定取点 + 运行时换算) 枚举:`FixedUp=0 / FixedDown=1 / MobileJ2=2 / MobileJ4=3 / MobileDown_XYPlatform=4 / None=99`。 | 方式 | 物理布局 | 标定九点取点动作 | 运行时像素→机器人换算 | 工具坐标步骤 | |---|---|---|---|---| | **FixedDown** 固定向下 | 相机固定工位上方俯视,机械手吸标定块在下方走位 | **防遮挡循环**(每点):`CalibMotion(点i)` → `CalibOutIO(0)` 放下块 → `CalibMotion(Home)` 退待机 → 拍照 → `CalibMotion(点i)` 回来 → `CalibOutIO(1)` 吸回;九点完回 Home | 仿射矩阵直出机器人 mm →(带 robotCoord 时)`ToolCoord.ComputeTool` 转工具坐标;**回传角度取反** | 需要:CalibrateFixedDownCameraTool | | **FixedUp** 固定向上 | 相机朝上(背光板下),机械手举块到镜头上方 | `CalibMotion(点i, Z)` → 拍照(无遮挡问题) | 同 FixedDown 族(ComputeTool) | 需要:CalibrateFixedUpCameraTool | | **MobileJ2** | 相机装 J2 臂随臂下移 | 同上(走到点位拍照) | 仿射直出 + 转工具坐标;**角度取反** | 需要 | | **MobileJ4** | 相机装末端腕(眼在手,随 U 轴旋转) | **先 `CalibMotion(中心点)` 并把 Mark 点换算到工具坐标系记录**;九点矩阵 = Mark − (点i − 点1 位移)(把 Mark 拉回相机中心) | 仿射出 mm 偏移 → **按 (当前U − MarkU) 构造旋转矩阵修正偏移** → 叠加机器人当前坐标 | 需要:CalibrateJ4MovingDownCameraTool | | **MobileDown_XYPlatform** | 相机装 XY 龙门模组下移 | 同 J4 偏移换算(Mark=中心点,不做工具换算) | 同 J4 偏移公式但**旋转角恒 0**(模组无旋转) | **跳过** | | **None** 独立相机 | 手动 | 手动 | 手动 | 不适用 | **共同前置(旋转预备标定)**:机械手走 P0 / P0+X / P0+Y 各拍一张 → Gram-Schmidt 求图像系↔机器人系 旋转矩阵 + PixelScaleX/Y(mm/px);九点机器人坐标先经该矩阵的逆变换对齐坐标轴,再进仿射求解 (2.0 用 OpenCvSharp `EstimateAffine2D`;我们用正规方程+高斯消元,数学等价)。 验证步骤:0.9 幅面再取 5 点 → RMSEX/RMSEY/最大偏差。 --- ## 五、夹具分支(PickInfo:吸取 vs 夹取) 模型:`PickInfo { PickPlaceModel: Suction|Clamp; Inhal: int; Blow: int; }`(+ 产品/标定里的 `WaitSuction`/`WaitBlow` 延时)。**同一对 IO 位,两种语义**: | 夹具 | Inhal(吸气/夹紧 IO 位) | Blow(吹气/松开 IO 位) | 时序 | |---|---|---|---| | **Suction 吸取**(默认) | 吸真空电磁阀 | 破真空吹气 |到位→吸真空→等 WaitSuction→搬运输送→破真空→等 WaitBlow→放料 | | **Clamp 夹爪** | 夹紧电磁阀 | 松开 | 到位→夹紧→等 WaitSuction→搬运→松开→等 WaitBlow→放料 | **交互方式**:标定/建产品时用 `CalibParame,{夹具类型},{Inhal},{Blow},{Speed},{Accel},{Power},{WaitSuction},{WaitBlow}` **一次性下发给机器人**;生产节拍里吸/放的 IO 时序由**机器人程序自持**(上位机不逐步遥控)。 标定向导与手动调试用 `CalibOutIO,1/0` 直接开关(向导第 2 步的「吸气/破真空」按钮即此)。 --- ## 六、Feeder 分支(供料 + 背光联动) **控制链路**:`Team.FFFeederService` 独立类库—— - TEAM 品牌:TouchSocket TcpClient,ASCII 大括号命令:`{K1}/{K0}` 背光开关、`{UV1}~{UV26}` 选振动组、 `{DV}` 保存、`{HC}` 停止、`{CA}~{CI},{毫秒}` 方向振动(前/后/左/右/斜向);振幅/频率/相位经寄存器读写 (平台起始地址 300、料斗 742、序列 950);断线 1s 重连。 - Afag 品牌:aflex 协议(`SetAuxPowerOut` 背光/辅助输出,振动强度/方向/配置号读写)。 **与视觉/机器人联动(生产)**: 1. `ExecuteFeederVisionTaskAsync`:解析触发命令选项(**是否先振动 / 是否先拍照**); 2. `ExecuteFeederForPhotoBefore`:先振动供料 + `OpenLightAsync` 开环形背光(带亮度与延时); 3. 拍照失败按重试上限重试 → 运行视觉流程 → 输出**点位集合**(Feeder 场景常为多目标); 4. 产品流程里 `FeederStockWork`(振动供料任务)与机器人取料节拍配合;`FeederClearWork` 清料任务 (配置 `Config\FeederClearanceTasksConfiguration.cfg`,支持按编号取消)。 **与标定联动**:向导第 2 步「下一步」时 `Feeder.OpenLightAsync()` 开背光;九点每个点拍照前 `OpenLight()` + 设亮度——保证背光曝光一致。 --- ## 七、与我们的兼容映射(差距清单) | 2.0 能力 | 本程序现状 | 动作 | |---|---|---| | 机器人 TCP 协议(全指令+回显确认) | ✅ EpsonRobot 已同源实现 | 无 | | 相机多品牌 + 软触发 | ✅ 已移植(GenImage 载体更通用) | 无 | | 吸气/夹爪 PickInfo + CalibParame/CalibOutIO | ✅ 已实现 | 无 | | Feeder TEAM/Afag TCP + 配方 | ✅ 已实现 | 无 | | 标定向导 7 步 + 旋转预备标定 + 九点 + 验证 | ✅ 已移植 | 无 | | **RemoteCommandService(触发命令→拍照→视觉→回坐标)** | ❌ 只有 FlowRunner 心跳的简化版 | **补"视觉触发服务"**:触发命令映射到我们的流程(视觉 procedure=一条流程),跑完按输出项(点位项经标定换算)应答——完美契合我们的流程配置模式 | | **输出点位自动标定换算(IsPointTran)** | ❌ | 同上,作为视觉触发服务的输出选项 | | 设置页添加对话框(AddRobot/AddCamera/AddFeeder…) | ❌(配置文件直改) | 移植 UI | | 标定 Feeder 背光联动 / 畸变校正 | ❌ | 补 | | 移动相机换算(J4/XY 模组 robotPos 修正) | ✅ 已移植 | 无 | > 实施建议:第 1、2 行(视觉触发服务 + 点位换算输出)是"我们在流程里配置、对外当视觉服务器"的 > 关键缺口——做好了,机器人侧协议与 2.0 完全一致,现场无需改机器人程序。 > 该服务适配层薄、验收标准清晰,适合派高级工程师 agent 实施;架构侧由本侧验收。