CodePlanet Platform

CodePlanet 软件帮助

在页面内直接阅读项目文档,支持目录导航与原文下载。

CodePlanet 项目目标与架构终点

下载原文

CodePlanet 项目目标与架构终点

> 文档性质:平台级「北极星」——描述视觉检测设备的终态架构、模块边界与演进路线。 > 当前基线:运维工具(Ops)CodeEditor.exe,AST 运行时 P0~P5 已结案(见 docs/AST审计执行报告/)。 > 版本:v1.5(2026-05-24) > 状态:Q1~Q10、T1~T38 已确认;R0/R1/R1.5/R2 已结案(见各阶段交付报告);R3 目标冻结。

---

1. 愿景与定位

1.1 业务目标

本项目面向 工业视觉检测设备:多相机硬触发采集 → 传统图像处理(OpenCV / HALCON)→ 深度学习模型(Python 统一 runner)→ IO/通讯联动 → 跨工位/跨相机汇总判定(如多路 OK 后驱动下一气缸)。

一台设备可挂载多个产品项目(不同相机参数、脚本、模型),通过 切换 yslib 项目 统一管理,而非「一条线一个软件」。

1.2 平台与环境(T1:A)

决策
目标 OS Windows 10 / 11 x64 工控机(首期不支持 Linux / IoT)
编译 MSVC + Qt 5.11+(与现仓库一致)
部署根 安装包根目录下 {InstallRoot}/(见 §3.4)

1.3 三端产品形态(Ops + Runtime + Launcher)

产品 exe(规划名) 角色
启动器(Launcher) CodePlanetr.exe 启动前 预检、监控 Runtime 启动、完整性/版本/更新;避免静默闪退T7
运行软件(Runtime) CodeRuntime.exe 产线运行:加载 yslib、多相机硬触发、主/子任务、状态 UI
运维工具(Ops) CodeEditor.exe 项目树、编辑 .ys/.yslib、调试脚本、Ctrl+B

三者共享 core / services / 插件接口,单 monorepo(Q1:A)。 产线默认入口:桌面/开机自启 → Launcher → 通过预检后 拉起 Runtime;工程师维护走 Ops

1.4 终态模块(可独立发版)

模块 形态 职责
启动器 CodePlanetr.exe 项目完整性、插件清单、版本/更新、Runtime 监护与日志(§1.5)
运行软件 CodeRuntime.exe 多相机硬触发、主/子任务、汇总与 IO
运维工具 CodeEditor.exe 项目树、多 tab、yslib JSON 编辑
硬件驱动 plugins/hardware/* 多相机、光源、IO
通讯配置 plugins/comm/* Modbus/TCP/串口 + 写队列
模型配置 plugins/models/* 统一 Python runner + config.yamlT4:B
算法库 plugins/algorithms/opencvhalcon 含 XLD/HOBJECT(§4)
共享 core 库 + 源码 AST、VisionObject、yslib、GlobalBroker、ProjectValidator

1.5 启动器 Launcher(T7 — 独立 exe)

背景:Runtime 启动需加载 yslib、多插件、相机/模型/通讯,任一步失败若 无界面直接闪退,现场无法定位。Launcher 作为 轻量、稳定、先启动 的壳,专门做「能启动再启动」。

能力 说明
项目完整性 校验 yslib JSON Schema;scripts[] 路径存在;assets/models/ 引用有效;相对路径可解析
核心插件清单 对照 yslib / 清单 manifest,检查 bin/plugins/ 必需 DLL 是否存在、Qt 版本匹配
预加载探测 可选:Python 环境、相机 SDK 注册、关键 DLL LoadLibrary 烟雾测试(不初始化重型硬件)
启动 Runtime CreateProcess 拉起 CodePlanetRuntime.exe --project <yslib>;捕获 退出码;超时未出现主窗口则报错
监护与日志 Runtime 崩溃/快速退出 → Launcher 弹窗 + 写 %AppData%/CodePlanet/launcher.log;可选 mini dump 路径提示
版本与更新(T13:B + T21) 在线 + U 盘离线(见 §3.5);项目 zip + manifest 校验后解压覆盖(保留 logs/
崩溃诊断(T14:B) 记录 exit code;引导查看 launcher.log / Runtime 日志;启用 Windows mini dump%AppData%/CodePlanet/dumps/
换型 用户选择 projects/ 下另一 yslib → 预检通过 → 结束旧 Runtime 进程 → 启动新 Runtime(T7:A 重启
开机自启(T19:B) Launcher 注册开机自启;禁止 产线绕过 Launcher 直启 Runtime
启动倒计时与修复模式(T19:B) 自启后 5 秒倒计时 再进入预检/拉起 Runtime;倒计时内按 F8修复模式(见下)

修复模式(T22:B)(F8 进入,R1.5):

  • 手动选择/切换 yslib 项目;打开 日志 / dump 目录
  • 可跳过「核心插件清单」预检,在用户确认风险后 仍拉起 Runtime(其它项如 yslib 可读性默认保留)
  • 不自动倒计时启动;由用户点击「启动 Runtime」
  • 不含 内置 yslib 编辑器(编辑走 Ops)

Runtime 启动约束(T27:B + T28:C):Launcher 拉起时传入 --parent-pid=<launcherPid>(或等价令牌);Runtime 校验 父进程为 Launcher,否则拒绝启动。 开发豁免(T28:C):设置环境变量 CODEPLANET_DEV=1 时(Ops 调试、本机开发),跳过 父进程校验;产线 Launcher 不得 注入该变量。

R1.5 已交付补充(2026-05-24)

  • 启动参数 --project= → Ops 自动打开 yslib;ParentProcessGuard + nonce 统一 %LOCALAPPDATA%/CodePlanet/
  • 仓库布局 / CODEPLANET_DEV=1 下可回退拉起 CodePlanet.exe(仍经 Launcher 注入 parent/nonce)
  • UiLocaleService:Launcher 与 Ops 共用 ui/locale;Launcher 右上角 CH/EN 切换;启动 Runtime 时附加 --locale=zh_CN|en(点击「立即启动」快照,Runtime 进程内不再随 Launcher 切换)
  • 本地 staging:scripts/deploy_staging.ps1dist/CodePlanet/bin/(gitignore)
  • 更新检查:U 盘优先 → HTTPS manifest.json → RSA 验签;Apply 下载/解压留 R3

完整性校验(T17:A):Launcher 与 Ops 共用 ProjectValidatorsrc/core/project/),Ctrl+B 与启动预检 同一套规则

不做的事:Launcher 跑 AST、不采图、不替代 Runtime;保持 exe 小、依赖少,降低「守门人也崩溃」的概率。

flowchart LR
    User[操作员/开机] --> L[CodePlanetLauncher]
    L --> V[完整性/插件/版本预检]
    V -->|失败| Err[对话框 + 日志]
    V -->|通过| R[CodePlanetRuntime.exe]
    R -->|异常退出| L
    Eng[工程师] --> Ops[CodePlanetOps.exe]

app_settings 关系:Launcher 与 Runtime 共用 SQLite;default_project_path 由 Launcher 或 Ops 写入。

---

2. 已确认战略选型

2.1 Q1~Q10(架构)

编号 决策 说明
Q1 A monorepo 共享 core,Ops/Runtime 分 exe
Q2 A 首里程碑 Ops 产品化 项目树 + yslib(R1)
Q3 A yslib = JSON Schema + Ctrl+B
Q4 A 默认项目 → app_settings 指针指向 yslib 路径
Q5 B Python 常驻 Worker + IPC
Q6 A OpenCV/HALCON 独立插件 + ImageRuntime
Q7 A 每任务 RuntimeWorker + global 跨任务通讯 §5
Q8 Modbus 独立线程 + 写队列 §6
Q9 A R0 参数/CI;拆 lib 跟 R2
Q10 C Python 开发明文 / 量产加密 §7

2.2 T1~T6(产品与数据)

编号 决策 要点
T1 A Win10/11 x64 工控机
T2 完整项目 一 yslib = 一整台设备上的完整检测方案多工位、多相机 为常态;需显式建模 跨相机/跨工位数据汇总(§5.3)
T3 A 硬触发为主;子任务默认由相机触发,未绑定子任务的相机触发后不执行脚本
T4 B 统一 Python runner + 每模型 config.yaml,非每模型独立入口脚本
T5 见 §3.4 安装根下 /projects/{project_name}/ 目录树(采纳并补充规范)
T6 B 语言层新增 global 关键字ProjectGlobalStore / GlobalBroker(与 static 区分,§5.2)

2.3 T7~T12(启动、汇总、模块、资产)

编号 决策 要点
T7 A + 独立 Launcher exe 非仅「重启 Runtime」:见 §1.5 预检、监护、版本/更新;通过后拉起 Runtime
T8 A 子任务间 不传图像/XLD;仅 global 标量/小结构
T9 A 主任务脚本手写汇总;不用 yslib 自动 aggregate 引擎(§5.3 输送带论证)
T10 A IO/气缸仅主任务 经 IO 插件 + Comm 写队列输出
T11 B import "path.ys" 模块语法;yslib 与任意 .ys 均可 import 同目录树内子脚本
T12 B 标定/ROI → assets/*.json(等),yslib 引用路径

2.4 T13~T20(更新、诊断、import、定时器、自启)

编号 决策 要点
T13 B 在线更新以 项目包 zip 为主(产线换型/修脚本);整包安装可选
T14 B Runtime 异常:exit code + 日志 + Windows mini dump
T15 B import 允许 ../shared/foo.ys 等跨任务目录;禁止绝对路径
T16 不适用 原「epoch 清零平台信号」属 T9:B;现 T9:A,清零/对齐 全部由主任务脚本 实现,平台不配置
T17 A Launcher / Ops 共用 ProjectValidator
T18 B global 命名约定 {camId}_{metric} + Ops/静态 linter 警告(非强制白名单)
T19 B 仅 Launcher 自启;5 秒倒计时F8 → 修复模式
T20 B import#include 过渡期并存#include = 文本展开,import = 模块符号表

2.5 T21~T27(更新源、修复模式、定时器、UI、语义、防绕过)

编号 决策 要点
T21 A + C 在线 HTTPS 更新站 + U 盘离线;见 §3.5
T22 B 修复模式可 跳过插件预检 后启 Runtime
T23 B 定时器用 QElapsedTimer 单调时钟,非墙钟
T24 B 定时器 id 为 字符串名(如 "reject_pulse"
T25 C Runtime UI:日志 + global 表 + processGroups 树状状态(R2 首期)
T26 A R1 一次性 breaking 迁移;语义见 §5.2(用户最终定义)
T27 B Runtime 无 Launcher 父进程则拒绝启动

2.6 T28~T34(开发豁免、更新策略、UI 细项、R0)

编号 决策 要点
T28 C CODEPLANET_DEV=1 跳过 T27 父进程校验(仅开发)
T29 B 更新 manifest / zip:RSA 签名校验(量产)
T30 C manifest 含:项目 zip + Runtime 安装包版本 + 插件 DLL 最低版本
T31 A+B(建议性更新) 更新 非强制;失败/跳过 → 提示可用 U 盘;准备 U 盘前 继续用旧版 正常生产
T32 B processGroups 树叶节点:global 值 + 子任务最后触发时间
T33 B 主任务 loopIntervalMs 默认 20(yslib 可改)
T34 A 编写 R0-执行提示词.md(已创建)

2.7 T35~T38(更新实施、Ops 首屏 — 已确认)

编号 决策 要点
T35 resources/config/update.pub RSA 公钥随安装包分发;UpdateManifestVerifier 读取此路径(R0 stub,R1.5 实装)
T36 仅警告 插件/Runtime 版本 低于 manifest 要求 → Warning,不阻断启动(与 T31 一致)
T37 manifest + 1 个示例 zip conbos.cn/CodePlanetr/Update/ 首批:manifest.json + 一个示例项目包(如 demo-1.0.0.zip);Setup 包可后续追加
T38 B Ops 启动首屏:最近打开的 yslib 列表(+ 仍可浏览 projects/ 树)

---

3. 文件与项目模型

3.1 .ys — 脚本

  • 程序逻辑;AST 管线不变。
  • 可在项目目录内 任意层级 存放;由 yslib 登记路径与角色
  • 模块:import "相对路径.ys"T11:B);路径相对 当前 .ys 文件T15:B),允许 import "../shared/align_utils.ys"
  • 禁止 import "C:/..." 等绝对路径;静态检查报错。
  • #includeT20:B):预处理 文本展开,无模块隔离;与 import 并存,新代码优先 import
  • 建议目录:projects/{name}/shared/ 放跨任务公共脚本。
  • Parser:模块表 + 循环依赖检测;未在 yslib scripts[] 登记的 import 目标 → Ctrl+B 警告

3.2 .yslib — 项目清单(JSON)

项目唯一真相源(除运行时瞬态外)。包含:项目元信息、全部脚本注册、任务入口、相机/工位/工艺组绑定、硬件、模型、通讯。

路径:一律相对 yslib 所在目录(便于整包拷贝、换机)。

3.3 yslib 结构 v1(多相机 / 多工位)

{
  "schemaVersion": 1,
  "project": {
    "name": "product_A",
    "displayName": "产品 A 检测方案",
    "createdAt": "2026-05-21T08:00:00Z",
    "customer": "…"
  },
  "layout": {
    "root": ".",
    "yslibFile": "product_A.yslib"
  },
  "scripts": [
    { "id": "main", "path": "taskmain_name.ys", "role": "main" },
    { "id": "sub_cyl1_camA", "path": "tasksub_cyl1/tasksub_cyl1.ys", "role": "sub" },
    { "id": "mod_helper", "path": "tasksub_cyl1/sub_name.ys", "role": "module" }
  ],
  "tasks": {
    "main": {
      "entryScriptId": "main",
      "loopIntervalMs": 20,
      "description": "汇总各工位/相机结果,驱动气缸2等(loopIntervalMs 默认 20,T33:B)"
    },
    "subs": [
      {
        "id": "sub_camA_cyl1",
        "entryScriptId": "sub_cyl1_camA",
        "trigger": { "type": "camera", "cameraId": "camA", "edge": "hardware" },
        "processGroup": "cylinder1_reject",
        "writesGlobals": ["camA_ok", "camA_seq"]
      }
    ]
  },
  "processGroups": [
    {
      "id": "cylinder1_reject",
      "description": "相机 A/B/C 负责气缸1 剔除逻辑(仅分组/文档/UI,不自动汇总)",
      "cameraIds": ["camA", "camB", "camC"]
    },
    {
      "id": "station_pair",
      "description": "D/E/F/G 负责两工位结果(汇总逻辑在主任务脚本)",
      "cameraIds": ["camD", "camE", "camF", "camG"]
    }
  ],
  "hardware": {
    "cameras": [
      {
        "id": "camA",
        "driver": "hikvision",
        "configPath": "assets/camA.device.json",
        "calibPath": "assets/camA.calib.json",
        "roiPath": "assets/camA.roi.json"
      }
    ],
    "lights": [],
    "ioModules": []
  },
  "models": {
    "runner": "models/runner.py",
    "configs": [
      { "id": "defect1", "configPath": "models/defect1/config.yaml", "enabled": true }
    ]
  },
  "communications": { "modbus": [], "tcp": [], "serial": [] }
}

说明:

  • processGroups:表达「多相机同属一个工艺意图」(ABC 剔除、DEFG 两工位),供 Ops/Runtime UI 分组展示 与文档化; 内置自动汇总(T9:A)。
  • 汇总、对齐、清零/矫正 全部由主任务 .ys 实现T16 不适用)。
  • T18:BwritesGlobals 为文档/静态检查辅助;命名推荐 {camId}_{metric}(如 camA_ok),linter 对不符合约定 警告

3.3.1 标定与 ROI(T12:B)

"hardware": {
  "cameras": [
    {
      "id": "camA",
      "driver": "hikvision",
      "configPath": "assets/camA.device.json",
      "calibPath": "assets/camA.calib.json",
      "roiPath": "assets/camA.roi.json"
    }
  ]
}
  • 大 JSON/标定矩阵 不进 yslib 本体,仅 相对路径引用
  • Launcher 完整性检查:上述文件 存在且 Schema 合法

3.4 项目目录布局(T5 — 采纳与规范)

3.4.1 你提出的结构(规范化)

安装包根目录 {InstallRoot} 下:

{InstallRoot}/
  projects/
    {project_name}/                    # 如 product_A、product_B(换型=换项目)
      {project_name}.yslib             # 项目入口(文件名可自定义,须在 app_settings 登记)
      taskmain_name.ys                 # 主任务入口
      tasksub1_name/
        tasksub1_name.ys               # 子任务入口(可被相机触发)
        sub_name.ys                    # 被 tasksub1_name.ys #include
      tasksub2_name/
        tasksub2_name.ys
        sub1_name.ys
        sub2_name.ys
      models/                          # 【建议新增】该产品的模型 config.yaml + 权重
      assets/                          # 【建议新增】标定、ROI 模板、Halcon 参考图
      logs/                            # 【建议新增】运行时日志(gitignore)
    {project_name2}/
      …

命名:带 _name 处均可自定义;yslib 内用相对路径引用,不依赖文件夹必须叫 tasksub1_name

3.4.2 对你方案的评价与建议

你的做法 评价 建议
每产品一个 {project_name} 目录 ✅ 正确 换型 = 切换 default_project_path 或 Runtime 菜单选项目
yslib 与 ys 同目录树 ✅ 正确 yslib 内路径 相对 yslib 文件
子目录 + 被 include 的 ys ✅ 正确 yslib scripts[] 登记全部 .ys(含 module),Ops 树与 Ctrl+B 不遗漏
仅按文件夹约定、不登记 ⚠️ 风险 必须 yslib 显式列表或「扫描 + 校验未登记文件」警告
安装根 /project ⚠️ 小改 推荐 {InstallRoot}/projects/(复数),与 bin/ 并列;AppPaths::projectsRoot()
多产品共存 app_settings 存默认项目;recent_projects 存多个 yslib 路径
运行时写日志/缓存 增加 logs/cache/ 子目录,避免污染脚本目录

3.4.3 默认项目指针(Q4:A)

  • app_settings.default_project_path = 如 C:/Program Files/CodePlanet/projects/product_A/product_A.yslib
  • 相对路径解析:相对 yslib 文件所在目录,非 bin 目录。

3.4.4 Ops 首屏与最近项目(T38:B,R1)

主题 约定
启动首屏 最近 yslib 列表(路径、显示名、openedAt);列表为空时引导打开 projects/demo.yslib
持久化 SQLite recent_projects(或 app_settings JSON 数组):最多 20 条,去重、按时间倒序
与项目树关系 左侧 ProjectTreeWidget(R0)保留;双击最近项 = 打开 yslib 并刷新树选中
默认项目 仍用 app_settings.default_project_path(Q4);「设为默认」菜单写库

3.4.5 Ops IDE 布局与用户配置(R0 落地,R1 完善)

主题 约定
USER 目录 开发态 %ProjectRoot%/USERconfig/editor.jsonactiveLayout + layouts blob)、projects/
目标 Dock 网格 ADE / BDE / CFF(A=图片 B=图参 C=数参 D=编辑 E=项目 F=调试);调试区横跨 D+E 底行
出厂默认 resources/config/editor.default.jsonlayouts.__default__;USER editor.json 再存 __default__ blob
可选 Dock 项目结构/迁移提示 参与 ensureCorePanelsVisible;打开 yslib 自动弹出项目结构
布局持久化 EditorPreferencesService + QMainWindow::saveState/restoreState仅「保存当前布局」写 blobactiveLayout 记录上次选用项
legacy panels R0 字段;R1 起废弃(layoutVersion≥6 以 blob 为准)
手动调整 取消「锁定布局」 后方可拖拽;调整后 视图→布局→保存当前布局(可覆盖当前自定义布局)
回归 scripts/run_r0_regression.ps1 + scripts/run_r1_regression.ps1

3.5 项目更新分发(T21: A + C)

通道 说明 状态
在线(A) 基址 https://www.conbos.cn/CodePlanetr/Update/ 客户端 R1.5 已就绪;站点部署与 Apply 实装 R3(见 [维护文件/在线更新站部署规范.md](./维护文件/在线更新站部署规范.md))
离线(C) U 盘 CodePlanetrUpdate/manifest.json + 相对路径 zip 客户端 R1.5 已就绪;Apply 实装 R3(见 [维护文件/U盘离线更新部署规范.md](./维护文件/U盘离线更新部署规范.md))

在线目录规划(manifest 驱动,与 T13 项目包 zip 一致):

https://www.conbos.cn/CodePlanetr/Update/
  manifest.json              # 平台/项目版本索引、sha256、下载 URL
  projects/
    product_A/
      product_A-1.2.3.zip
    product_B/
      …
  runtime/                   # 可选:整包安装程序
    CodePlanetSetup-2.x.exe

更新策略(T31 — 建议性,非强制)

原则 行为
非阻断 有新版本时 提示「建议更新」;用户可 忽略 并继续启动
在线失败 / 无网 提示「可使用 U 盘更新」;不阻止 使用当前已安装项目/Runtime 继续生产
未准备 U 盘前 保持 旧版本 运行,直至用户主动完成 U 盘或在线更新
禁止 因更新检查失败而 拒绝启动 Runtime(与强制升级相反)

manifest.json 粒度(T30:C) 示例字段:

{
  "schemaVersion": 1,
  "publishedAt": "2026-05-19T12:00:00Z",
  "signature": "<RSA-SHA256 over canonical json>",
  "runtime": {
    "minVersion": "2.0.0",
    "setupUrl": "runtime/CodePlanetSetup-2.0.1.exe",
    "setupSha256": "…"
  },
  "plugins": [
    { "id": "BuiltinFunctions", "minVersion": "1.4.0", "path": "bin/plugins/BuiltinFunctions.dll" }
  ],
  "projects": [
    {
      "name": "product_A",
      "version": "1.2.3",
      "zipUrl": "projects/product_A/product_A-1.2.3.zip",
      "zipSha256": "…"
    }
  ]
}
  • Launcher:拉取 manifest → RSA 验签(T29:B,公钥 T35) → 对比本地版本 → 建议性 提示 → 用户确认后下载 → ProjectValidator → 解压(保留 logs/)。
  • 插件/Runtime 版本 低于 manifest:仅警告(T36),不阻断生产(T31)。

RSA 公钥(T35)resources/config/update.pub(随安装包复制到 {InstallRoot}/resources/config/);验签失败 → 拒绝应用该 manifest/zip,但不影响继续用本地旧版。

更新站首批(T37)

https://www.conbos.cn/CodePlanetr/Update/
  manifest.json
  projects/demo/demo-1.0.0.zip    # 与 examples/projects/demo 对齐的示例包

U 盘离线布局zipUrl 相对 CodePlanetrUpdate/manifest.json):

{Volume}/CodePlanetrUpdate/
  manifest.json
  projects/
    demo/
      demo-1.0.0.zip
  • 插入 U 盘后 Launcher 优先读 U 盘 manifest;验签规则与线上一致;公钥用安装目录 config/update.pub(T35)。

---

4. 视觉数据与 HALCON XLD / HOBJECT

(与 v0.1 一致,摘要)

  • 不用 QImage 存 XLD;用 VisionObjectStore(每 TaskWorker 一份) + 类型 Raster/Region/Xld/...
  • HOBJECT 仅 Halcon 插件私有持有;UI 通过 polyline JSON 等轻量导出显示。
  • 跨任务传递图像/XLD禁止T8:A);仅 判定结果 写入 global 标量/小结构(§5.4)。

---

5. 任务、线程、global 与多工位数据(T2 / T6 / T3)

5.1 任务与触发(T3:A)

类型 线程 触发
主任务 MainTaskWorker 循环执行 taskmain_name.ys
子任务 每 sub 一个 SubTaskWorker 相机硬触发(yslib trigger.cameraId
未绑定 sub 的相机 触发后 仅采图/缓存(可选)不执行脚本

相机插件:硬触发到达 → 投递到对应 SubTaskWorker 队列(与 UI 线程分离)。

5.2 staticglobal(T6:B + T26:A — 最终语义)

关键字 语义(用户定义,T26 存储 可见范围
static 子任务(或主任务)内部的保持型变量 — 同一 TaskWorker 多次触发仍保留 TaskWorker 局部表 仅本 Worker,不跨任务
global 跨任务的保持型变量 — 主任务 ↔ 子任务 ↔ 子任务间共享 ProjectGlobalStore 全项目;写经 GlobalVariableBroker
局部变量 单次触发 / 单次函数调用 栈/帧 本 Worker

> Ops 单脚本调试补充(R2 约束):若未绑定 ProjectGlobalStore(例如直接调试单个 .ys),global 变量读写回退到参数槽,保证 F5/F6/F10 与 Ctrl+B 语义一致,不出现“已声明但运行时报未定义”。

global int camA_ok = 0;          // 跨任务:子任务写、主任务读
static int trigger_count = 0;      // 本子任务内:每次硬触发累计

function on_camA() {
    trigger_count = trigger_count + 1;
    // … 检测 …
    global camA_ok = 1;
}

迁移(T26:A)

  • R1 一次性 breaking:现 AST 将 static 当作 scope 0(类全局)的行为 删除;scope 0 global
  • 旧脚本:凡需跨任务共享的变量 → 改为 global;仅本子任务累计的 → 保持 static(新语义)。
  • 提供 docs/迁移-static-global.md + Ops 打开旧项目时 一次性告警列表(不做长期双语义,T26 否决 B/C)。
  • Lexer/Parser:新增 KwGlobalstatic 绑定 TaskWorker 存储;Catalog / 高亮同步更新。

5.3 多相机汇总:主任务负责(T9:A)与输送带场景

5.3.1 为何不用「自动 aggregate」(原方案 B)

典型场景:输送带上,相机 A/B 在前端C 在后端,物理位置不同 → 同一时刻各相机看到的 不是同一件产品。若简单取「各相机最新一次结果」对齐,必然乱套

进一步约束:

  • 多数现场 无法稳定追踪产品 ID(无 RFID、无唯一视觉码)。
  • 累加计数 当伪 ID 易 累积误差,一次错位后续全错。
  • 需要 周期清零/矫正(如每 5 分钟或光电/编码器零位),逻辑因线而异。

因此 T9:A(主任务手写汇总)合理:平台 不提供 臃肿的自动对齐引擎;processGroups 仅作 分组与 UI;对齐策略写在 taskmain_name.ys,由懂工艺的工程师维护。

5.3.2 平台建议(增强 A,而非回到 B)

在仍由主任务写逻辑的前提下,平台提供 小粒度机制,避免重复造轮子:

机制 用途
global inspection_epoch 主任务定时或 IO 信号 递增 epoch;子任务写结果时带 global xxx_epoch = inspection_epoch,主任务 忽略过期 epoch
global_int_inc("camA_count") Broker 内原子自增,减少读-改-写竞态
环形槽位 globals global slot0_ab_ok… 主任务维护 write_idx % N(文档提供 范例,非引擎)
清零/矫正 仅主任务脚本(读 IO、定时、计数重置);平台 提供 T9:B 式「平台级清零信号」配置
禁止 平台 假设「三相机各 ok 即 ready」; 自动 merge 最新结果
主任务定时器 §5.7(DO 保持 2 秒等时序由主任务 + 定时器 API 完成)

5.3.3 三层状态(修订)

Layer 1: TaskLocal — 图像/XLD + 子任务 static 计数
Layer 2: processGroups — 仅文档/UI 分组(T9:A 不自动写状态)
Layer 3: ProjectGlobal — 子任务写检测结果;主任务读、对齐、汇总、写 IO(T10)
角色 职责
子任务 A/B/C 检测 → 写 global(结果 + epoch/序号)
主任务 按工艺对齐槽位 → 判定 → 唯一 写气缸/IO(T10:A
IO/Comm CommService 写队列

5.3.4 审计结论(T9)

你的选择与现场约束一致,文档采纳 T9:A。 若未来某条线逻辑稳定且要复用,可将 主任务脚本片段 抽成 import 模块,仍 不是 平台级 auto-aggregate。

5.4 跨任务图像(T8:A)

  • 子任务间 不共享 大图/XLD;仅 global 标量/小结构
  • 图像仅在 TaskLocal VisionObjectStore 内生命周期内有效。

5.5 IO 控制(T10:A)

  • 气缸、输送带、分拣 IO仅主任务 调用 IO/Comm API。
  • 子任务 禁止 直接写气缸/关键 DO;静态检查可警告。
  • CommService 写队列不变(§6)。

5.6 GlobalVariableBroker

  • 所有 global → 队列 → 单线程 apply。
  • → 快照或版本号,避免读一半被写。
  • 可选 global_int_inc("name") 原子自增,供计数型汇总。
  • 命名(T18:B):推荐 camA_okcamB_scoreScriptAnalyzer / Ops linter 对其它模式 警告(可配置严格度)。

5.7 主任务定时器(替代原 T16 平台清零)

背景:T9:A 下,周期清零、DO 脉冲、气缸延时等 时序逻辑均在主任务;子任务 不提供 定时器(避免与 T10 冲突)。

需求(已确认)

能力 说明
数量 不限制 定时器个数(由 Runtime 动态表管理,仅受内存约束)
启动 timer_start(id, duration_ms) 或创建时带时长
停止 timer_stop(id) — 停止计时,保留已计时长
重启 timer_restart(id)从 0 重新计时(时长不变)
查询 timer_elapsed_ms(id) — 当前已计时时长;timer_running(id) / timer_expired(id)
作用域 仅 MainTaskWorker 可调用;子任务调用 → 静态错误

实现归属MainTaskTimerService;内部 QElapsedTimer 单调时钟T23:B),主任务循环 tick(与 loopIntervalMs 同线程)。

定时器 id(T24:B)字符串名,同项目内唯一;重复 timer_create 同名 → 静态/运行错误。

脚本 API 草案(R2,Catalog):

// DO 保持 2 秒后关断
timer_create("reject_pulse", 2000);
io_write_do("reject", 1);
timer_start("reject_pulse");

while (true) {
    if (timer_expired("reject_pulse")) {
        io_write_do("reject", 0);
        timer_stop("reject_pulse");
    }
}
函数(草案) 行为
timer_create(name, ms) 注册命名定时器,默认时长
timer_start(name) 开始/继续
timer_stop(name) 停止,保留已计时长
timer_restart(name) 从 0 重新计时
timer_elapsed_ms(name) 已流逝 ms(单调时钟)
timer_expired(name) 是否达到 duration
timer_destroy(name) 注销(可选)

与清零关系:若需「每 5 分钟矫正」,主任务用 timer_create("session_reset", 300000) + reset_session();平台不配置专用清零通道。

5.8 Runtime 状态 UI(T25:C)

R2 首期CodePlanetRuntime.exe 主窗口):

区域 内容
日志面板 主/子任务、插件、Comm 最近 N 行;可导出到项目 logs/
Global 表 当前 ProjectGlobalStore 快照(名、类型、值、最后写入任务)
ProcessGroups 树(T32:B) processGroups 分组;叶节点(相机/子任务)显示:关联 global 当前值最后硬触发时间(单调时钟戳)
暂不包含(后续) 实时缩略图、最后一次 OK 图路径(T32 否决 C)

刷新:主线程 QueuedConnection 订阅 Broker;UI 节流 100~200ms(与主任务 loopIntervalMs 默认 20ms,T33:B,解耦)。

---

6. 通讯与 Modbus

CommService 独立线程、写 FIFO。 IO 输出策略:与 §5.5 一致,主任务集中下发

---

7. Python 模型(T4:B + Q5 + Q10)

7.1 统一 runner(T4:B)

projects/{project_name}/models/
  runner.py              # 统一入口:load config.yaml → infer
  defect1/config.yaml    # 模型名、权重路径、输入尺寸、class map
  defect1/weights/…
  • C++ ModelPlugin IPC:(modelId, inputTensor/ref, params) → runner 内读 yaml 路由。
  • Ops:校验 yaml 字段与平台 request/response JSON Schema 一致。

7.2 安全(Q10:C)

开发明文;量产加密权重 + 签名校验 runner 包。

---

8. 插件设计规范(R0)

(同 v0.1:IHardware / IComm / IModel / IImageAlgorithm / IConfigPage。)

---

9. 演进路线图

阶段 状态 重点
R0 已结案(2026-05-21) Schema、ProjectValidator、AppPaths、global 占位、demo、项目树、yslib Ctrl+B、Dock 布局;见 R0-阶段交付报告.md
R1 已结案(2026-05-23) static/global breaking、import 静态分析、recent_projects、YslibStructureWidget、迁移扫描;见 R1-阶段交付报告.md
R1.5 已结案(2026-05-24) Launcher v1、RSA 验签、父进程约束、F8、i18n、staging;见 R1.5-阶段交付报告.md
R2 已结案(2026-05-24;调试收敛 2026-05-26) Runtime exe、Main/SubTaskWorker、import 运行时、YS408、include、MainTaskTimerService、状态 UI + i18n、父进程校验;Ops F6 可视策略(if/switch/for)、结束态 RunSessionEndedrun_r2_regression 构建重试;见 R2-阶段交付报告.md §15
R3 待启动 硬件/Comm、更新 Apply(下载/解压/覆盖)在线+U 盘 E2E 测试(Apply 后)、更新站运维(T37)、mini dump;测试计划见 AST审计执行报告/R3-更新Apply与E2E测试计划.md
R4 待启动 Python runner
R5 待启动 OpenCV/HALCON 独立插件

R0 已覆盖、R1 不再重复验收:左侧项目树、ProjectValidator+Ctrl+B、demo 项目、AppPaths::projectsRoot()、路径/迁移文档、global 词法与高亮占位。

---

10. 与当前 Ops 差距(post-R1)

能力 R1 缺口阶段
yslib Schema + Validator + demo
项目树 + yslib Ctrl+B
static 任务内 / global 跨任务
import 静态分析 运行时链接 ✅(R2)
最近 yslib 列表(T38)
yslib 结构化编辑
迁移 static→global 扫描 手动触发(非自动弹窗)
项目级 global 重复定义 Ctrl+B R2 YS408
import 跨文件调用用户函数 R2 运行时 + demoV1.1
Launcher / Runtime 独立 exe ✅ / ✅ R1.5 Launcher;R2 Runtime
产线多任务 / 真机硬触发 骨架 ✅ R3 真机 trigger
GlobalBroker(若单独抽象) R3+

---

10.1 R1.5 目标与边界(已结案,2026-05-24)

> 交付报告:[docs/AST审计执行报告/R1.5-阶段交付报告.md](./AST审计执行报告/R1.5-阶段交付报告.md)

R1.5 必做(进入 Runtime 前的“守门”能力)

1. CodePlanetLauncher.exe 可独立启动,作为产线默认入口。 2. 启动链:5 秒倒计时,倒计时期间 F8 进入修复模式(T19/T22)。 3. 预检复用 ProjectValidator(T17),支持选择项目并拉起“运行进程目标”:

  • 产线目标:CodePlanetRuntime.exe(R2 真正落地);
  • R1.5 过渡:允许配置回退到 CodePlanet.exe 做启动链联调(仅开发/联调环境)。

4. UpdateManifestVerifierresources/config/update.pub 读取公钥并完成 RSA 验签(T35/T29)。 5. 更新策略执行 T31:建议性更新,失败仅提示 U 盘,不阻断旧版本运行。 6. Runtime 启动约束(T27)+ 开发豁免(T28):

  • 产线需 Launcher 父进程/令牌;
  • CODEPLANET_DEV=1 时允许开发直启。

R1.5 不做(明确留给 R2/R3)

  • CodePlanetRuntime.exe 完整产线能力(R2)
  • import 运行时模块链接与跨文件用户函数调用(R2)
  • 项目级 global 重复定义检查(R2)
  • MainTaskTimerService、Runtime 状态 UI(R2)
  • 更新包下载、解压、覆盖 Apply(R3)
  • conbos 站点运维上架、硬件/Comm 插件(R3)

R1.5 验收口径(摘要)— 已通过

  • Launcher 能在预检通过后启动 Runtime,并在 Runtime 快速退出时弹出错误与日志路径。
  • F8 修复模式可跳过插件预检启动(带风险确认),且不自动倒计时启动。
  • 验签失败时拒绝应用更新包,但允许继续运行本地旧版。
  • 插件/Runtime 版本低于 manifest:Warning,不阻断(T36)。
  • 在线/U 盘/Apply 完整 E2E:统一在 R3 Apply 实装后验收(见 [R3-更新Apply与E2E测试计划.md](./AST审计执行报告/R3-更新Apply与E2E测试计划.md));R1.5 仅验签单测 + 断网不阻断。

---

10.2 R3 更新 Apply 与 E2E 测试(计划)

> 详细步骤:[R3-更新Apply与E2E测试计划.md](./AST审计执行报告/R3-更新Apply与E2E测试计划.md)

里程碑 内容
R3 开发 Launcher Apply:下载、SHA256、解压、保留 logs/ProjectValidator
R3 测试(U 盘) 验签失败、缺 zip、Apply 闭环、U 盘优先于在线
R3 测试(在线) conbos 静态托管、HTTPS 拉取、Apply 下载
不在 R1.5 测 上述 E2E 统一在 Apply 可用后一次性回归

---

10.4 R3 目标与边界(执行口径)

> 执行入口:[docs/AST审计执行报告/R3-执行提示词.md](./AST审计执行报告/R3-执行提示词.md) > 更新专项测试清单:[R3-更新Apply与E2E测试计划.md](./AST审计执行报告/R3-更新Apply与E2E测试计划.md)

R3 必做(从“可提示更新”到“可安全应用更新”)

1. Launcher Apply 更新实装:下载(在线/本地)→ SHA256 校验 → 解压覆盖项目(保留 logs/)→ ProjectValidator 复核。 2. 在线 + U 盘 E2E 全量执行(T-UPD-1~11),并形成可追溯记录表。 3. U 盘优先策略、断网不阻断、签名失败/缺包可读报错(维持 T31/T36 产品行为)。 4. SubTaskWorker 对接 真实触发入口(至少抽象层接入,允许无真机 mock)。 5. mini dump 落盘与路径提示(%AppData%/CodePlanet/dumps/),补齐 R1.5 占位。

R3 不做(留后续)

  • Python runner 产线闭环(R4)
  • HALCON/OpenCV 产线插件化(R5)
  • 更高阶运行时诊断(性能剖析/分布式日志)

R3 验收口径(摘要)

  • Apply 成功后可启动并加载新项目版本;失败不破坏旧版本可运行性。
  • 在线/U 盘两通道均通过 E2E,且 U 盘优先策略可复现。
  • 子任务真实触发链路可验证(真机或规范化 mock),simulateTrigger 不再是唯一入口。
  • dump 文件可按错误路径定位。

---

10.3 R2 目标与边界(已结案,2026-05-24)

> 交付报告:[docs/AST审计执行报告/R2-阶段交付报告.md](./AST审计执行报告/R2-阶段交付报告.md) > 执行入口(归档):[docs/AST审计执行报告/R2-执行提示词.md](./AST审计执行报告/R2-执行提示词.md)

R2 必做(运行时落地)— 已完成

1. CodePlanetRuntime.exe 最小可运行壳:可被 Launcher 拉起并进入主任务循环。 2. 多任务执行骨架MainTaskWorker + SubTaskWorker(按 yslib tasks/trigger 建图)。 3. import 运行时链接:导入模块函数可被当前脚本调用。 4. 项目级 global 重复定义检查:Ctrl+B 报错 YS408(跨脚本同名冲突)。 5. #include 路径解析修正:相对「当前脚本目录」。 6. MainTaskTimerServicetimer_create/start/stop/restart/elapsed/expired(T23/T24);表达式 timer_expired 返回 0/1。 7. Runtime 状态 UI 首期:日志 + global 表 + processGroups 树(T25/T32);界面 i18n 随 Launcher --locale=。 8. 父进程约束接入 Runtime--parent-pid + nonceCODEPLANET_DEV=1 开发豁免。 9. Ops 调试一致性修复global 在无 ProjectGlobalStore 场景回退参数槽存取;跨文件 F10 返回采用调用方恢复点与 CRLF/LF 归一化,避免错误回跳与会话误重置。 10. F2/F3 就地重置 + 项目树展开策略:F2/F3 在当前文件首行重置(RunDebugReset),不回跳旧 IP,重置后可直接 F5/F6/F10;项目树启动/刷新后仅展开 active 项目。 11. F6/F10 逐行箭头:单步按物理行推进(含空白/注释);函数声明扫描跳闭合行;顶层调用 F6 进入函数头行;F10 跨文件返回落在调用语句下一行(executingStatementLineForFrame + 1)。 12. 首轮一致性 + F5 结束位sourceFilePath 已绑定时首轮 F6/F10 与 F2 后语义一致(不再出现“第一遍不跳函数声明”);F5 完成态箭头统一落在入口脚本末行(EOF)。

R2 不做(明确留给 R3+)

  • 更新 Apply(下载/解压/覆盖)与在线/U 盘 E2E(R3)
  • 硬件/Comm 插件真机联调、子任务 相机硬触发(R3;R2 为 simulateTrigger
  • Python runner 产线链路(R4)
  • HALCON/OpenCV 插件产线化(R5)

R2 验收口径(摘要)— 已通过

  • Launcher 正常拉起 Runtime(非 Ops 回退)。
  • demoV1.1:import 跨文件调用、pulse_active 定时器 2s、camA_ok 子任务写入。
  • 跨脚本重复 global Ctrl+B 报错 YS408。
  • 定时器 API 主任务可用、子任务 YS406。
  • Runtime UI 观察 processGroups 与 global;中/英界面与 Launcher 启动时语言一致。
  • 自动化:run_all_checks.ps1run_r2_regression.ps1、父进程拦截测试 pass。

R2 本机构建约定(Release 推荐)

步骤 说明
Qt Creator Release 构建全部 覆盖 bin/*.exe(三端)
scripts/deploy_bin.ps1 -Config Release 必须windeployqt + plugins/config/translations)
scripts/run_launcher_dev.ps1 -Config Release 可选;本机 dev 启动 Launcher

注意:Release exe 与 Debug Qt DLL(Qt5Cored.dll)不可混用;切换配置后须对应该 -Config 重新 deploy_bin

---

11. 已确认项索引

  • Q1~Q10:§2.1
  • T1~T6:§2.2
  • T7~T12:§2.3
  • T13~T20:§2.4、§1.5、§3、§5
  • T21~T27:§2.5、§3.5、§5.2、§5.7、§5.8、§1.5、§9
  • T28~T34:§2.6、§3.5、§5.8、§9
  • T35~T38:§2.7、§3.4.4、§3.5

---

12. 文档完善度评估(v1.5,post-R2)

维度 完成度 说明
战略与产品决策(Q+T) 100% Q1~Q10、T1~T38 已闭环
三端边界与职责 ~99% Launcher + Runtime 产线最小闭环;R3 口径冻结
数据模型 ~90% docs/schemas/* 与 demo 已存在(R0)
运行时机制 ~96% R2 产线 worker + timer + import 运行时;真机 trigger 待 R3
实施路线图 ~99% R0~R2 结案,R3 目标/验收路径已冻结
与仓库同步(§10) ~99% post-R2 差距表已更新

综合完善度:约 98%

阶段文档:R0 → R0-阶段交付报告.md;R1 → R1-阶段交付报告.md;R1.5 → R1.5-阶段交付报告.mdR2 → R2-阶段交付报告.md

---

13. 实施期可选项(非 T 编号,按需)

主题 说明
更新站运维 + E2E 部署规范见 docs/维护文件/Apply 与在线/U 盘闭环测试R3-更新Apply与E2E测试计划.md
R1 拆分 工期紧时:先 static/global 迁移 → 再 最近列表 + import 分析
Ops 更名 CodePlanetOps.exe 可与 R1.5 Launcher 打包一并改,非 R1 必须

---

14. 文档维护

  • 同步:docs/架构说明.mddocs/维护文件/AST逻辑架构.md.cursor/开发指南.md(重大变更时)。
  • 阶段验收:docs/AST审计执行报告/(R0~R5)。

---

15. 变更记录

版本 日期 摘要
v0.1 2026-05-21 Q1~Q10、VisionObject、Broker、R0~R5
v0.2 2026-05-21 T1~T6:projects 目录、global、processGroups
v0.3 2026-05-21 T7~T12:Launcher、T9 主任务汇总、import、assets
v0.4 2026-05-19 T13~T20:项目包更新、mini dump、import、主任务定时器、F8 修复模式
v0.5 2026-05-19 T21~T27:conbos 在线+U盘、修复模式、定时器、Runtime UI、父进程校验
v0.6 2026-05-19 T28~T34:DEV 豁免、RSA manifest、建议性更新、UI 叶节点、R0 提示词;Q+T 冻结
v0.7 2026-05-21 §3.4.5 Ops IDE:USER 配置、Dock CFF、布局持久化、R0 回归
v0.8 2026-05-21 T35~T38;R0 结案;§9/§10 刷新;R1 目标与提示词
v0.9 2026-05-23 R1 结案;§3.4.5 布局显式保存、panels 废弃;§10 post-R1
v1.0 2026-05-23 R1.5 目标/边界/验收口径冻结;完善度与路线图同步更新
v1.1 2026-05-24 R1.5 结案;§3.5 U 盘路径修正;更新站/U 盘部署规范;Launcher 交付补充
v1.2 2026-05-24 在线/U 盘 E2E 测试统一并入 R3 Apply 后R3-更新Apply与E2E测试计划.md
v1.3 2026-05-24 R2 目标/边界/验收口径冻结;新增 R2-执行提示词.md 入口
v1.4 2026-05-24 R2 结案;Runtime i18n(--locale=);§10.3 验收通过;Release+deploy_bin 约定;§10 差距表刷新
v1.5 2026-05-24 R3 目标/边界/验收口径冻结;新增 R3-执行提示词.md 入口;完善度更新

---

CodePlanet — 视觉检测平台架构终点(living document)

帮助阅读建议

  • 左侧目录可快速切换文档,右侧区域支持长文滚动阅读。
  • 遇到复杂流程,建议先阅读“项目目标与架构终点”再看部署规范。
  • 每份文档都保留原文入口,便于下载归档或离线传阅。