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.yaml(T4:B) |
| 算法库 | plugins/algorithms/opencv、halcon |
含 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.ps1→dist/CodePlanet/bin/(gitignore) - 更新检查:U 盘优先 → HTTPS
manifest.json→ RSA 验签;Apply 下载/解压留 R3
完整性校验(T17:A):Launcher 与 Ops 共用 ProjectValidator(src/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:/..."等绝对路径;静态检查报错。 #include(T20: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:B:
writesGlobals为文档/静态检查辅助;命名推荐{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%/USER:config/editor.json(activeLayout + layouts blob)、projects/ |
| 目标 Dock 网格 | ADE / BDE / CFF(A=图片 B=图参 C=数参 D=编辑 E=项目 F=调试);调试区横跨 D+E 底行 |
| 出厂默认 | 仅 resources/config/editor.default.json → layouts.__default__;USER editor.json 不再存 __default__ blob |
| 可选 Dock | 项目结构/迁移提示 不参与 ensureCorePanelsVisible;打开 yslib 不自动弹出项目结构 |
| 布局持久化 | EditorPreferencesService + QMainWindow::saveState/restoreState;仅「保存当前布局」写 blob;activeLayout 记录上次选用项 |
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 static 与 global(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:新增
KwGlobal;static绑定 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_ok、camB_score;ScriptAnalyzer/ 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++
ModelPluginIPC:(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)、结束态 RunSessionEnded、run_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. UpdateManifestVerifier 从 resources/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. MainTaskTimerService:timer_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 + nonce;CODEPLANET_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子任务写入。 - 跨脚本重复
globalCtrl+B 报错 YS408。 - 定时器 API 主任务可用、子任务 YS406。
- Runtime UI 观察 processGroups 与 global;中/英界面与 Launcher 启动时语言一致。
- 自动化:
run_all_checks.ps1、run_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-阶段交付报告.md;R2 → 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/架构说明.md、docs/维护文件/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)