FFVision 智能视觉INDUSTRIAL VISION

软件下载与更新

轻量补丁包适合已装客户升级(十几 MB、秒级),完整安装包适合新机安装或更换运行环境

下载用户手册
最新版本4.2.02026-10-03 发布
目标框架 net10.0-windows随包固件:FVT控制卡 | v2.5.3 | firmware-app.bin | D:\work\AxisControl\firmware\build\release\v2.5.3\firmware-app.bin / FVT智能光机 | v1.0.6 | gd32f407_w5500_app.bin | D:\work\AIGJ\build\gd32f407_w5500_app.bin / FVT云台 | firmware_v1.4.11.fvt | firmware_v1.4.9.fvt + ESP32_GENERIC_YTEx_v28.bin | D:\work\YTEx
轻量补丁包(推荐)
FVision-AI-Patch-4.2.0.zip · 17.0 MB
下载

只含变更的程序文件,逐文件 MD5 校验后覆盖并重启,几分钟完成升级。

MD5:f49c43cbdbdd1fffeaa4bb47fb2b0025
完整安装包
FVision-AI-Setup-4.2.0.exe · 1.9 GB
下载

新机安装、或本次升级更换了 .NET 运行环境时使用(体积较大,建议用下载工具)。

SHA256:6526e9a71e392489ee03fccb3187778c21dd87c607ebc7f12327f8e88b4b7075
下载后请核对校验值
PowerShell:
Get-FileHash .\FVision-AI-Patch-4.2.0.zip -Algorithm MD5
文件不完整或校验不一致时请重新下载,不要直接安装。

更新说明

FVision-AI(AreaAI)

Windows 桌面工业视觉检测软件:相机采集 → ONNX GPU 推理 / OpenCvSharp 传统视觉 → 结果输出,
配合运动控制(FVT/固高/雷赛)、机械臂(越疆)、云台、智能光机、Modbus 等硬件;
逻辑图(.stn)由 NodeFlow 子工程承载(节点编辑器 + 执行器)。

发布约定:每次发布补丁包,都在下面「版本更新记录」里追加一条(写清这一版加了/修了什么),
并把本文件一并放到投放目录(现场可直接看到补丁内容)。


版本更新记录

4.2.0(2026-10-03)

自 4.2.0 起按「完整安装包」发布——功能与 4.1.62 相同(检测模板建模向导 / 标注可撤销与免重复确认 / 训练前检查清单 / 模板试匹配自检 / 图层模板图缩略图与导入 / 定位模板参数就地生效 / AI 操作条三处 z 序遮挡修复等),本版重点是安装包口径 + 可选组件:

  • 四个 exe 图标各不相同:主程序用 Resources\app.ico;FVT控制卡 / 智能光机 / 云台各用自己仓库的 app.ico(由各工程 <ApplicationIcon> 内嵌进 exe)。安装包不再随包发 tool\*.ico,安装器三条工具快捷方式也不再指定 IconFilename,直接显示各自 exe 的内嵌图标。
  • 母版库随包下发:data\stn-templates\(来源=投放镜像 D:\work\publish\stn-templates,如 sets\机械臂\{hw,product,teach}.stn)。全新安装与升级都下发,但逐文件「缺失才写」→ 现场自己改过的母版不会被覆盖,随包新增的方案会补齐;卸载不删。轻量补丁不含母版。
  • 完整包组件(安装器 full 类型默认勾选):CUDA 13 + cuDNN 9(GPU 推理)、AI 模型、用户手册/演示视频、模板样例工程(检测样例 + logitall)。
  • 三件套随发布自动重编(各工程自带 ApplicationIcon),随包带最新 OTA 固件:FVT控制卡 v2.5.3、FVT智能光机 v1.0.6、FVT云台 firmware_v1.4.11.fvt + ESP32 YTEx v28。

4.1.62(2026-10-03)

检测模板:建模向导面板 + 标注可撤销/免重复确认 + 训练前检查清单 + 模板试匹配自检 + 图层模板图缩略图与导入;定位模板参数改「就地生效」;修 AI 操作条三处遮挡(Dock z 序写反)

  • 建模向导(新增 Form/BlobWizard.cs):非模态停靠面板,按「选模型 → 标 ROI / OK-NG → 生成训练图/掩膜 → 训练 → 阈值试跑」分段推进,不离开画布就能走完整条链路。
  • 标注可回退:特征库加单级快照 + 操作条「撤销更新」;连续标注可勾「本次不再询问」免重复确认;方向键微移 1px(Shift=10px)、F2 数值微调(挂到窗体 KeyPreview,不再受画布焦点链影响)。
  • 训练前检查清单:点「训练」先自检并弹三色清单(缺项红色并阻塞训练),替代原来只弹一句模糊提示。
  • 定位模板试匹配自检:对图像列表逐图跑模板匹配,输出分数 / 位置 / 角度报告窗,投产前就能看出模板稳不稳。
  • 图层模板图:图层列表 owner-draw 缩略图(一眼看出有无模板图);右键新增「从文件导入模板图」,新旧并排预览确认后再写盘(写盘后回读校验)。
  • 定位模板参数就地生效:匹配最低分数 / 角度值 / 角度范围 / 缩放 / 步进 改完即保存 → 推送原生句柄 → 自动重训 + 立刻试跑,状态行汇报命中数/分数/位置/角度;角度范围等越界会被校验拦下。
  • ROI 批量选择与复制:画布右键「按标签选择 ROI」升级为批量选择窗(标签复选 + 按分数范围过滤);图层右键新增「复制标签布局到图层…」(跨图层深拷贝,目标已有框会先确认)。
  • 修 AI 操作条三处遮挡(Dock z 序写反,含上版遗留):①操作条把算法/基础算法/图层列表首行与画布顶部盖住;②操作条内层状态行文字被裁;③操作条与状态行之间透出一条浅色边线(Sunny 面板浅色填充+边框 + ToolStrip 默认底边线)——改为按 z 序显式 SetChildIndex(先 Fill 后 Top)。同类根因的两个动态弹窗(训练前检查清单、模板自检报告)一并修正。
  • 画布联机提示:拉框实时显示框 W×H 与中心坐标;连续创建模式在画布显示「连续创建中,Esc 退出」横幅。

4.1.61(2026-10-01)

检测模板(Blob 算法编辑窗):外观检测「有定位 / 无定位」人机操作界面精简 + 步骤化操作条 + 状态行;参数去魔法数字;顺带修掉模板建立链路 4 个缺陷

① 精简模式(选中外观检测两类算法时自动切换,切走自动还原):底部整条带(曲线图 / 传统参数滑条组 / 颜色图 / 数据表)收起,
高度让给画布;两套右键菜单同步精简——AI模型库菜单按流程分 5 组(模型管理 / 标注 / 训练数据 / 训练执行 / 阈值与特征),
「无定位三项」与「有定位三项」按算法类型互斥显示;画布右键只留绘制 / 选择 / 检测相关项(卡尺、直线、圆环ROI、拾色、掩膜、测量、
纹理保存、ROI注册、扩展等隐藏,有定位才显示定位三项)。操作条勾「完整界面」可临时全开,不改 Designer 生成区、全部可逆。

② 顶部操作条 + 状态行(原来没有):一键串联 导入图片 / 单张图片 / 画区域 / 画定位框(有定位) / 删定位框(有定位) /
定位验证(有定位) / 模板参数(有定位) / 标NG(N) / 标OK(X) / 更新模型(Y) / 生成训练图 / 生成掩膜 / 训练 / 保存模型 / 检测验证 / 显存释放;
原先藏在图像列表右键里的「浏览 / 定位 / 检测 / 打标签 / 全部检测」模式选择器提到操作条上。
状态行常驻显示:图层|算法|模型名|good 样本数|其它类别|模型 已训练(时间)/未训练|定位 未初始化/正常/失败;
按钮按「模型已绑定 / 有样本 / 定位已验证 / 已有模型文件」分级启用,点「训练」前先自检并列出缺什么(样本偏少、未生成掩膜列为提醒项)。

③ 参数面板去魔法数字:有定位AI检测的「定位类型」(0~5 自动选择/两直线/两圆/线圆/模板定位/圆定位)与「根据尺寸旋转图像」
改中文下拉(写回仍是原 int 索引,存盘格式不变、旧配方零迁移);无定位AI检测隐藏 定位类型 / 尺寸旋转 / 尺寸号(运行时不使用,避免误填);
「不显示掩膜 / 不显示检测结果 / 不显示检测元素」改自解释标题;新增「定位模板参数」入口
(匹配最低分数 / 角度值 / 角度范围 / 缩放 / 步进 —— 这些参数本就挂在定位模板对象上,此前界面没有入口)。

④ 模板建立链路缺陷修复:

  • 「有定位生成训练掩膜」的多边形掩膜原为空分支(静默丢弃)→ 补 FillPoly,并补上缺失的 DisPos 反相,与无定位链路对齐;
  • 批量生成训练图片原为静默 continue → 结束弹「成功 N / 跳过 M」清单,跳过原因分 无ROI / 定位失败 / 写盘失败 三类;
  • 定位模板训练反馈补全:成功改信息级日志、失败给原因级错误、「没有定位模板」不再静默(新增 showResult 可选参数,自动路径不弹窗);
  • 删除重复且未接线的空处理器「无定位掩膜生成外观检测训练图片」;「模型恢复 / 释放显存 / 清除自由标签」加二次确认(清除标签会先列出数量)。

4.1.60(2026-10-01)

参数与逻辑图备份体系(二版):按「系统 / 产品」两级划分 + 保存前自动留上一版 + 主程序内置「🛠 备份与恢复…」;取消 data\bconfig、删除老 Restore 工程

① 统一备份仓库(新):<备份根>\(参数项「备份根目录」,默认空 = 程序目录 backup\,可指别的盘或共享)——
system\(与产品无关:config\Config.dat.<时间戳>.dat、stn\_app\…、templates\…)与
product\<产品>\(与产品有关:config\config_<产品>.<时间戳>.dat、stn\…)两级分开存放,
条目类型=系统参数 / 系统 stn / 母版 / 产品配置 / 产品 stn;每份备份同目录写 .meta.json
(原始路径 / 时间 / 类型 / 产品 / 大小 / 版本 / 备注),meta 丢失时按目录结构回退推断。
保留策略:同一文件最近 20 份、system\ 与每个 product\<产品>\ 各自合计 ≤300MB,超限从最旧删(各记一条日志)。

② 保存前自动留上一版(不再有"改坏了回不去"):参数走 CConfig.Save / 产品模板 Tmps.Save 写盘前的快照;
逻辑图的所有写盘路径(画布保存 / 另存为覆盖 / 母版保存 / 分组编辑写回 / 独立编辑器)统一经新增的库层钩子
STNodeEditor.BeforeSave,由 NodeFlow.WinForms.Backup.StnBackup 按路径自动归类(程序 stn\=系统 stn、
data\stn-templates\=母版、其余=产品 stn)。"开始运行"留档与"每 300 帧产品配置留档"也改写进新仓库。

③ 取消 data\bconfig:首次启动新版把该目录里最新一份能读成 CConfig 的配置迁进 system\config\
(备注"旧 bconfig 迁移"),随后直接删除整个目录并记日志(读不出来则只删并告警)。旧目录不再写入。

④ 自动恢复链改口径:隔离件 → Config.dat.bak → <备份根>\system\config\*.dat(最新 8 份逐个试读) →
backup\<版本>\…\Config.dat(升级前快照,原逻辑);产品配置同理追加 backup\product\<产品>\config\*.dat。

⑤ 主程序内置恢复窗口:菜单「参数设置 → 🛠 备份与恢复…」与逻辑图画布右键同一入口(打开时预选本画布 stn 的备份)——
顶部:备份根目录 +「📂 打开目录 / 📦 立即备份 / ↻ 刷新」+「范围:全部 / 系统(与产品无关)/ 当前产品」;
列表按类型分组(时间 / 类型 / 目标路径 / 大小 / 状态 / 备注),可读性懒校验(视图最近 20 条 + 选中项;
参数=试读、stn=节点数),不可读标红并禁止恢复;恢复前自动把当前文件再快照一份,
并按类型给出影响范围(系统参数=影响所有产品、重启生效;产品参数=只影响该产品,可一键重新加载该产品;
stn=正被画布打开则即时重载,否则下次打开生效)。

⑥ 升级前快照 + 删除老工具:点升级时先把"系统 + 当前产品"整体快照到 backup\upgrade\<旧版本>\
(内部保持 system\ / product\<产品>\ 结构 + manifest.json,与脚本自己的程序文件备份合起来才是完整回滚点)。
老 Restore 工程(只读 data\bconfig 的人工恢复工具)已从解决方案删除,功能由主程序「🛠 备份与恢复…」取代。

相机 Bayer→BGR 全链路提速(OpenCV 主实现 + 原位零拷贝 + 释放原始字节);水印改字符串;存图标注 Mat↔Bitmap 往返省掉两次整幅拷贝

  • Bayer→BGR 真机改走 OpenCV(Cv2.CvtColor BayerRG/GR/GB/BG2BGR,双线性去马赛克):去掉海康 SDK 那层;
    OpenCV 结果原地写入结果 byte[](源/目标都钉住、用 Mat 包住目标缓冲 → 无中间 Mat、无整幅 Marshal.Copy)。
    实测 5MP 2.1ms/帧(≈478 帧/秒;旧逐像素 51ms、纯托管回退 14ms),20MP 约 11ms;每帧托管分配 = 结果数组本身(14.34MB / 57.22MB,已是理论下限)。
    NodeFlow.Core 仍零原生依赖:BayerConverter 出钩子,AreaAI 在 NodeFlowHost 注册(未注册/失败自动回退托管最近邻)。
  • 内存:Bayer/Mono8 帧在首次成功转出 BGR8 后释放原始字节(消费者只用 GetBgr8)→ 每帧常驻 4×w×h 降到 3×w×h(5MP 省 5MB/帧、20MP 省 20MB/帧);转换失败时保留便于排查。
  • 水印改字符串:系统参数「产品存图添加水印(检测前)」bool → 「图片水印文字(空=不加水印)」;非空即画该文字(GDI+,中文不乱码),
    支持占位符 {产品名} {水印名称} {图层} {日期} {时间};老配置勾过的自动迁移成等价文案(只迁一次、不覆盖用户改过的文字)。采集设置向导里的水印询问改成文字输入框。
  • 存图标注(水印/批量烧录)Mat↔Bitmap 往返优化:去掉两次多余整幅 Clone + 复用绘制用 Bitmap(不再每张图分配 15MB/60MB 的整幅 Bitmap)
    → 5MP 14.9ms → 4.7ms,输出逐字节不变(等价性已断言)。
  • 新增自检:AreaAI.exe --bayer-bench [宽 高 图案 次数](三条实现计时 + 每帧分配 + 内存说明)、--watermark-selfcheck。

4.1.59(2026-10-01)

系统参数清理:删 6 个"改了没用/危险"的参数 + 9 个 0 值参数给出合理默认(老配置一次性补齐)+ 47 条描述全部重写

  • 删除 6 个参数(现场改了也会被代码/产品模板覆盖,或属危险调试开关):
    虚拟相机个数(启动按加密狗写死 8)、高速相机回调线程(运行期状态)、图层容量(由 行数×列数 / 图层数 覆盖)、
    产品OK/NG计数到自动停止(载入产品即被产品模板覆盖)、模拟NG(生产误开=全判 NG)。
    改法:无法再配的值改常量/内部字段/直接读产品模板;旧 Config.dat 里这些键自动忽略。
  • 9 个 0 值参数给出合理初始值(0 原来意味着"不画框/看不见/高度恒 0/必判红"这类无效效果):
    尺寸显示大小 12、检测信息文字大小 12、坐标轴大小 50、面显示大小 3、点滤波半径 3、
    边界框宽度 0.005(占图像短边比例)、边界框透明度 128、Z比例 1000(1:1)、BD 判定上下限系数 1。
    已有现场配置按"值 ≤0 = 从未配过"一次性补齐(新增 DisplayDefaultsVersion 迁移标记,照日志筛选那套做法;
    现场显式设过的非 0 值永不覆盖)。现场升级后能看到的变化:结果图出现 OK/NG 边界框、坐标轴/文字回到默认尺寸、
    3D 高度显示正常、测量面板按模板公差判色。
  • 去掉 4 处"绘制期写回配置"(坐标轴大小/面显示大小/点滤波半径/边界框透明度):只在本帧用局部默认值,
    不再把默认值写回 Config.dat。
  • 描述补全:47 条系统参数全部按统一口径重写(作用|取值/单位|默认值与 0 的含义|生效时机|注意),
    其中把名字不达意的写清:BD 上下限公式、Sin 实际是 cosθ、SetK 加补偿值、FXZX 是置信度阈值、
    EnableCnt 是"累计超过 N 条才写库"、行数/列数 由自动布局决定。分类维持 7 类,6 批次与数据库 更名 6 数据库。

Bayer→BGR 提速:真机走海康 SDK 转换 + 托管回退重写(5MP 实测 45.1ms → 12~15ms,3.1×)

  • 真机改走厂商 SDK:Bayer8→BGR8 用海康 MV_CC_ConvertPixelType(厂商 SIMD + 双线性去马赛克),与主程序
    FWLib/CameraMVS.cs / FWLib/DetectEngine.cs 完全同一条路;源/目标都用 GCHandle 钉住 → 零额外拷贝。
    NodeFlow.Core 不引 SDK:Core 出 BayerConverter.HostConverter 钩子,AreaAI 在 NodeFlowHost 注册(与 HdrEngineBridge 同范式)。
  • 托管回退重写(仿真相机 / 无头测试 / SDK 失败 / 相机已断时用):改成按 2×2 块处理、图案偏移提成块内常量,
    去掉旧实现的逐像素 Math.Clamp 与 int[,] 取值;与旧实现逐字节一致(4 图案 × 1×1/2×2/3×3/5×4/8×8/7×3/16×9 逐字节比对用例)。
    顺带把 Mono8→BGR8 的循环收紧。
  • 实测(本机 2448×2048):旧逐像素 45.1ms/帧 → 新托管回退 12~15ms/帧(最快 11.5ms、≈68 帧/秒/线程,3.1×);
    真机走 SDK 那条路,双线性去马赛克顺带明显减少彩色锯齿/伪彩。
  • 先量数据:转换带节流计时日志(首 3 帧 + 之后每 100 帧一条)——
    [Bayer] 设备0 2448x2048 BayerRg8 → BGR8 12.3ms(MVS SDK,累计 12 帧 平均 12.5ms);
    新增离线自检 AreaAI.exe --bayer-bench [宽 高 图案 次数](默认 2448×2048 / 图案 0 / 20 次):
    同时给出托管回退与旧实现的 ms 与倍数,供决定"托管回退是否还需要多核并行"。

4.1.58(2026-10-01)

「参数设置」重新归类 + 深色底文字对比度修复 + 光源标定/融合算法改枚举下拉

① 「参数设置」系统参数重新归类:10 类 → 7 大类 + 序号固定顺序(同类按声明顺序排)

  • 新分类(分类名带序号,网格按名排序 = 顺序固定):
    1 采集与相机(5)、2 算法与测量(7)、3 存图与清理(8)、4 扫码与产品码(4)、
    5 显示与预览(16)、6 批次与数据库(5)、7 日志与诊断(8)。共 53 项(48 可见 + 5 隐藏),
    参数名/显示名/说明/默认值/持久化一律未动(data\Config.dat 结构不变)。
  • 修的四处不合理:参数 大杂烩(算法/采集/批处理混放)按语义拆进 1/2/6;测试参数 里塞的
    数据库→6、删图三项→3、模拟 NG→7;运行参数 只有日志 → 更名 7 日志与诊断;
    显示参数 过载 → 5 显示与预览;单属性分类(硬件参数/读码器参数)并入 1/4。
  • 同类属性按声明顺序排:参数设置 网格显式设 PropertySort.Categorized(原默认
    CategorizedAlphabetical 会把同类属性按中文显示名乱序),并把「图层存图(检测前)」提到存图类最前、
    「模拟 NG」排到日志类最后。
  • 筛选框口径不变(分类名不参与关键字匹配);5 个隐藏参数保持隐藏,只归类不显示。

② 深色底文字对比度修复(两处看不清)

  • 产品列表底部「复制产品时排除运行期图片(Images:抓图/检测存图,整目录照抄可取消勾选)」复选框
    漏设 Style/ForeColor → SunnyUI 按默认样式画成暗灰字,深色底上几乎看不清;现与同窗体其它控件一致
    (Style=Custom + 白字)。
  • 「参数设置」属性网格的说明栏/属性行原来用的是系统默认色(深色下说明栏是暗灰字):显式给网格一套深色
    高对比配色,说明栏 13.7:1、属性行 11.8:1(WCAG),分类标题纯白、选中蓝底、网格线/禁用色一并统一。

③ 光源标定 / 光源融合:算法改「枚举下拉」+ 修节点面板显示异常

  • 两个节点面板各加一行算法下拉:标定=单选(算法: 显示名 ▾)、融合=多选勾选
    (融合算法: N 个 ▾,弹窗含全选/全不选);属性面板的「算法 / 融合算法」同步改成下拉选择
    (只列已注册算法,防手输拼错;存储仍是算法键 / 逗号分隔 CSV,STN 格式不变,未注册的旧键会标注「(未注册)」)。
  • 修显示异常:节点被拉矮时「对比按钮会压到 输入/输出 端口行上」——加端口行兜底 + 多预留一行高度。
  • 修报错:点「标定对比… / 融合对比…」原来会弹
    「在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke」(构造期 ItemCheck 里 BeginInvoke),已修。

④ 逻辑图菜单补图标

  • 标题栏菜单:📂 打开、💾 保存、💾 另存为;标题栏与画布右键两处「📷 相机搜索…」
    (与同菜单 📡 TCP 通讯监视…、🔧 FVT 硬件搜索… 同款 emoji 前缀)。

4.1.57(2026-10-01)

「参数设置」新增筛选框;硬件初始化失败按账户分流(厂家账户不自动卸载产品)

  • 「参数设置」顶部新增筛选框:输入关键字后属性网格只显示命中的参数行(空格分词、全部关键字都要命中;
    匹配「显示名 + 属性名 + 说明」,忽略大小写),右侧显示 命中 m/N 项,无命中显示 0/N 项(无匹配);
    「✕」或 Esc 清空即恢复全部。分类名不参与匹配——输「存图」只会列出名字/说明里真带「存图」的行,
    不会把「3 存图与清理」整类都列出来。空筛选与旧版逐字一致(对象仍是同一份参数),编辑照旧写回参数、
    「保存」与 Config.dat 格式都没变;筛选词不写进配置。
  • 硬件初始化失败(hw.stn init 失败)后的收尾按账户分流:厂家账户(FVT)不再自动卸载产品——
    只做「启动键置灰 + 关闭已初始化硬件 + 停正在跑的产品流程」,产品保留在加载态,修好 init 分支后重新加载产品即可
    (不用先卸载产品);管理员/工程师/操作员照旧自动卸载产品,避免带着半初始化状态继续用。
    系统日志、命令式接口返回、产品列表加载失败提示都按账户给出对应文案。

4.1.56(2026-10-01)

标定支持 ChArUco 标定板 + 相机内参标定;新增光源标定 / 光源融合节点

  • 标定取点新增 ChArUco 标定板(标定窗「取点来源」= 板角点,默认):用板上两个内角点(默认 r0c0 原点、r0c1 方向)作为九点/圆心的取点来源,
    不再依赖算法层配「创建点」。板参数(方格数 X/Y、方格边长、marker 边长、字典)可配、可一键生成带 100mm 校验尺的标定板 PNG
    (按 100% 打印后用校验尺核对);奇数方格数的板与 OpenCV 默认板(11×8 → 20 个 marker、70 个内角点)一致。
  • 新增相机内参标定(标定窗「相机内参」页;节点按钮「📐 内参」直达):手动摆板逐张拍(≥8 张不同姿态,建议 12 张)→ 标定针孔 + 5 参畸变
    → 按「相机 + 分辨率」存档 data\calib\intrinsics\cam{设备}_{宽}x{高}.xml(覆盖自动留 .bak,支持导出/导入、从图片文件夹重标);
    显示重投影 RMS 与样本数(默认 RMS ≤0.5px、样本 ≥8 提示,超阈只提醒、不阻止保存)。
  • 采集端与运行端统一去畸变:标定采集点与运行期「偏置计算」读到的两个点按同一份内参去畸变
    (「畸变校正」= 自动/开/关,默认自动;缺内参时明确提示并按原始像素计算),避免两侧坐标系不一致带来的系统误差。
  • 可视化与追溯:预览图叠加检出 marker 编号与插值内角点,并高亮配置的原点/方向角点;标定图照旧存 data\calib\images\{标定名}\,
    标定 XML 记录内参引用(文件 / RMS / 样本数 / 时间)。
  • 新增 AreaAI.exe --charuco-selfcheck:离线自检整条标定链路(生成板图 → marker 检测 → 内角点插值 → 内参标定 → 去畸变往返),无需相机。
  • 新增节点:光源标定(/光机)与光源融合(/相机):读「光源示教(打光)」目录 → 插件化标定算法
    (球面-漫反射方向 / 球面-近场位置 / 镜面球高光…)算每路光源方向(可选位置/亮度)→ 存 data\lightcalib\{名}.xml 并写 lightcalib.* 变量;
    再按多算法融合出图、落盘并写回图像缓存;附算法对比窗体与 docs\光源标定与光源融合节点.md 使用说明。
  • 兼容:老标定文件(无板配置)按原「算法层命名点」取点,行为不变;算法层取点、模板设置、超限输出口、多套标定 XML 全部保留。
  • 全量 NodeFlow.Tests(693 用例)通过;dotnet build AreaAI.csproj 0 error;--charuco-selfcheck 通过。

4.1.55(2026-09-30)

重发补丁(内容与 4.1.54 一致,无功能改动)

  • 本版仅重新出包,内容同 4.1.54:循环日志采样(While/For)+ 重复日志窗口去重(界面与 logs\ 文件一起收敛)。
  • 现场若已升级到 4.1.54,无需再升本版。

4.1.54(2026-09-30)

循环日志采样(While/For)+ 重复日志窗口去重(界面与 logs\ 文件一起收敛)

  • 循环节点新增「循环日志」四档(While / For 属性面板):全部(默认,每轮都打)/ 仅第一次 / 每 N 次(N 可填,第 1 轮一定打印)/ 不打印;另加「退出汇总」(默认开)。
    被判定"本轮不打印"时,循环体内的节点日志(信息级)被静音——警告/错误照旧输出(不会把告警吞掉);
    循环退出时补一条汇总:循环「条件变量 x」共 N 轮,耗时 x s;循环体日志按「每 10 次」采样,已静音 M 条。
    嵌套循环外层覆盖内层(外层配"不打印",内层即使"全部"也安静);只统计、不改流程行为。
  • 重复日志窗口去重:同一「级别 + 正文」在窗口内(系统参数「日志去重窗口(ms)」,默认 2000,0=关闭)重复时只保留首条,
    并补一条 ↳ 上一条重复 N 次(已折叠,2s 内):正文…;界面与 logs\ 文件同时收敛(原先文件是逐条无条件写,循环刷屏会把文件灌爆)。
    交替出现的 A/B/A/B 也各自折叠(不要求连续);错误/异常不折叠(照旧逐条);被折叠的条目不再进日志窗内存缓冲。
  • 全量 NodeFlow.Tests(673 用例)通过;dotnet build AreaAI.csproj 0 error。

4.1.53(2026-09-30)

修「缺帧事件」永不触发:判定改产品级、从「该产品第一张图」起算(不再看「开始拍照」)+ 整批检测耗时日志

  • 现象:产线一直跑时,某产品缺张到超时也不报缺帧;空线(没放产品)时反而会周期性误报。
  • 原因:计时起点取的是「开始拍照」批次时刻,而批次时刻是按相机记的——只要持续有新批次(每个产品/每批都开拍照),
    上一产品的起点就被一直往后推,elapsed 永远小于超时 → 永不触发;判定对象里又含"已登记待拍但一帧未到"的产品,空线时会周期性判缺帧。
  • 修法(产品级口径):
    • 判定对象 = 该产品已出现至少一张图(跨相机累计入缓存帧数);一帧未到的一律不判 → 空线不再误报。
    • 计时起点 = 该产品第一张图采集(入缓存)时刻,与「开始拍照」彻底解耦(持续开拍照不影响判定)。
    • 产品总张数 = 参与相机拍照数之和(画布上的「图像缓存」节点),与主界面状态栏「已检测 xx/xx」分母同源;
      已到 = 跨相机累计采集帧数(不因某相机整批出队把帧移出缓存而回落)。
    • 到「缺帧超时(ms)」仍 已到 < 总张数 → 报警一次(同一产品只报一次,跨「图像处理」节点共享去重;新一轮后可再报)。
    • 告警文本:⚠ 缺帧:产品 7(SN)已到 5/8(缺 3 张),第一张帧后 5.2s(最后一张距今 1.1s);等待相机:1,3。
    • miss.* 载荷产品级化,新增 miss.waiting(等待相机,逗号分隔,与状态栏「等待相机」同源);
      miss.device = 首台未完成相机、miss.layers = 已到图层(跨相机去重)。
  • 新增:整批检测耗时日志(每个产品一条,走图像处理那套日志出口):
    产品 7(SN)整批检测完成:3.2s(首帧 12:00:01.123 → 最后一张检测完成 12:00:04.323),8/8 张。
  • 新增可测辅助 ImageCacheManager.DescribeProductRunTime;节点属性文案与 docs/全局变量与相关节点使用说明.md 同步。
  • 全量 NodeFlow.Tests(668 用例)通过;dotnet build AreaAI.csproj -c Debug 0 error。

4.1.50(2026-09-30)

修「缺帧事件」误报:没放产品(一帧都没到)也会隔一段时间报一次缺帧

  • 现象:线上一直没放产品、相机一张图都没出,缺帧事件/告警却每隔「缺帧超时」报一次。
  • 原因:判定对象里含"相机已登记待拍、但一帧都没到"的产品(筛选机行登记拍照元数据后一直挂着);
    计时起点又允许用「开始拍照」批次起点,于是"登记挂着 + 到点"就周期性判缺帧。
  • 修法(口径按现场要求收紧):只有"该产品已经出现过至少一张图"才纳入缺帧判定,
    计时起点 = 该产品第一张帧入队时刻(有「开始拍照」批次起点时取两者中较晚者,避免上一批遗留帧让新批次立刻被判缺帧);
    到「缺帧超时(ms)」仍凑不满「拍照数」才报一次。一帧都没到的产品一律不判(空线不再误报)。
    • 判定对象仍只算产品号 > 0 的帧;补满到「拍照数」后自动静默;同轮/同批次同产品只报一次。
    • 告警日志的计时说明同步改为「第一张帧后 Xs(最后一张距今 Ys)」;本批无新帧(沿用旧帧)时写「开始拍照后 Xs」。
    • miss.* 载荷不变(device/product/name/got/expected/missing/layers/last/time);miss.last 恒为最后一张帧时刻。
  • 「图像处理」节点属性「缺帧超时(ms)」与「缺帧事件」节点的画布级覆盖语义不变(0=关闭;默认 5000)。
  • 全量 NodeFlow.Tests(668 用例)通过;dotnet build AreaAI.csproj -c Debug 0 error。

4.1.52(2026-09-30)

全局 hw.stn 优先:程序级硬件入口(存在且启动 init 成功时,加载/切换产品不再动硬件)

  • 规则:exe 同级 stn\hw.stn 存在,且启动时它的 init 分支执行成功 → 它就是本程序唯一的硬件入口:
    • 加载/切换产品忽略产品目录的 hw.stn(不加载、不跑 init;产品目录里确实有 hw.stn 时日志给一条说明);
    • 卸载/切换产品不关闭硬件(硬件保持在线,不再每换一次产品就 reset 一遍);
    • 只有关闭软件时才执行全局 hw.stn 的无名 Start(关闭硬件)。
    • 全局 hw.stn 不存在、或存在但启动 init 失败 → 完全回退旧行为(产品目录 hw.stn:加载跑 init、卸载/退出跑 close)。
  • 影响面:产品目录里若同时还有 hw.stn,会被忽略(文件保留不删)。想回到"按产品初始化硬件",删掉/改名 exe 同级 stn\hw.stn 即可。
  • MCP/CLI 行为同步:load_product 忽略产品 hw.stn(日志「已存在全局 hw.stn:本次忽略产品 hw.stn」);
    unload_product 不关闭硬件;说明见 docs/AreaAI-MCP-CLI.md。
  • 改动在宿主侧(Form1 的硬件 stn 生命周期:init/close 的配对与跳过),dotnet build AreaAI.csproj -c Debug 0 error;
    NodeFlow 用例集不受影响(4.1.51 全量 668 PASS)。

4.1.51(2026-09-30)

点位「多张灯态 + 多张曝光/增益」:一个点位 T 张,逐张配 灯态(光源方案名)/ 曝光 / 增益

  • 新属性「多张灯态/曝光…」(「机械臂点位」节点属性面板,点击弹表格窗):行 = 该点位本件的第 1..T 张
    (T = 本件触发次数 × 一次触发帧数),每行填 灯态(下拉选 data\lightschemes.xml 里的方案名;「(全亮)」= 48 位全 1)+ 曝光(us) + 增益。
  • 光源轮询按张展开:按点位轮询时,配了逐张表的点位在这条链上占 T 格配方通道(板卡按相机曝光脉冲逐帧推进 → 一帧一个灯态);
    没配表的点位行为完全不变(仍是 1 格、按点位单灯态 灯态48)。
  • 相机轮询按张展开:相机轮询「轮询写入」时,该点位写 T 组曝光/增益给相机 Sequencer(逐帧切换)。
  • 灯态存方案名:方案改名自动跟随;方案被删/改名找不到 → 该张按 48 位全亮下发并告警(写明点位/第几张/方案名)。
  • 曝光/增益要么 T 张全填、要么都不填(部分填在编辑窗与运行时都中文报错并拒绝下发,避免 Sequencer 组数与实际帧数错位)。
  • 整表保留:T 调小时多余行不删(T 调回来仍在);旧画布没有该块 → 空表,行为与旧版逐字节一致(shots 独立块持久化,向后兼容)。

4.1.49(2026-09-30)

「变量变化事件」新增第三个输出端口「变值 ▶」:任意值变化(2→3 等)也触发事件

  • 原来只按"真假"判定(0/非 0、false/true),2→3、5→7、"RUN"→"STOP" 这类同侧/文本变化不产生事件;
    现在新增 「变值 ▶」 端口专门覆盖"任意值变化"。
  • 三个输出端口:变真 ▶(false→true / 0→非 0)、变假 ▶(true→false / 非 0→0)、变值 ▶(任意值变化,含上面两种)。
    0→5 会同时命中「变真」与「变值」→ 两条挂接分支都会跑(不是二选一)。
  • 端口名都可在节点属性里改(新增「变值端口名」),端口 Id 固定 → 改名不影响已有连线。
  • 载荷新增 var.rising(是否变真) var.falling(是否变假) var.changed(是否任意值变化) var.edge(变真/变假/变值);
    勾了节点属性「发布全局变量」时同步发布 g.var.*。
  • 判定口径:按值文本比较(与 var.value 一致)——2 与 "2"、1.0 与 1 视为同一个值(不触发);
    首次采值只记录不触发;变量被删除/不存在不触发;响应速度由「轮询间隔(ms)」(默认 100、下限 20)决定。
  • 全量 NodeFlow.Tests(661 用例)通过;dotnet build AreaAI.csproj -c Debug 0 error。

补记(此前已随包发布,此处补说明):产品管理「复制产品」改为整目录克隆

  • 旧实现只复制根文件(跳过 *.dat)+ Train 一个子目录 → 复制品会丢 Map(固定图)、PImages、现场样例目录等;
    重名只按大小写敏感比较(用大小写变体可绕过并覆盖原产品配置)、名字不校验、复制失败会留下"能被列出并加载"的半成品。
  • 现在:整目录递归复制(排除 *.legacy.bak/*.unreadable/*.recovered/*.tmp);名字做非法字符/路径/保留名/长度/
    大小写不敏感重名校验;复制走"暂存目录 → 整体改名落地",失败或取消自动回滚;进度框可取消,复制在后台线程执行(界面不卡)。
  • 新增开关:产品管理界面底部「复制产品时排除运行期图片(Images)」,默认勾选(不复制抓图/检测存图目录,省时省盘);
    取消勾选则连运行期图片一起克隆(Images = Projs\Tmp\{产品}\Images,也是"自动删图"的清扫目标)。
  • 自检:AreaAI.exe --product-copy-selfcheck(整目录克隆 / 名字校验 / 取消回滚 / 开关两态)。

4.1.48(2026-09-30)

修:同一引脚上「输出」节点的 PWM 与其它输出「打架」(PWM 停不掉,点开/关好像没反应)

  • 现象:A 节点(输出形式=PWM)启动后,另一个「输出」节点对同一根脚执行开/关/翻转/脉冲,引脚依旧是 PWM,电平写不进去。
  • 原因:PWM 的"已启动"原先只记在单个节点实例上,而它占用的是「运控卡 + cmpbuf 通道」这个物理引脚(比较输出 CMP07、通用输出 OUT07);别的节点写同一根脚时没人知道 PWM 还在跑。而固件软 PWM 是每 1ms 写一次该引脚,所以其它写法最多生效 1ms。
  • 修法(后写者赢):新增进程内「PWM 引脚占用登记」,按 (设备, 通道 0~15) 记账。任何「输出」节点写该引脚(开/关/翻转/脉冲,节点按钮或流程执行)之前,先停止并清空该通道的 PWM 配置再写电平;被接管的那一路节点按钮会自动回到「PWM启动」。启动 PWM 时若该引脚已被别的输出节点占用,会先替它停清再启动(接管),日志/节点提示里会写明接管来源。
  • 顺带修掉两个同源缺陷:
    • PWM 启动后改「编号」再停止,原先会去停新通道、旧通道永远停不掉;现在按启动时记录的通道停(流程停止 StopAllPwm 同理,节点删了也能停对通道)。
    • 被别人接管后,原节点的 PWM 按钮文案/状态不同步(一直显示「PWM停止」);现在按登记表判断,自动复位。
  • 范围:只收口在「输出」节点;筛选机、探针延时输出、固件与驱动层不改(按"物理上一个 IO 只有一个功能"的口径)。引脚无 PWM 占用时零额外指令。
  • 全量 NodeFlow.Tests(661 用例)通过;dotnet build AreaAI.csproj 0 error。

4.1.47(2026-09-30)

重发补丁(内容与 4.1.46 一致,无代码变更)

  • 本版仅重新出包,内容同 4.1.46:「软PWM输出」节点并入运控卡「输出」节点(新增第 5 种输出形式 PWM)、修 IO 节点「编号/名称不联动」。
  • 若现场已升级到 4.1.46,可不必再升本版。

4.1.46(2026-09-30)

软PWM并入运控卡「输出」节点(新增第 5 种输出形式 PWM);修 IO 节点「编号/名称不联动」

  • 删除「软PWM输出」节点,PWM 并入运控卡「输出」节点:「输出形式」由 4 种(脉冲/翻转/开/关)扩成 5 种(新增 PWM)。
    节点上原四个按钮之外新增一个满宽的「PWM」按钮(开关:未运行=「PWM启动」,运行中=「PWM停止」;停止即清空配置),
    不再有单独的「清空配置」按钮——切走 PWM(改成 脉冲/翻转/开/关)就自动停止并清空该通道配置,流程停止也会停止并清空全部已启动的 PWM。
    • 新增属性 「周期(ms)」(265535,默认 1000)与 「导通(ms)」(0周期,默认 500);仅在「输出形式=PWM」时可编辑(「值」「脉宽」仍只在「脉冲」时可编辑)。
    • 通道映射沿用旧软PWM:比较输出 = 编号(07)=CMP07、通用输出 = 8+编号 = OUT0~7;PWM 与比较输出共用同一 cmpbuf 引脚,同一通道不要同时用。
    • 需 FVT 运控卡固件 v2.4+;配置仅 RAM(板卡重启恢复默认);运行中每拍占用该引脚。状态块在 PWM 形式下改读 STS_PWM,显示 运行状态 / 周期 / 导通 / 占空 / 运行·电平位图。
    • PWM 只对运控卡开放:机械臂输出、相机 Line 输出的「输出形式」下拉不出现 PWM(仍是 4 项)。
    • 升级注意:旧画布上的「软PWM输出」节点会显示为**「缺失类型」占位**(不崩、不连线错位),请人工换成「输出」节点(输出形式=PWM)并重连。
  • 修「编号/名称不联动」:IO 节点里从「名称」下拉选中名称表里已有的名称时,编号会跟着切到该名称所在位置(输入 / 输出 / 边沿检测 / 点控制,机械臂与运控卡都生效);
    若是输入新名称,行为不变(只改当前编号槽位的名字,编号不动)。比较输出选 CMPn 仍是「切通道」语义。
  • 全量 NodeFlow.Tests(660 用例)通过;dotnet build AreaAI.csproj -c Debug 0 error。

4.1.45(2026-09-30)

边沿检测新增「脉冲长度」判定(达标 / 未达标 / 超时三分支);2D 相机帧改走「原始缓存」+ 新增「原始缓存」节点;显示字号按屏幕像素统一

  • 边沿检测(机械臂 / 运控卡)新增脉宽检测:勾选「启用脉宽检测」并设「脉宽阈值(ms)」(默认 2000)后,节点在等到所配边沿的基础上再判"电平是否连续保持到阈值"——
    保持满阈值 → 走新增的 「长度达标 ✓」;阈值内回落 → 走原 「检测到 ✓」(短脉冲 / 未达标);等不到边沿 → 「超时 ⏱」(不变)。
    「超时(ms)」只约束"等边沿"这一段,达标判定不受它限制;达标即刻返回、不等松开;回落即判未达标、不重计时(不做抖动容忍)。电平读取走共享快照,与边沿锁存同源(不额外读硬件)。
    • 「长度达标 ✓」端口只在勾选后才出现:stn 连线是按整张画布的端口序号存储的,恒定多一个端口会把其后所有节点的连线序号整体后移 →
      改成"启用才追加":老图(没有该属性 → 默认关 → 仍 2 个端口)端口表与旧版逐字节一致、连线不错位;运行期勾选/取消只增删这一个端口,
      不断开「检测到 ✓」/「超时 ⏱」已接的线。未勾选时行为与旧版完全一致。
  • 2D 相机帧改走「原始缓存」(不再走帧事件):抓图回调只把原始字节入队,由缓存自己的分发线程按容量丢最旧(计数告警)、按模式分发、按需做 BGR8 懒转换(多消费者共享一次转换)。
    free(连续预览)帧只发预览类消费者;触发模式的登记帧发全部消费者;订阅幂等,清空/断开即停止分发。相机预览、缓存浏览、标定、光源扫描的取帧都改接它。
  • 新增「原始缓存」节点(/相机):为某台相机设「容量(帧)」(默认 4)、「启用」(关 = 只计数不入队,排查用)、「逐帧明细日志」(每帧一行,查丢帧用,日志量大查完关掉),
    并实时显示入队 / 分发 / 丢弃统计。
  • 「缓存浏览」节点新增「缓存来源」:可选「登记缓存」(图像缓存队列,只含拍照点登记过的帧)或「原始缓存」(最近 N 帧,含 free / 未登记帧)——排查丢帧时能直接看到没登记的帧。
  • 「相机预览」新增"本次帧数"统计:开始预览即清零,配合原始缓存丢弃计数定位少帧 / 丢帧。
  • 参数写入策略「可流式写入」(Streamable):能在采集态写的相机参数直接写、不停采;否则按原逻辑停采重写(线扫 / 连续采集少一次打断)。
  • 一次触发多帧的采集模式口径:机型没有 MultiFrame 时用 Continuous(不再直接判为不支持)。
  • 节点 / 流程日志按内容分级:节点日志走统一出口,「警告:/ 告警:/ 警示:/ 注意:」开头的按警告级(日志窗警告色、日志文件 WARN),其余按信息级——
    以前节点的告警混在信息里看不出来;Graph 与主程序的各条 LogSink 全部接过来。
  • 显示字号口径统一(修"图大字小、图小字大"):检测信息文字、尺寸标注、框内图层名等改为按屏幕像素换算(配置 ≤0 时用默认 12 像素),
    任何图像 / 窗口尺寸下视觉大小一致;不再把默认值写回全局配置(避免绘制期污染配置);显示参数字段补上"单位 / 0 的语义"说明。
  • 回归:NodeFlow.Tests 657 PASS / 0 FAIL(新增用例:脉宽达标 / 未达标 / 超时三分支与端口表兼容、原始缓存入队分发 / 丢最旧 / 懒转换 / 两种模式路由、
    缓存浏览、Streamable 参数写入、一次触发多帧口径、节点日志级别判定);dotnet build AreaAI.csproj -c Release 0 错误。

4.1.44(2026-09-30)

折叠组「展开编辑」不再多出「分组出口」节点(标记改为"穿透",不落画布)

  • 现象:折叠组只要在「✏ 编辑分组(新窗口)」里保存过一次,之后「展开编辑」画布上就会多出一个
    「分组出口」节点(多出口组会多出多个)。
  • 根因:打开分组编辑窗时会为组内每个 exec 出口自动补一个「分组出口」标记节点(它承载"出口端口名/顺序",
    并随组一起写回持久化);展开时它被当作普通内部节点还原到画布 → 每次展开都会多出它。
  • 改后:展开时把这类标记穿透——不落到画布,组外那条出线直接接到标记上游的内部节点
    (标记是纯穿透 In→Out,语义等价);找不到上游的标记(组内末端被删/从未接线)按原样保留,不阻断展开。
  • 兼容:组内数据格式、端口名与端口顺序、"折叠组运行期建图 / 单步整组"都不变;旧 .stn、旧组、多出口组照常。
  • 回归:新增用例「折叠组 展开不落「分组出口」标记(展开后节点数不多出)」;
    NodeFlow.Tests 637 PASS / 0 FAIL;AreaAI.csproj -c Release 0 错误。

4.1.43(2026-09-29)

机械臂拍照:点位连拍(触发一次拍多张 / 多次触发)+ 静止点稳定脉冲 + MOVS 段合法化

  • 点位连拍(在「机械臂点位」节点的点位属性里,与灯态/增益/曝光同一处):新增「本件触发次数 K」「一次触发帧数 N」
    「连拍用途(合成/独立检测)」「多帧来源(相机突发/多次触发)」。本件总张数 T = K × N,图层名自动变
    点名_1..点名_T;T=1 时保持原名不加后缀(老图零变化)。
    • 合成=这些帧是合成算法的源帧,最终只检测基名层 点名(HDR 链路天然支持:源帧入队即被占用、不进「图像处理」);
      独立检测=没有合成算法,点名_1..点名_T 各自是检测层,各自配算法/ROI。
    • 相机突发=一次触发直接出 N 帧(软件下发 AcquisitionMode=MultiFrame + TriggerSelector=FrameBurstStart +
      AcquisitionBurstFrameCount=N 并回读校验,相机不支持会明确报错);多次触发(默认)=相机一次触发一帧、
      流程触发 K×N 次(可配「相机轮询」写 N 组曝光/增益=Sequencer,做一次触发多曝光的 HDR)。
    • 软件按"本次触发将产生的帧数"登记元数据 → 「一次触发出 N 帧」与「触发 N 次各出 1 帧」产出的层名序列完全一致。
    • 打开产品时图层自动按点位声明建好(合成只建基名层 / 独立检测建 _1..T);「每产品拍照数」自动模式同样按点位声明计
      (合成计 1、独立检测计 T)。同一点位被多个节点引用只算一条声明(不再相加),彻底消除"以哪个节点为准"的歧义。
    • 一致性校验(不一致直接报错):合成必须有「HDR合成」且其「每层张数」== T;该相机有「HDR合成」时不允许"独立检测"
      的连拍点位(HDR 预标记按设备全局生效,_k 帧会被当源帧吞掉);同一台相机上多个"相机突发"点位的 N 必须相同
      (AcquisitionBurstFrameCount 是相机级参数);同一画布生成图层时汇总报错并跳过问题点位。
  • 静止拍照点支持 V2 时间距离补偿:静止点可选「触发方式=时间距离」,默认到位后 +0µs 触发 / +2000µs 复位(恒 2ms 脉冲、
    与速度无关)——解决"99.5%→100% 靠得很近时脉宽只有几十~几百 µs、相机丢触发"的老问题;老图(静止=百分比 99.5/100)不变。
  • MOVS 段点数合法化:修掉"段内点数不足 3 时复制末点凑数"造成的零长度样条段(17/33 个飞拍点、批次首个飞拍点、
    被过渡点切开的单点段等场景);改为"折叠相邻重合点 + 用有位移的微窗口点(预备/后随)补足",并保证段内真实拍照点全部是
    辅助点(必经、触发可靠)+ 段末一个合成非拍照目标点;下发前统一校验(点数 3~50、相邻不重合),退化段拒绝下发并给中文原因。
  • 机械臂工具箱按链路分目录:机械臂 ▸ 轨迹V1(开始拍照V1 / 拍照点V1 / 过渡点V1 / 开始运动V1 / 停止拍照V1)与
    机械臂 ▸ 轨迹V2(拍照点V2 / 过渡点V2(新增) / 检查点V2 / 事件V2 / 轨迹执行V2);专有节点标题带 V1/V2、底色区分,
    公用硬件节点目录不动。老图打开自动落到新目录(类型名不变、标题不落盘)。
  • 新增文档 docs/机械臂检查点V2使用说明.md:检查点用法、拍照脉冲怎么发才稳(百分比 vs 时间距离、错误码对照)、
    连拍与图层后缀(K/N/用途/来源、每产品拍照数口径、五类校验、改名同步)。

其它改动

  • 轴等待改为异步(节点层"下发不等待 + 异步等"):等待期间界面不卡(宿主等待、单步调试),点「停止」能立刻结束等待;
    卡内同步等待保留给标定/筛选机等既有调用。
  • 单步执行补上全局变量预载;设计期预载只执行「本分支」的变量设置,不再把全局变量表改写一遍(修"单步一次就把 g.x 重置"的老问题)。
  • 切换产品 / 卸载产品改为后台执行:界面不卡,状态栏 + 进度条提示。

4.1.42(2026-09-29)

缺帧报警改为「从开始拍照开始计时」,并在「缺帧事件」节点上加了时间设置

  • 计时口径:以前是"某产品最后一张帧到达后超过超时才报"(相机停了才报、批次整体太慢不报);
    现在改为从「开始拍照」开始计时(「开始拍照」/「开始拍照V1」/「机械臂轨迹执行V2」的批次起点都算),
    批次内超过设定时间仍未凑满「拍照数」的产品立即判缺帧。没有「开始拍照」的链路(筛选机/手工拍照)
    仍按旧口径(最后一张帧之后)判,不受影响。
  • 超时可配在「缺帧事件」节点上:新增属性「缺帧超时(ms)」= 画布级设置,填 >0(如整批节拍 3s 就填 6000)
    则本画布所有「图像处理」节点都按它判超时;留 0(默认)= 沿用「图像处理」节点上的「缺帧超时(ms)」(旧图行为不变)。
  • 补上真正的漏报:一帧都没到的产品现在也会报。判定产品集合改为"缓存里已有的产品 ∪ 相机已登记待拍的产品"
    (拍照点/比较下发登记过元数据),所以"这批该拍这台相机却一张都没到"同样在到点后报警:
    ⚠ 缺帧:产品 9 已到 0/3(缺 3 张),开始拍照后 6.2s(一帧未到)…登记未到:p91、p92。
  • 日志更好判因:告警写成 开始拍照后 6.2s(最后一张距今 0.3s)——一眼区分"批次整体超时"与"相机停了"。
  • 同批次同产品只报一次;再次「开始拍照」(新批次)后计时重新开始、允许再报;「图像缓存」清缓存(新一轮)时,
    若本批已跑过「开始拍照」,计时也从清缓存那一刻重新起算(与流程先后顺序无关)。
  • 只告警:不动缓存、不改产品流转、不自动判 NG。用法与调参见 docs/全局变量与相关节点使用说明.md §7.8。
  • 现场调参提醒:整批节拍超过 5s 的飞拍链路,请把「缺帧事件」节点的「缺帧超时(ms)」按整批时长调大(如 6000~8000),
    避免批次还在正常跑就报缺帧。

4.1.41(2026-09-29)

FVT 运控卡「停止轴」不再顺手把伺服下电(停止 product.stn 后机器掉使能)

  • 现象:点「停止」停止 product.stn,没有下电指令,但卡上映射的电机使能输出(如 OUT7)被拉低、轴掉使能;
    系统日志里对应那条是 [电平] 通道N(OUTx) 高→低(复位)(无上位机写 → 板卡侧/外部写入…电机使能 motor_en…)
    —— 因为电平是板卡自己按急停语义拉的,不是上位机写的 OUT。
  • 根因:停止流程逐轴调「停止轴」,而 FVT 侧旧实现(非点动中)用
    JOG STOP + 全局急停(0x01) + 解除急停(0x02) 凑"单轴停止";固件 v2.5.1 起急停会
    强制断开全部已映射的电机使能输出(伺服下电),并且解除急停不自动复电 —— 于是"停止"变成了"下电"。
  • 修法:改用固件自 v1.0.5 就有的 0x0E「立即停止运动」(axis_mask):停脉冲 / 清运动队列 / 退出回零与点动,
    轴状态回 IDLE(限位/急停封锁态保留、可继续操作),不动急停、不动使能输出。
    单轴停止 / 全部轴停止 / 回零中停止 / JOG 面板「停止」/ 停止 product.stn 全部生效;
    真正的急停(硬件安全输入、急停事件)语义不变,仍然会下电。停止命令下发失败会记日志并报错,不再退回"急停凑停止"。
  • 固件不用升级:0x0E 在任何在用固件版本里都有。

4.1.40(2026-09-29)

① 产品缺帧检测(图像处理内置告警 + 新「缺帧事件」节点)

  • 某产品最后一张帧到达后超时(「图像处理」节点新增属性「缺帧超时(ms)」,默认 5000,0=关闭)仍未凑满
    「拍照数」→ 判缺帧:系统日志 ⚠ 缺帧:产品 13 已到 10/13(缺 3 张)…、节点状态行、miss.* 运行变量,
    并 raise 一条总线事件;画布上用新节点**「缺帧事件」**(/事件,无输入起点,输出「缺帧 ▶」)挂分支去报警/停线/写日志,
    勾「发布全局变量」可写 g.miss.*。同轮同产品只报一次,新一轮(缓存节点清队)后可再报。
  • 缺的图层名从相机「待消费拍照元数据」快照取(新增可选接口 IShotMetaPeek,仿真/海康相机已实现)。
  • 「图像缓存」清缓存前的"丢弃未处理帧"告警改为按产品列明细(产品 13 已到 10/13(缺 3 张))——轮次边界判定天然准确。
  • 只告警:不动缓存、不改产品流转、不自动判 NG。

② 「光源示教」节点新增「打光」按钮:按勾选方案一键轮询 + 逐方案触发拍照存档

  • 点方案行右侧「打光」:把 lightschemes.xml 里勾选了「参与打光」的方案按顺序写进光机配方通道 0..n-1 并 LX n
    (固件按相机曝光信号下降沿自动切下一个配方),再脉冲机械臂触发 DO n 次——1 个脉冲 = 1 帧图 = 1 个方案;
    全程关相机轮询(Sequencer)并强制相机「一次触发帧数」= 1(防上一个连拍点位留下的突发让一轮图错乱;
    结束后恢复原值),再切触发采集。
  • 方案勾选(「光源方案编辑…」对话框):方案列表每行左侧有勾选框,只勾选的参与打光;方案名输入框下方新增
    筛选框(按方案名包含匹配)与全选 / 全不选(只作用于当前筛选可见行),并显示一行 参与打光:m/n;
    勾选变化即时写盘(lightschemes.xml 里每个方案多一个 <Sweep> 元素,老文件没有该元素 → 全部视为勾选)。
    勾选只影响打光:节点「方案」下拉、点位灯态解析仍用全部方案。
  • 图片落在 <打光保存路径>\<点位名>_曝光<曝光>_增益<增益>_光圈<光圈>_视野<视野>_焦距<焦距>\(默认 data\lighttest),
    文件名 序号_方案名.bmp(序号按本次参与的方案从 01 重排;重名自动 _2,非法字符替换);
    曝光/增益取现有点位已示教值(缺则相机当前值 → 画布「相机连接」默认 → 100us/1.0,按范围钳制);
    镜头三个值由光机直接读回舵机实际位置换算成百分比(一位小数),读不到(老固件没有 LR,DJS 读位置指令 /
    舵机不应答)那一轴写 - 并记一条告警 —— 不阻断打光。
  • 结束后恢复光机与相机原设置(通道0=当前灯态 + LX 1 + 当前 DAC;相机一次触发帧数 / 轮询开关 / 曝光增益 / 采集模式)。
  • 目标来源:新增属性「机械臂设备」「触发DO」(留空按画布上引用该点位的拍照点自动推导),相机按 臂+DO 查「输出相机表」。

③ 「机械臂结束」的伺服下电异常改为红色(错误级日志)

  • 下使能异常(忽略):伺服下电 失败 ret=2182578185 当前用户未获取到控制权 原来按信息级(绿色)显示,
    现改为节点错误级日志:主程序日志框红色并写入错误日志;子流程/事件分支/停止分支/主运行同口径。

④ 拖节点到折叠分组上 → 自动并入组内执行链尾

  • 把画布节点拖到折叠组上即并入(接在组内最后一个真实节点后面并从画布移除);有连线/锁定组/嵌套组/无执行输入会拒绝并给中文原因,
    接线中途失败自动回滚(画布与组数据保持原样)。

⑤ 静止拍照点 V2 时间补偿(0x51010)

  • 「拍照点V2·静止」+ 触发方式=时间距离:按 MovJ/MovL(blend=0)入队并走 V2,默认到位后 +0µs 触发 / +2000µs 复位
    =恒 2ms 脉冲(与速度/段长无关)——解决「99.5%→100% 靠得很近时脉宽只有几十~几百 µs、相机丢触发」;
    飞拍仍为点前 1ms 触发 / 点后 1ms 复位;静止+百分比仍走 V1(老图行为不变)。

⑥ 点位面板:行高决定可见行数

  • 拉高面板多显示行(行高不变,40 行封顶),不再固定行数。

4.1.39(2026-09-29)

折叠组「展开编辑」改为「以组当前位置为中心」展开(与子 stn 展开统一口径)

  • 现象:右键折叠组 →「展开编辑」,展开出来的节点经常不在组的位置(被甩到画布别处甚至画布外),
    用户得滚动/缩放满画布去找;这与「子 stn → 📤 展开回当前画布」(以被展开节点为中心)不一致。
  • 根因:折叠组展开原来按「组当前位置 − 折叠时锚点」把内部节点整体平移。这条规则要求
    "内部节点坐标与折叠那一刻完全一致",实际经常不成立:
    ① 在「✏ 编辑分组(新窗口)」里加过/挪过节点(坐标来自另一块画布);
    ② 组被复制粘贴、或跨画布/跨产品搬过来;③ 旧版本保存的组(没有锚点块)。
    这些情况按锚点平移就会把展开内容甩到组外面。
  • 改后:展开时恢复节点的外接矩形中心对齐到组节点当前位置(相对布局原样保留)——
    组拖到哪、展开就在哪;与子 stn 展开行为完全一致。
  • 兼容:GroupStNode 的锚点字段照旧读写(.stn 文件格式未变),只是不再参与定位;旧文件打开/保存不受影响。
  • 回归:折叠组 移动/复制后展开位置 按新口径重写(断言「展开内容中心 == 组/副本中心」+「log→end 相对位置不变」);
    NodeFlow.Tests 599 PASS / 0 FAIL;AreaAI.csproj -c Release 0 错误。

4.1.38(2026-09-28)

修「折叠组里的参数改了,运行还是旧参数」(筛选机 / 相机等)

  • 现象:在「✏ 编辑分组(新窗口)」里把折叠组内节点的参数改好、点分组编辑窗「保存」,
    编辑器里看是新值,但发到板卡 / 相机的还是改动前的值。
  • 根因:「分组编辑」窗的「保存」只把改动写回内存里的分组节点(SaveGroupEdit 不写 .stn);
    而运行期 hw.stn 的 init / 无名 close 分支与产品加载都是按磁盘文件建图
    (NodeFlowRunner.Load(path) 不带编辑器;product.stn 仅当对应逻辑图窗口开着时才复用内存画布)。
  • 修复:① 分组编辑「保存」联动把源逻辑图落盘(复用正常保存流程,提示写明是否已落盘);
    ② 新增运行前未保存守卫——运行将按文件建图而对应逻辑图有未保存改动时弹窗
    (是=先保存再运行;否=按磁盘旧文件继续并告警;取消=不运行),覆盖 hw 初始化、hw 关闭分支、
    产品 hw 初始化、产品运行。
  • 影响面:hw.stn 内的全部节点参数都属这一类(相机曝光/增益/触发模式、运控卡、光源、
    筛选机比较表/16 通道、IO/急停、云台、机械臂、点位/FIFO 绑定等);折叠组只是让这个坑更隐蔽。
    现在「运行时磁盘所见 = 编辑器所见」。

新增:用户变量 g.user*(值 + 最小/最大值)集中维护 + 按产品持久化

  • 主窗菜单「用户变量(g.user)…」打开集中维护窗口:数值超限自动夹紧、流程写入非数字时拒绝写入并告警。
  • 配置存 {产品目录}\user-global-vars.json:加载产品时装范围 + 写值,卸载产品时清理(其它 g.* 键不受影响)。
  • 说明见 docs/全局变量与相关节点使用说明.md、docs/全局变量写入与读取节点使用说明.md。

回归:NodeFlow 无头用例 599 PASS / 0 FAIL(含新增「分组编辑 写回+保存后落盘:属性参数与自定义键都保留」)。

4.1.37(2026-09-28)

加壳启用 JIT 加密(jit_encrypt=1)—— Virbox Protector 3.6.1 已支持 .NET 10

  • 加壳配置确认为最强加密组合:zip=1 + jit_encrypt=1 + anti_debugging=1(+ SenseShield 授权容器 slm_runtime)。
  • 回归验证(直接对加壳后的 AreaAI.dll 实跑,非源码版):
    --version → FVision-AI 4.1.37(exit 0);--graph-selfcheck → 已注册节点类型 151、结果 OK(exit 0);
    --persist-selfcheck → 全部通过(exit 0)。
  • 背景:早期 Virbox(3.3.x)的 jit_encrypt(JIT 加密)与 .NET 9/10 运行时不兼容,加壳虽报 Succeed 但产物启动即崩
    (Fatal error. Internal CLR error. (0x80131506) / 0xC0000005);升级到 3.6.1 后已兼容,本版起恢复 JIT 加密。

4.1.36(2026-09-28)

检测模板:Alt+6 快捷打开 + 没有算法的图层自动补「无定位AI检测」

  • Alt+6 打开检测模板:此前已有 Form1.OpenDetectTemplateFromHotkey 但从未接到热键(GraphHotkeys 只处理 Alt+1~5)。
    现已接通——按 Alt+6(主键盘/小键盘)打开当前产品的检测模板(算法参数设置窗);
    权限沿用「检测模板」闸门:厂家 FVT / 管理员 / 工程师可开,操作员拒绝;未加载产品或无权限只记系统日志、不弹窗打断。
  • 打开检测模板时:凡是没有算法的图层都自动补一个 AnomalyDetectNoPos(无定位AI检测),
    与其它图层是否已有算法无关;已有算法的图层保持原样。权限沿用右键「添加 → 无定位AI检测」闸门(g_acess[2] 含 1),补完落盘。

图像处理节点:运行期空图层也自动补「无定位AI检测」

  • 「图像处理」节点执行时:图层缺失照旧自动补图层(节点的「自动补」AutoEnsureLayers,默认开);
    新增——图层存在但一个算法都没有时,自动补一个无定位AI检测(命名 无定位AI检测{图层名})并保存;
    多相机图像处理线程并发时加锁双检,避免重复添加。
  • 行为变化:以前空图层会走 RunWindow 的 !ct.Any() 分支直接判 OK(静默放行);现在会带上默认算法参与检测。
    注意:自动补的算法默认未关联模型,本身暂时检不出东西(结果仍是 OK),需到检测模板里关联模型 / 画 ROI 后生效。
  • 关闭节点的「自动补」开关即回到严格模式(既不自动补图层,也不自动补算法)。

4.1.35(2026-09-28)

修「存图产品名没了年月日」:无 SN 恢复自动编号 P_年月日时分秒_号(号固定 5 位,1 → 00001)

  • 问题:4.1.29 起「图像处理」节点把产品号顶替成产品名传给桥,导致桥上"有 SN"分支永远命中 ——
    没扫码时存图目录退化成纯产品号(例:…\9_28\1\1_图层_时分秒毫秒_序号.jpg),
    而 4.1.28 及以前的自动编号 P_年月日时分秒_产品号 成了死代码;既没 SN 又没产品号时连产品目录都不建(文件名只剩时间戳)。
  • 改后口径(= 产品目录名 / 同名 XML 的 ProductName / 状态栏显示,三处一致):
    · 有 SN(手动扫码 / 算法识别)→ 纯 SN(1、SN123456;同 SN 的件并入同一目录)—— 不变;
    · 无 SN、有产品号 → P_{年月日时分秒}_{号},号固定 5 位补零(产品号 1 → P_20260928153012_00001);
    · 无 SN、也无产品号 → P_{年月日时分秒}_{自动序号}(同样 5 位;按「轮次」盖章,同一轮的无号帧共用一个编号,新一轮重新编号)。
    时间戳恒为 14 位,便于按名排序与解析(HistoryStats 的图层名剥离逻辑已兼容)。
  • 新增无界面自检:AreaAI.exe --naming-selfcheck(三种命名 + 位数约定,打印示例名字,退出码 0=通过)。
  • 名称带 P_ 的产品目录其文件名同样带该前缀(P_20260928153012_00007_图层_时分秒毫秒_序号.jpg),
    图层目录 / 判级 OK|NG|Fail 仍是硬链接,删图/保留天数/批量烧录规则不变。

另修:批量结果烧录界面「点不动」|状态栏「理论产能」颜色与旁边不一致

  • 批量结果烧录界面之前根本没法用:BurnInForm 里「源日期目录 / 到 / 档位 / 过滤」四个下拉框
    只 new 了、从没 Controls.Add(...) 加进窗体 —— 界面上看不到任何下拉框、档位与日期范围都选不了,
    于是"要么没有可烧录目录、要么点了没反应"。现已补齐并显式配色(黑底下不会再与背景同色而看不见)。
  • 界面同时改成可自查、可自救:
    · 顶部显示实际「存图根目录」,配「浏览…」手动指定(本次运行内记住)+「自动探测」清除手选;
    自动探测按 当前产品存图目录 → {存图目录}\\{产品} → Projs\\Tmp\\{产品}\\Images / {产品} 找第一个含日期目录的;
    · 日期目录改成列表勾选(多选、全选/全不选、双击切换,直接显示每个目录的源图数与输出目录);
    · 没有可烧录内容时状态栏写明原因(未加载产品 / 目录不存在 / 目录下没有 {月}_{日} 形式的文件夹);
    · 新增「打开输出目录」;烧录中禁用全部输入,结束后按勾选数恢复按钮。
    (顺带修:Sunny.UIForm 顶部有约 35px 自绘标题栏,控件 Y 小于该值会被压住/重叠 —— 布局已下移。)
  • 状态栏「理论产能」改绿:该标签从未设过颜色,被 UI.SetUI(statusStrip1, UIStyle.Black) 刷成主题白,
    与旁边显式 LimeGreen 的「登录 / 料号清零」不一致;现统一(含「产品号·已检测」「TCP 状态占位」)。

回归:NodeFlow.Tests 全量 593 PASS / 0 FAIL;AreaAI.csproj -c Release 0 错误。

4.1.34(2026-09-28)

修「打开/单步就闪退」:建图 ↔ 组内节点还原 ↔ 点位回调 无限递归(StackOverflow)|标签框颜色丢失

  • 栈闪退根因(现场 VS 调用栈实测):打开逻辑图时
    重建设计期上下文 → GraphBuilder.Build → 设备名解析 → GlobalStnState.CaptureFrom → 还原折叠组内部节点 → 节点属性 setter(输入点位变量)→ 点位载入 → 宿主重建设计期上下文 → … 无限递归 →
    StackOverflowException(无法 catch,进程直接退出;现场就是"一打开/单步就闪退,什么提示都没有")。
  • 修法(两层防):① 「为登记信息而临时还原组内节点」整段进入抑制节点副作用区间,期间点位载入
    不再回调宿主;② 设计期上下文重建加防重入(构建中再进入只返回轻量上下文,不递归、也不覆盖外层结果)。
  • 另修:标签模式下标签框颜色丢失(System.Drawing.Color 字段全为 readonly,字段级深拷贝/JSON 往返
    退化成 Color.Empty)——标签模式下 alt+左键克隆出来的标签框现在颜色正常。
  • 回归:NodeFlow.Tests 新增「点位捕获 还原组内节点不回调宿主(防栈溢出递归)」用例,581 PASS / 0 FAIL。

4.1.33(2026-09-28)

日志不再被死循环刷屏(连续重复自动折叠)|图像处理「停止后还在拍/存图」修复

  • 连续重复日志自动折叠:日志框把「正文 + 级别相同」的连续日志合并成一行,并在其后给出
    ↳ 上一行重复 N 次(已折叠)(每条时间戳不同也照样折叠)。死循环里 run 反复写 1/0
    这种现场表现,从"每秒上百行"变成几行;筛选/重放同样折叠,日志筛选与「显示 N / 缓存 M 条」口径不变。
  • 「变量设置」节点只在值变化时记日志:变量本身仍然每次都写,只是不再重复刷同一行
    (While 循环里反复写同一个值不再刷屏)。
  • 修「图像处理」停止后仍在检测/存图:持续消费(填了「开始启动变量」)以前有意忽略流程取消,
    所以点停止(或流程内节点故障)后取流消失、后台仍在逐帧消费缓存 → 每帧检测一次、每次都存图。
    现在「图像处理」节点新增属性**「流程停止时自动停止」(默认勾选)**:流程停止/取消即停掉持续消费;
    取消勾选 = 旧行为(一直消费到点节点上的停止)。另加了新旧任务交接保护(上一轮退出未完成时先等收尾再启动)。

4.1.32(2026-09-28)

主界面日志可筛选(级别+关键字)|节点树新增「示教」分组|STN 子流程防环(修"一运行就闪退")

  • 日志筛选:「日志」Tab 顶部新增筛选栏——4 个级别复选框(信息 / 警告 / 错误 / 异常)+ 关键字输入框
    (多个词用空格分隔=都要包含)+「清空」+「显示 N / 缓存 M 条」。内存保留最近 5000 条,切换筛选会重放,
    被筛掉的历史取消筛选后仍能看到;筛选项写入 Config.dat,重启保留;系统参数里的「显示所有Log信息」
    就是「信息」级别开关,与筛选栏双向同步。只影响界面显示,logs\ 下文件日志仍按原规则全量记录。
    · 顺带修掉一个升级后遗症:旧二进制配置里没有这几个新开关,载入时会落成 false(现场表现"升级后日志一片空白"),
    现在会自动补回默认值(警告/错误/异常显示,信息沿用原设置)。
  • 节点树新增「示教」分组:左侧节点树顶层多出一个「示教」,平铺
    机械臂示教 / 运控卡示教 / 光源示教 / 镜头示教 / 云台示教 + 机械臂点位 / 运控卡点位 / 光机点位 / 云台点位。
    原分类(/机械臂、/运控卡、/光机、/云台)里的条目与顺序完全不变(同一节点出现两次,只是多了个快捷入口)。
  • 修闪退:STN 子流程循环引用:子流程是在当前调用栈上嵌套执行的,以前 A→B→A(或子流程调回自己/调回主图)
    会无限递归 → StackOverflowException(不可捕获,进程直接消失;现场表现为"一运行就闪退",不弹任何提示)。
    现在进入子流程前先查调用链:命中环、或嵌套超过 32 层 → 报明确中文错误(带出 A.stn → B.stn → A.stn 调用链)
    并让本次运行失败,不再崩进程。
  • 未处理异常落盘:运行期未处理异常(UI/非 UI 线程)现在一律写 logs\crash_<时间>.txt
    (含程序版本与完整堆栈)并记一条 log4net Fatal —— 旧实现只在启动阶段留痕,运行期闪退查不到任何信息。

4.1.31(2026-09-27)

机械臂 3D 浏览窗「贴附到节点」:3D 直接长在节点里,跟着画布移动/缩放(30ms 跟手)

  • 不再"左键点一下画布就掉到 Graph 后面":3D 窗改为画布所在窗体的子窗(Owner)——只压逻辑图、不抢其它程序的前台,
    无边框、不进任务栏。
  • 位置与大小实时对齐节点的「3D 预览区」(独立 30ms 同步器,只在存在 3D 窗时运行,无 3D 时零开销):
    拖节点 / 平移画布 / 滚轮缩放画布,3D 与节点同框移动与缩放;窗口矩形取与画布客户区的交集(任一边 <40px 即隐藏),
    节点拖出可视区自动隐藏、拖回自动出现;节点被删或画布关窗 → 3D 窗自动关闭注销,不留残窗。
  • 节点改版:标题栏 → 3D 预览区 → 按钮行 → 两行状态(J: 关节角 / 模型: 真实还是内置);
    按钮行 = 「⚙ 打开3D / ✕ 关闭3D」(按状态切换)·「读实时位姿」·「重绘轨迹」·「复位视角」·「重载模型」。
    节点右下角新增拖拽手柄:自由改宽高(不锁比例,最小 360×300,预览区保证 ≥200×140),3D 随节点一起变大变小。
  • 交互与「相机预览节点」一致:3D 上滚轮=缩放模型、左键拖动=旋转视角、右键拖动=平移。
  • 新属性「贴附到节点」(默认开):关掉即回到原来的独立浮动窗(可自由拖动,方便现场单独看这台臂)。
  • 覆盖区域不响应画布鼠标(点它就是操作 3D)——要拖动这个节点请抓标题栏;快速平移画布时可能有十几~几十毫秒拖影。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.5.3、FVT智能光机 v1.0.3、FVT云台 firmware_v1.4.11.fvt + ESP32_GENERIC_YTEx_v28.bin。

4.1.30(2026-09-27)

机械臂 3D 浏览:入库 HAR7-910 真实模型包(六个连杆 STL + 关节轴),打开 3D 即按真机外观跟随关节动

  • 真实模型已随包:厂家官方整机模型(HAR7-910.x_t/.stp/.igs)导出为 data\model\HAR7-910\A1..A6.stl
    (六连杆、装配坐标、mm,约 9.9 MB / 20.7 万三角形)+ har7-910.model.json(连杆↔关节映射、关节轴、坐标系对齐),
    安装包与轻量补丁都带(本版补丁 16.7 MB,其中模型 ~9.9 MB)。
    现场无需任何 CAD:拿到补丁即显示真机外观;换臂型/换版本只替换该目录里的模型包即可(节点上点「重载模型」生效)。
  • 只驱动 J1..J5:厂家给的 6 个连杆只能解出 5 根关节轴(J6 是 A6 内部法兰自转,视觉上不明显)——
    J1 竖直、J2/J3/J5 侧向、J4 沿小臂,读实时位姿时按真机角度摆位。
  • 关节轴是拟合值:由"接口处顶点圆拟合"得到(J2 残差偏大,位置可能差几十毫米)。现场若发现某关节动作时连杆错位,
    直接改 har7-910.model.json 的 axes[].point/dir,或对应 link 的 sign(方向反)/offsetDeg(零位偏),
    点「重载模型」即生效,不用发版(步骤见同目录 如何重新导出.txt)。
  • 附带:提取工具新增 importx(整机中性文件 → 逐连杆网格 + 关节轴)与 axisfit(纯数学反算关节轴),
    LoadFile4 导入整机 .x_t(厂家 .SLDASM 被更新版 SW 另存过、旧版打不开)见 tools\ArmModelExport。
  • 另含并行开发线的同期改动(4.1.29 起的存图收敛/SN 命名/相机输出节点等),随包生效。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.5.3、FVT智能光机 v1.0.2、
    FVT云台 firmware_v1.4.11.fvt + ESP32_GENERIC_YTEx_v28.bin。

4.1.29(2026-09-27)

存图收敛为「单份物理图 + 硬链接」+ SN 命名/回填 + 批量结果烧录;筛选机手动码与料号清零;相机输出节点

  • 存图开关收敛为 3 个:「图片保存(总开关)」「压缩保存(png/jpg)」「水印」。
    删除 OK/NG 分存、产品保存模式、图片缩放率、压缩质量、保存检测截图 等旧开关(参数设置 →「存图选项」按新口径询问)。
  • 一张图 = 一份物理文件:主份只写一份(放在产品目录里),图层目录、判级 OK|NG|Fail、复检 OverKill|Miss
    都只是硬链接(同盘不额外占空间;跨盘或链接失败自动回退真拷贝并记日志);同名检测结果 XML 只写一份。
  • 产品目录命名:本件有 SN(手动扫码或算法识别)→ 目录名就是纯 SN(同一 SN 的多次检测并入同一目录,
    文件名带「毫秒 + 序号」不会互相覆盖);没有 SN → P_{年月日时分秒}_{产品号}。
  • 中文水印:水印改用 GDI+ 绘制(微软雅黑),中文不再乱码(旧版用 OpenCV 字体,中文必然乱码)。
  • 「手动扫码」页签新增「回填到当前件」:先拍后扫、算法晚于成帧时,把输入框里的 SN 回填给刚拍的那一件
    (改产品目录名 / 文件名前缀 / XML 内产品名,不动硬链接);要求该件全部图层检测完成,否则拒绝并提示原因。
  • 新增「批量结果烧录…」(参数设置菜单、主界面图像右键菜单):按 {月}_{日} 到 {月}_{日} 把
    判级 / 尺寸线 / NG 轮廓烧录进图片,输出到同级 {月}_{日}B 目录(统一 JPG + 同名 XML,目录结构与源一致);
    档位=摘要 / 完整,过滤=全部 / 仅 NG / 仅 OK / 仅 Fail,已存在默认跳过;3D 的 .mat 跳过并计数。
    B 目录可被自动清理、不进 Tab4 统计。
  • 统计与清理:Tab4「数据来源」固定按产品;自动清理把 {月}_{日}B 一并纳入(同一天先删 B、当天目录永不删);
    历史统计不再把同一张图的判级/复检硬链接重复计数。
  • 筛选机手动码与料号清零:「筛选机」节点新增「手动码变量名(默认 manual_code)」「手动码一次性」「复位变量名(默认 sorter_reset)」;
    主界面「手动扫码」页签确认/回车提交后,下一件产品用它做产品名(数字产品号仍自增用于分组);
    FVT logo / 状态栏点击可「料号清零」(清手动码 + 产品号从起始号重新计数)。删除已失效的料号计数持久化(data\cnt.dat)。
  • 相机输出节点(节点树「相机」):面阵相机两路可编程 IO(Line1 / Line2),输出形式=脉冲 / 翻转 / 开 / 关;
    节点上另有四个按钮可直接写硬件(不等流程执行),状态块回显当前电平。

4.1.28(2026-09-26)

结果指示灯改走通讯直控(随包光机固件 v1.0.3)+ 机械臂轨迹V2 链路 + 显示图像控制/存图删图改造

  • 结果指示灯(节点树「光机 ▸ 结果指示灯」):光机四路指示灯(红/绿/蓝/白)不再靠"相机 IO 脉冲 → 光机按脉宽分档点灯",
    改为经通讯直接下发(光机固件 LR,LED),每路可 开 / 关 / PWM(占空比 0-100% + 频率 1-1000Hz);
    · 两种模式:单路=只控选中那一路(其余三路强制关,OK 接绿灯 / NG 接红灯各放一个节点);
    多路=四路各自独立设置(可同时亮多路或单独调亮度);
    · 一次执行只发一条指令(四路原子生效,无中间态闪灯);未连接光机 / 通讯失败 / 固件低于 v1.0.3 时只记日志、不中断流程;
    · 旧的 SendOKLED/SendNGLED/SendStart/SendClose/SendCloseLED 与「使能智能光机指示灯功能」参数、参数设置页的「指示灯测试」按钮已删除。
  • 随包固件:FVT智能光机 v1.0.3(新增 LR,LED 四路指示灯指令 + 软件 PWM,引脚映射集中一处);
    控制卡 v2.5.3、云台 firmware_v1.4.11 / ESP32 v28(补丁与安装包都带,工具里直接 OTA)。
  • 机械臂轨迹V2(节点树「机械臂 ▸ 轨迹V2」):新增 拍照点V2 / 过渡点V2 / 检查点V2 / 事件V2 / 轨迹执行V2,
    检查点V2=机械臂到位停住(blend=0)→ 等条件满足 → 继续(超时走执行器「超时」),用于等轴到位/等变焦/等外部信号;
    原链路节点归入「机械臂 ▸ 轨迹V1」(老图不动)。详见 docs/机械臂检查点V2使用说明.md。
  • 显示图像控制(节点树「事件 ▸ 显示图像控制」):刷新所有图像=主界面已有图像强制重绘并重新适配视图(不重新取帧);
    清空图像=清空实时窗/预览/固定图结果(不动产品结果缓存)。
  • 存图/删图:新增系统参数「图片保留天数」「存图暂停阈值(MB)」;删图=保留天数(全部产品)+ 剩余空间(当前产品);
    满盘时可恢复暂停存图(回升到阈值+256MB 自动还原)。详见 docs/存图与删图审计.md。
  • 抛出异常(节点树「基本 ▸ 抛出异常」,调试用):执行到即抛节点异常,用于验证「节点异常 → 红字 → 系统日志 → 自动停止」;
    可停用直通、可前 N 次跳过。
  • 清理旧 ModBus 通道遗留的配置项与相关方法。

4.1.27(2026-09-26)

机械臂 3D 浏览:支持加载真实模型包并跟随关节动 + 修「读实时位姿」度/弧度;补丁补带 3D 依赖 HelixToolkit

  • 打开 3D 就跟随:3D 窗打开期间每 150ms 读一次机械臂关节角刷新模型(机械臂一动 3D 就动),关窗即停、不占检测节拍。
  • 修「读实时位姿」的老 bug:以前把 MPSDK 的关节角(度)当弧度直接喂给 3D,点一次模型就乱转;
    现在统一在边界换算(并公开 DegreesToRadians 供自检)。
  • 真实模型包(data\model\&lt;型号>\*.model.json + 每个连杆一个 STL):
    · 节点新增属性「模型文件夹」(留空=默认 data\model\HAR7-910;填型号名= data\model\&lt;型号>;绝对路径;填「内置」=强制简化模型)
    与「自动跟随」开关,节点上新增「重载模型」按钮(现场换网格/改 JSON 免重启);
    · 状态行会写清当前用的是哪种几何:模型: HAR7-910(6 连杆) / 模型: 内置简化(原因);
    · 模型按"零位装配变换 + 6 根关节轴"驱动(右手定则;每关节可配 sign/offsetDeg 纠正方向与零位,
    坐标系对齐用 robotBaseInModel)——现场只改 JSON 点「重载模型」即可标定,不用发版;
    · 模型包缺失/损坏时自动回退内置简化模型并说明原因,绝不影响检测与流程。
  • 随包发布:安装包与轻量补丁都会带上 data\model\**(模型包一放进去即随包发);
    轻量补丁补入 HelixToolkit*.dll(4 个)——以前补丁不带这几个第三方依赖,纯补丁升级的机器一开 3D 会报缺文件。
  • 新增提取工具 tools\ArmModelExport(开发机一次性用,不进包):dump 看装配体零件/配合与候选关节轴、
    export 逐零件导出 STL + 读装配变换 + 取关节轴并生成 *.model.json、stepinfo 看中性文件;
    用法与标定/打包须知见 tools\ArmModelExport\README.md 与 docs\机械臂3D模型.md。
  • 待外部配合(本条尚未落地):现场那份 装配体1.SLDASM 被更新版 SOLIDWORKS 另存过(本机 SW2019 打开报
    swFutureVersion),两个包里的 A1..A6.stp 是各自坐标系的子装配导出、拼不成装配;需要在新版 SW 上导出
    「STL(每件一个、装配位置)+ STEP AP214」或向厂家索取 URDF,之后跑一次 ArmModelExport 即可把
    真实网格放进 data\model\HAR7-910。本补丁仍使用内置简化模型(功能与跟随已可用)。
  • 另含工作区中并行开发的其它改动(机械臂轨迹 V2 分链/节点、MOVS 点数合法化等),随包生效。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.5.3、FVT智能光机 v1.0.2、
    FVT云台 firmware_v1.4.11.fvt + ESP32_GENERIC_YTEx_v28.bin。

4.1.26(2026-09-26)

修「进入实时运动模式 失败(切换实时模式错误)」——机械臂模式/使能判定改用真机状态;新增「机械臂报警清除」节点、删除「机械臂急停/解除急停」

  • 现场故障:按「走光机点 → 拍照点 → 开始运动」多段循环跑,节拍一快机械臂就报
    「进入实时运动模式 失败(切换实时模式错误)」,且日志里常与「已进入实时运动模式,全局速度设为 X%」同现。
  • 根因:进/退实时、以及"要不要补上电/切自动"的判断,读的都是 100 ms 推送的状态缓存
    (_robotStatus.eRobotMotionMode / eServoStatus),而「停止拍照」每件都会给机械臂下电、
    「全局速度」每件都会 SetWorkMode(自动)(= 停实时→清队→退实时);节拍一快缓存还没刷新,
    该补的上电没补、该退的实时没退,MP_EnterRealTimeMotionMode 被控制器以前置条件
    (自动模式 + 电机上电 + 未加载工程)不满足拒绝。放大因素:模式切换内部固定 Sleep(500)、
    同一 SDK 句柄(进程单例)没有任何互斥,上一件收尾与下一件启动必然在 500 ms 窗口里交叠。
  • 修法:模式/使能判定一律查真机(MP_HAR_GetRobotStatus / MP_GetRobotWorkMode,读不到才回退缓存);
    只在真机"不在实时"时才进实时(重复进会被控制器拒绝),进之前按真机状态补齐 自动模式 + 电机上电;
    Sleep(500) 全改短轮询(生效即继续);新增 SDK 串行锁(切模式/使能/进退实时/下发+启动/停止/清报警/设速度,
    以及 2 s 工作模式轮询与参数推送回调里的 Get 全部互斥);MovJ/MovL 补 EnsureRealtimeMode()
    (批次外静止拍照点/过渡点/标定走点用的实时接口,以前不确保实时就直接报模式错);
    「开始运动」的下发+启动成对持锁。
  • 「全局速度」节点:批次内(开始拍照之后)只设速度比例、不再切工作模式
    (旧行为等于每段"停实时→清队→退实时",会把正在跑的实时会话打断);批次外保持原行为;
    日志文案改为与实际一致(旧文案"已进入实时运动模式"与实际行为相反,容易把排查带偏)。
  • 节点增删:新增 「机械臂报警清除」(节点上「清除报警」按钮即刻执行、「▶ 单步执行」=清除报警、
    状态行实时显示报警文本;由原「清除报警」改造,老画布 exec 入/出不变);删除
    「机械臂急停」「机械臂解除急停」(StNode + 节点树注册 + Core 模型 + IDobotArm 的
    EmergencyStop/EmergencyStopRecover,机械臂急停走硬件急停回路)。
  • 排查辅助:真正要进实时时会打一行
    [机械臂] [模式] 进实时:工作模式=… 使能=… 实时=0(本地 _runMode=…),现场可直接核对当时状态。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.5.3、FVT智能光机 v1.0.2、
    FVT云台 firmware_v1.4.11.fvt + ESP32_GENERIC_YTEx_v28.bin。

4.1.25(2026-09-24)

随包控制卡固件 v2.5.3:修「筛选机皮带停两次 / OUT4 复位两次」(一个产品被命中多次)

  • 现场现象:跑一件产品,筛选机皮带停两次、OUT4 复位两次;上位机只记录到一次捕获,
    第二次复位在电平日志里只留下一句「(比较命中(命中动作)触发:触发计数 +1)」,看起来像"没人下发却复位"。
  • 根因(固件 v2.5.0 的缺陷):探针捕获自动装填(0x33)挂在捕获确认拍上,但没有判断这次捕获是否被采纳。
    它前面的 probe_push() 会把「探针屏蔽(死区)窗口内的沿」静默丢弃,而自动装填照装不误 →
    屏蔽窗内的回弹/多沿各自又追加一组「锁存 + 间隔」比较点 → 同一行/通道被固件命中多次
    (日志表现:剩余 2→1,而正常通道是 剩余 1→0)。
  • 修法:probe_push() 返回"本次捕获是否被采纳",三个装填点(滤波确认 / 滤波=0 立即捕获 /
    PEND 边界竞态)统一改为被采纳才装填;屏蔽窗口内的沿不再产生比较点。
  • 现场升级步骤:用「FVT控制卡」工具把筛选机那块卡 OTA 到 v2.5.3(本补丁已把工具的默认
    升级目标版本设为 v2.5.3,直接点升级即可;本补丁随包固件也正是 v2.5.3)。
    升级后启动物理表现:每件产品只停一次;比较诊断日志 里 丢弃 恒为 0,不再出现"命中时上一件分支仍在执行 → 排队"。
  • 回归:sorter_host 604 项 / protocol_host 131 项 / dio_host 66 项全过;实板 OTA v2.5.0 → v2.5.3 后
    board_verify 15 项全过(0x33 能力位、187B 计数块、feature2 自动装填/计数位)。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.5.3、FVT智能光机 v1.0.2、
    FVT云台 firmware_v1.4.11.fvt + ESP32_GENERIC_YTEx_v28.bin。

4.1.24(2026-09-24)

线扫触发源改按枚举值兜底:行触发源 = 编码器(枚举 8,不是 6)

  • 现场口径(以相机枚举为准):TriggerSelector=FrameStart(帧触发)的 TriggerSource = Line0(枚举 0);
    TriggerSelector=LineStart(行触发)的 TriggerSource = 编码器(枚举 8)。
    6 不是这台相机的行触发源(GenICam 里 6 一般是 FrequencyConverter),别按 6 下发。
  • 修 4.1.23 的漏:上一版只按 GenICam 名称(Encoder0 / Encoder1 / Encoder)试着写 TriggerSource,
    名称对不上(这型相机枚举名不同)就直接放弃 → 行触发源实际没写进去(行频仍按原设置走)。
    现在名称写不进时按枚举值兜底(帧 0 / 行 8),并回读校验:兜底必须回读 == 8 才算成功,
    失败才列出相机支持的 TriggerSource 值提示去 MVS 核对。
  • 日志可直接核对:名称路径也回读一次,形如 帧触发源=Line0=0 / 行触发源=Encoder0=8;
    走兜底时 行触发源:名称 Encoder0/Encoder1/Encoder 不可用 → 按枚举值 8 下发,回读=8。
  • 只写本次 TriggerMode=On 的触发器(自由模式 / 行触发关闭时不动现场已设的源),采集中被
    TLParamsLocked 锁住照旧自动 停采→重设→复采。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.5.0、FVT智能光机 v1.0.2、
    FVT云台 firmware_v1.4.11.fvt + ESP32_GENERIC_YTEx_v28.bin。

4.1.23(2026-09-24)

日志能看出是哪台相机 + 相机参数线扫「高度」+ 筛选机标题跟随 + 线扫触发源(帧=Line0 / 行=编码器)+ 修「线扫断开崩溃」

  • 相机日志带相机名:相机/轮廓仪/仿真相机的日志出口统一加「名称(设备N)」前缀,例如
    [MVS相机 左云台(设备0)] 登记拍照元数据 产品=1 图层=左云台0、[3D轮廓仪 SN(设备0)] 已连接;
    只带设备编号的链路日志(图像处理完成 / 图像缓存 / 相机轮询 / 相机打开关闭 / HDR 合成)改为
    设备2·左云台;相机还没起名时自动回落成原来的 设备N(老日志格式不变)。
  • 「相机参数」节点新增「高度」(线扫行高):线扫相机执行时按相机 Height 范围钳制后下发(0/空 = 不设置);
    面阵相机行高不是它的参数,属性面板该项灰显并写明原因,执行时忽略并打一条说明日志。
  • 筛选机节点标题跟随「节点名称」:以前标题只按所用运控卡名生成,改名后画布上永远是「筛选机」,
    多筛选机(必须改名区分)根本分不清是哪一台。现在标题 = 运控卡名·节点名称,改名/换卡 ≤180ms 跟随,
    「设备名称」里存的是连接节点改名前的旧别名时标题显示运控卡当前名。
  • 线扫触发源按现场口径下发:帧触发源 = Line0(外部 IO 给帧信号),行触发源 = 编码器
    (按名称依次试 Encoder0 / Encoder1 / Encoder,取第一个成功的)。只写本次 On 的触发器
    (自由模式 / 行触发关闭时不动现场已设的源)。以前只写 TriggerSelector/TriggerMode、不写 TriggerSource,
    于是「帧行触发」的行频仍走 Line0 → 行触发实质不生效;编码器枚举名对不上时日志会列出相机支持的
    TriggerSource 值,便于在 MVS 里对齐名字。
  • 修「线扫断开时报错」IndexOutOfRangeException:节点自绘控件集合 STNodeControlCollection 的
    RemoveAt 左移后不清数组尾槽,而 IndexOf 又扫整个后备数组 → 命中的是"已移出集合"的陈旧引用:
    Contains 误判为"还在集合里"、Remove 拿到越界下标直接抛。现象=线扫相机断开/重连两次后崩溃,
    且第二次切回线扫布局时「行高」编辑框会消失。现在 IndexOf 只扫有效区间、RemoveAt 清尾槽、
    CopyTo 只复制有效元素(同一类问题的其它调用点一并修好)。
  • 同期一并修复:云台示教「插入示教」新建点位(取云台实际位置 / 标记已示教 / 关联引用自动切到新点)、
    节点最小化后复制导致尺寸与子控件布局错乱、右侧节点栏列表重建后滚动位置被顶回顶部。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.5.0、FVT智能光机 v1.0.2、
    FVT云台 firmware_v1.4.11.fvt + ESP32_GENERIC_YTEx_v28.bin。

4.1.22(2026-09-24)

筛选机比较点「零延迟装填」(需把控制卡升到固件 v2.5.0)+ 主机区分「真命中 / 过期丢弃」

  • 现场根因:比较点由上位机在 50ms 轮询里算好位置再 0x12 下发(延迟 050ms+往返),
    而「间隔脉冲 ÷ 带速」常只有十几
    几十毫秒余量 → 点到达时已被越过 → 固件按过期丢弃
    (消费但不触发、不写引脚),主机却只按「FIFO 剩余减少」记命中(假命中)→
    现场现象:命中写了低但皮带不停 / 只有第一件停 / 机械臂空跑 / 事件排队串件。
  • 固件 v2.5.0(FVT控制卡,需升级"筛选机"那块卡;工具与补丁包已带):
    • 新命令 0x33:探针捕获确认那一拍由固件按「锁存位置 + 间隔」直接把比较位置入队(零下发延迟,
      不会再"到达即过期");只对非延迟行启用,「延迟下发」行仍由「比较下发」下发。
      启用了自动装填的通道,追加必须朝当前运动方向前进,落后会被固件拒收。
    • STS_SORTER 尾部追加每通道真触发 / 过期丢弃计数(帧长 123→187B,前缀布局不动,老上位机无感);
      STS_CAPS 追加第二个能力字(u16 主能力字已用满)。
  • 主机(本补丁):
    • 启动捕获时自动把"非延迟行"的间隔表按通道下发 0x33(日志:探针自动装填已启用:N 路(OUT4×M));
      该通道不再逐件 0x12 下发,但仍按同序登记在途(命中归属的产品号/行名不变)。
    • 命中判定改为以固件计数为准:真触发照常触发事件;过期丢弃只记日志
      比较丢弃:OUT4 丢弃 N 条(位置已越过 → 未触发、不写引脚)、不触发事件

      (不再白跑机械臂、不再挤占事件队列/串件);两者与"剩余差"不一致时另有一条诊断告警。
    • 老固件(< v2.5.0)自动退回原行为(逐件下发 + 剩余差判定)并提示一次,不需同步升级。
    • 顺带修正 STS_SORTER 解析:187B 帧(带计数块)不再被误判成 125B 布局(否则通道段整体错位)。
  • 现场验收:升级控制卡 → 启动后跑 3~5 件,每件皮带都停;日志无「命中时上一件分支仍在执行 → 排队」;
    打开「比较诊断日志」应看到 触发= 递增、丢弃=0;事件分支产品号 1/2/3 连续。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.5.0、FVT智能光机 v1.0.2、
    FVT云台 firmware_v1.4.11.fvt + ESP32_GENERIC_YTEx_v28.bin。

4.1.21(2026-09-24)

未示教/失效点位标记(画布 + 点位下拉)+ 示教面板未示教红显;机械臂示教「插入示教」与「当前光机/当前相机」关联

  • 「已示教」标志:四个示教面板(机械臂/运控卡/光机/云台点位)的点位新增显式「已示教」标志,点面板「示教」即打标,
    随 STN 持久化(新增 ptsTaught 等标志块,旧文件不报错);旧画布没有该标志时按示教值回退判定(全 0 = 未示教),老图行为不变。
    灯态/曝光/增益不算示教依据。
  • 示教面板:未示教点位行文字改为红色 + 名称后加「(未示教)」,头部行显示「未示教 M」(M=0 时不显示)。
  • 引用点位标记(13 类引用节点):拍照点 / 走过渡点 / 新机械臂拍照点 / 机械臂示教面板 / 相机参数 / 相机预览 / 光源示教 /
    轴点动面板 / 多轴定点移动 / 镜头示教 / 光机走点位 / 云台示教 / 云台走位——
    引用的点位从未示教 → 节点标题栏变红 + 标题加「(未示教)」,节点上的「点位」行同步(后缀插在下拉三角之前);
    引用的点位在当前画布与跨 stn 目录里都找不到(引用已失效)→ 标题栏变洋红 +「(点位不存在)」。
    运行期高亮(运行中/成功/错误、当前正走向的点)优先:只拼后缀、不覆盖运行色,运行结束 ≤180ms 自动恢复标记色。
  • 点位下拉当场可见:两级的「组→点」下拉与属性面板的点位下拉里,未示教项红字 +「(未示教)」、
    失效项洋红 +「(点位不存在)」;点位变量节点自己的「当前点位」下拉同样标。
  • 跨 stn 判定:打开任一 stn 时自动捕获同目录 hw/product/teach 的「已示教」标志,
    子 stn(如 拍照A.stn)引用 teach 里的点位同样能判出未示教 / 失效。
  • 机械臂示教面板新增「当前光机」「当前相机」两个关联属性:⚡自动选择 只同步这两台关联设备的光源示教 / 相机预览·相机参数节点
    (多光机、多相机画布不再互相串点位)。
  • 机械臂示教面板新增「插入示教」按钮:输入新点名 → 在示教点位所在组新建点位
    (位姿 = 当前实拍并标记已示教;灯态 = 切点前的环态;曝光/增益 = 该相机实时值,
    带回退链「硬件实时 → 预览显示值 → 连接默认 → 内置默认」并在提示里写明本次取值来源)→ 自动选中新点并把关联引用切到新点。
  • 相机支持回读当前曝光/增益(MVS + 仿真):供「插入示教」记录该相机此刻的曝光/增益。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.4.16、FVT智能光机 v1.0.2、
    FVT云台 firmware_v1.4.11.fvt + ESP32_GENERIC_YTEx_v28.bin。

4.1.20(2026-09-23)

飞拍「起点保护」(修"第二遍少一张")+ 点位引用重播种不误清 + 节点测量线程安全;完整安装包 + 补丁包

  • 飞拍起点保护:现场确认"段的起点与该段第一个拍照点太近(≈原地起步)时这一段会少出一张"
    (表现为状态行 已检测 10/11、等待相机 1)。现在下发前自动判定:拍照点与它的实际前驱距离 < 5mm
    就在它前面插一个无触发的"预备点"(沿段内行进方向反退 20mm、姿态/速度/blend 取该点),
    把"原地起步"变成"20mm 外走进来";覆盖飞拍(V2)、百分比(V1)与静止点段,过渡点不参与;
    方向无法确定时不插并告警(不盲拍)。拍照点数/位置、元数据、拍照数、触发行数都不变。
  • 段下发日志:[下发] MOVS(段#N) … 触发行数=8 首点=… 末点=… 起点=(…) 起点距首点=x.xxxmm 预备点=0/1。
  • 段末点未出图告警(这类丢图以前完全静默):运动结束后 ≤2s 检查该段末点图层是否进了缓存,
    没进则告警 段末点未出图:图层「…」(相机 N)——该点触发可能被吞(段起点太近/段末收尾)…。
  • 点位引用:跨 stn 目录"重播种"期间不再判失效(修"机械臂拍照点子 stn 里拍照点显示(未选择)"、
    "光机走点位报点位不存在")。
  • 节点绘制线程安全:文字/尺寸测量共用 Graphics 统一加锁(修执行线程与 UI 线程并发测量
    Object is currently in use elsewhere 崩溃)。
  • 拍照点「飞拍⇄静止」批量转换认全新旧两类拍照点。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.4.16、FVT智能光机 v1.0.2、
    FVT云台 firmware_v1.4.11.fvt + ESP32_GENERIC_YTEx_v28.bin。

4.1.19(2026-09-23)

机械臂「开始拍照」按相机清元数据(修产品号/图层滞后一批)+ 点位引用重播种期间不再误清 + 拍照点批量转换认新节点

  • 机械臂「开始拍照」批次起点清理改用「该机械臂实际用到的相机」:
    「待消费拍照元数据」和「图像缓存」都是按相机编号存的(拍照点登记时用的是它 DO→相机 映射到的那台相机),
    原来这里传的是机械臂编号 —— 机械臂=0、其相机=智能光机=1 时清的是 0 号相机(右云台),
    机械臂那台相机的残留一直没人清,本批帧会配到上一批的 (产品号,图层) → 产品号/图层滞后一批;
    重启后筛选机从 1 重数,两边就对不上(现场:登记=1、整批完成=5)。现在按映射逐台相机清,
    日志给出 开始拍照:已清空待消费拍照元数据(相机 …);没配「输出相机表」时退回旧行为并提示去配置。
    「图像处理」「图像缓存」两个节点保持原样(不清元数据、不丢已处理残留帧)。
  • 点位引用:跨 stn 目录「重播种」期间不再判失效(修现场"机械臂拍照点子 stn 里拍照点显示「(未选择)」"):
    运行/加载产品会先清空再逐文件重建点位目录,重建窗口内任何"按目录判定点位不存在→清空引用"都会误伤有效引用;
    现在该窗口内 PruneDangling/ClearDeleted/点位变更联动一律跳过清理。
  • 拍照点「飞拍⇄静止」批量转换认全新旧两类拍照点(原来右键菜单/批量转换只认旧拍照点,新拍照点选不中、转不到)。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.4.16、FVT智能光机 v1.0.2、
    FVT云台 firmware_v1.4.11.fvt + ESP32_GENERIC_YTEx_v28.bin。

4.1.18(2026-09-23)

Graph 内打开的窗口「已存在就置到前台」+ 筛选机撤掉电平绕行(固件已修)+ 比较表「初始电平」灰显

  • 窗口置前:Graph 里打开的非模态窗统一「已存在 → 不重复开窗,还原最小化 → 显示 → BringToFront/Activate
    → 强置前 → 被其它程序盖住时短暂置顶约 0.4s」,并写一行
    [窗口] 「xxx」已打开 → 已切到前台(不重复开窗),让用户一定能感知。
    覆盖:运控卡 / 筛选机 / 飞拍 / EtherCAT / 机械臂 / 标定 / 3D 预览 7 个节点配置窗;相机搜索、FVT 硬件搜索、
    全局变量、TCP 通讯监视、逻辑图编辑授权、独立编辑器「工作台」(由原来的每点一次新开一个改为单例复用);
    以及「逻辑图编辑」新建空白窗、拍照/硬件/示教逻辑图、母版编辑、子 stn、折叠组「✏ 编辑分组(新窗口)」。
    同一目标静默置前;同类但不同目标(例如已在编辑产品 A 的检测模板,又点产品 B)仍先提示、再把已有窗置前。
  • 筛选机撤销上一版的电平绕行(固件侧已处理「机械臂拍照期间输出被拉起」):删除下发前按"当前电平"
    改写初始电平的护栏,点表下载 / 启动时下发通道参数 / 延迟行「比较下发」恢复按各行「初始电平」下发;
    撤表恢复按节点属性「停止时比较输出」执行(该属性恢复可见可编辑),并删除启动时那行提示。
  • 比较表配置窗(筛选机「⚙ 比较表配置…」):通道「脉冲类型」选成 置位(高)/复位(低) 时,
    「初始电平」置灰不可编辑(值保留、仍随画布保存与原样下发);切回「脉冲 / 反转电平」恢复可编辑
    ——置位/复位是绝对动作(命中即写到目标电平并保持),初始电平不参与语义。
  • 随包三工具最新 OTA 固件:FVT控制卡 v2.4.16、FVT智能光机 v1.0.2、
    FVT云台 firmware_v1.4.10.fvt + ESP32_GENERIC_YTEx_v27.bin。

4.1.17(2026-09-23)

升级检查新增「本机镜像 D:\work\publish」兜底(主共享不可达时也能发现新版)

  • 背景:发布脚本每次都会往本机镜像 D:\work\publish 投一份,但客户端检查更新只用
    \\Win-20250222jjj\共享文件夹\fuwei\up + 两个发布机共享(\\FVTGAME\publish、\\192.168.1.90\publish)——
    主共享不可达(或共享里还是旧版本)时,本机镜像里的新版看不到。
  • 升级目录候选顺序改为:主共享 → 本机镜像 D:\work\publish → \\FVTGAME\publish → \\192.168.1.90\publish。
    本机镜像走本地路径,秒查;现场机器没有该目录时 Directory.Exists 立即返回 false,
    不占网络超时、不影响启动;多目录仍按"取版本更高的一份"挑选(共享 4.1.6 + 镜像 4.1.16 → 用镜像)。
  • 新增环境变量 FVISION_UPDATE_MIRROR 指定本机镜像目录(换盘/换目录用);
    FVISION_UPDATE_DIR(分号分隔整表自定义升级目录)照旧可用。
  • AreaAI.exe --check-update 的诊断会打印"尝试过的升级目录(按顺序)+ 本次实际使用",现场可直接核对。
  • 说明:现场机器仍以主共享为准(没有 D:\work\publish);本条主要便于发布机/调试机自升级与临时本地升级。

4.1.16(2026-09-23)

点位改名/删除全链路同步(标定 / 机械臂事件 / 检测模板图层)+ 相机曝光增益范围跟随硬件

点位引用同步(补齐三类引用 + 跨逻辑图)

  • 点位改名/删除时,除已有 12 类引用节点,新增同步:标定节点「拍照点位」(完整名)与「图层名」(点名)、
    偏置计算节点「图层名」(点名)、机械臂事件「到点名」(完整名 = 拍照点传进轨迹的点位名)。
    删除点位时这三处引用一并清空;「原点点名/方向点名」(算法层创建点名称)不动。
  • 作用范围 = 当前画布 + 产品目录下全部 stn(含子 stn、折叠分组内部),与既有跨图同步同一套机制与提示。
  • 检测模板图层名跟随改名:图层名(= 点名)、产品目录下 {图层名}.png 模板图、
    Train\{图层名}\ 训练图片文件夹一起改,改完立即落盘;检测模板窗口开着时图层列表即时刷新。
  • 冲突一律不覆盖(模板里已存在目标图层名/同名文件、未加载产品、文件被占等):不动原物,改写记入
    {产品目录}\point-renames.json;打开检测模板时逐条弹窗选择「改名保留算法配置 / 删除旧图层按新名新建 /
    跳过不再提示」——避免旧图层被当成"多余图层"删除而丢掉该图层的算法配置。
  • 顺带修掉"删点后跨 stn 目录/全局变量只增不减":目录按来源文件记账(删除/改组名后立即消失,
    别的文件同名组点位不受影响),删点位的变量残留一并清理;检测模板打开时不再出现已删点位的"幽灵图层/点位"。

相机曝光/增益范围跟随硬件

  • 「相机连接」节点新增「连接时自动读取范围」(默认开):连接后读取相机实际曝光/增益 min~max 并写回节点
    「曝光最小值/最大值、增益最小值/最大值」(滚动步进不覆盖),日志打印新旧对比;相机不支持/未连接则沿用节点配置并记一行日志。
  • 新增「默认曝光/默认增益」:相机预览与点位未单独设置时使用;新增点位自动带上(不再出现"空增益")。
  • 相机预览的曝光/增益编辑框按「相机连接」节点的范围与滚轮步进钳制,范围变化即时同步。

4.1.15(2026-09-22)

随包固件更新到 FVT 控制卡 v2.4.16(程序本体与 4.1.14 相同,现场升级补丁即同步拿到最新固件)

  • 控制卡 v2.4.16:四轴电机使能输出——每轴可选 OUT0~7 与极性、可持久化到板卡 Flash(配置 v7 → v8),
    上位机「运控卡参数配置」新增电机使能分组(单轴/全部使能·禁用,未映射或旧固件灰显);
    下发运动指令(走点/点动/回零/飞拍)前会检查"该轴已映射但未使能"→ 板卡返回 NACK STATE,避免带病动作。
    含 v2.4.15 的"解除急停后补回仍在触发的限位封锁"。
  • 配套工具:tool\FVT控制卡 同步到该版本(电机使能行 + 系统配置分组),并已支持 v2.4.14 起的设备类型显示。
  • 其余随包固件不变:FVT智能光机 v1.0.1(设备类型 0x02)、FVT云台 firmware_v1.4.8.fvt + ESP32_GENERIC_YTEx_v25.bin。

4.1.14(2026-09-22)

运控卡 / 光机 不再"长得一样":发现应答带设备类型 + 扫描窗「设备类型」列 + 连接后身份核验

  • 背景:两块板协议同源(同样的 ACDP/ACDR、同样按 02:A5:11 + UID 末 3 字节 派生 MAC),
    扫描列表里 IP/MAC/UID/版本/轴数全都有,光看报文无法分辨——拿错设备去改 IP/MAC/烧固件都危险。
  • 固件在发现应答尾部追加 1 字节 dev_type(56 → 57 B,只加帧尾,旧上位机按固定偏移解析不受影响):
    0x01 = AxisControl 运控卡(v2.4.14)、0x02 = AIGJ 智能光机(v1.0.1)、0x00 = 未声明(老固件/其它产品)。
  • 「FVT 硬件搜索」新增**「设备类型」列**:运控卡 / 光机 / 未声明(≤v2.4.13、光机 ≤v1.0.0)/ 其它设备 0xNN。
    **明确声明为"其它设备"**的行整行灰字 + tooltip 警示(协议同源产品,勿改 IP/MAC/烧固件),状态栏给红字计数;
    「一键生成流程节点」与「应用」(仅当本次真要写 IP/MAC,只改名称不弹)对这类设备先弹确认框。
    「未声明」只显示文字、不告警(现场大量老固件设备)。
  • 连接后身份核验:运控卡连接、光机连接在 TCP 连上后按 IP 做一次 UDP 探测(1.2s),
    日志给一行 身份核验:UID/MAC/SN/版本/类型;明确声明为非本产品时输出 [报警](勿下发配置/升级固件);
    无 UDP 应答(老固件/防火墙拦 30303)只记"跳过",不影响连接。运控卡连接节点新增一行状态「设备类型 …」
    (运控卡=绿、非运控卡=红字、未声明=灰);光机连接节点新增只读属性「设备类型」。
  • 工具侧口径统一:0x02 在 FVT 控制卡工具与 find_boards.py --scan 里显示「光机」(仍算非运控卡、仍告警)。
  • 随包固件:FVT控制卡 v2.4.14 + FVT智能光机 v1.0.1。现场要区分类型需把这两块固件都升级;
    未升级的设备显示"未声明",原有功能不受影响。

4.1.13(2026-09-22)

「相机连接」的曝光/增益范围改为自动读相机(不用再手填)+ 默认值与步进按现场约定调整

  • 新增属性「连接时自动读取范围」(默认开):连接成功后读相机的 ExposureTime / Gain 浮点节点范围
    (MVS 的 fMin/fMax),写回本节点的「曝光最小值/最大值、增益最小值/最大值」,日志打印新旧对比
    (如 曝光范围已按相机更新:10~1000000us(原 1~100000));读不到(相机不支持/未连接)沿用节点上配置的范围并记一行日志。
    MVS 浮点节点不提供步进,所以滚轮步进不会被覆盖(仍按节点上填的值)。不需要自动的现场把该开关关掉即可。
  • 读到的范围会写进全局上下文 → 点位执行钳制、相机预览底行编辑框(含滚轮步进)都按真实范围工作,
    预览编辑框的范围会随「相机连接」的范围自动跟随(不用重开窗口)。
  • 默认值/步进统一为:默认曝光 100us、默认增益 1;曝光滚动步进 20us、增益滚动步进 1
    (「相机连接」节点、「相机参数控制」节点、以及"新增点位的内置默认"三处一致)。
  • 「曝光(us)/增益」填 0 = 连接时不设置(保持相机当前值,不动相机参数);填 >0 才按范围钳制后下发;
    若读到的相机范围让钳制结果发生变化,会按相机范围复核并补下发一次(日志有 按相机范围复核后补下发…)。

新增拍照点位的曝光/增益不再为空

  • 现象:面板「➕批量添加」新增点位后,点位属性行的「增益/曝光(us)」是空白(点位执行时不写相机参数 → 用默认值)。
  • 现在新增点位一律带默认值:优先取画布「相机连接」节点的「默认曝光/默认增益」;
    没配(≤0)或画布没有该节点时回退内置默认(100us / 增益 1);新建点位变量节点自带的第一个点位同样如此。
  • 仍可手动清空(留空 = 未设置,点位执行时不写相机参数);载入旧画布保持文件里的原值,不受影响。

4.1.12(2026-09-21)

系统参数文件"读不懂"不再整份作废、不再被默认值覆盖(现场"更新补丁后参数被重置"的根因)

  • 现象:补丁更新后现场系统参数(data\Config.dat)经常变成默认值(一大堆 0/空)。
  • 根因:CConfig.LoadProject() 一旦读不出来就"隔离原文件 + 立刻写一份默认 CConfig";配置是按类型名
    反序列化的($type + 白名单绑定),而补丁只替换程序集 —— 旧文件里只要有一处读不懂
    (删类导致 $type 找不到、参数类型变化、文件被写坏/半截)就会触发这条兜底。实测该路径还会
    "日志↔载入"互相递归,直接栈溢出崩溃(0xC00000FD)——也就是说旧版本遇到坏配置是启动即崩。
  • 现在:① 容错读取:单个成员/条目读不懂只跳过那一处并记日志(根对象的 $type 读不懂时按声明类型重读);
    ② 读失败先救副本:最新隔离文件 → Config.dat.bak → data\bconfig\* → backup\&lt;版本>\data\,
    (4.1.60 起第 3 档由统一备份仓库 &lt;备份根>\system\config\* 取代,旧 data\bconfig 已取消),
    第一个能读成 CConfig 的自动写回主配置;③ 实在没有才落默认值,并写 ERROR 日志 + 弹一次明确提示
    (带上隔离文件名,告诉现场去哪找);④ Config.dat.bak 由"读成功/保存成功"两条路径自动维护,
    默认值重建那一次写盘禁止覆盖备份;⑤ 载入期加重入保护,坏配置不再崩溃。
  • 发布侧加固:轻量补丁白名单断言——禁止夹带 data\ / Projs\ / Log\ / *.dat 等现场数据(唯一允许的
    data\ 文件是 log4net.config),从根上杜绝"补丁把现场参数冲掉"。

云台新增「云台电机上下电」节点(全部舵机一键上电/下电)

  • 与云台工具/上位机的「全部上电 / 全部下电」同一条固件命令:LR,STQ,&lt;id|0>,&lt;0|1>,;(写舵机 SRAM 0x28),
    应答 LR,OK,STQ;;id=0 → 固件遍历所有已发现舵机,一条指令即全部生效。
  • 节点属性:设备名称(全局下拉,只选不可手输)/ 设备编号(隐藏)/ 动作(上电=保持·锁死防手搬动、下电=松弛可手动转动)
    / 舵机ID(0=全部,>0 只操作该舵机)。标题随动作显示「云台电机上电 / 云台电机下电」。
  • 固件过旧不支持 STQ、或一个舵机都没扫到(LR,ERR,stq,nofound;)时抛中文错误,不静默当成功。

属性表达式:属性框里打 = 直接弹全局变量下拉

  • 位置/速度/轴号等属性支持 =变量名 引用全局变量;现在打一个 = 就弹出变量候选(不用背名字),
    定点移动/多轴定点移动的取值范围同步补了测试。

逻辑图:节点标题按"名称表/设备名"自动跟随

  • 打开 stn、保存 stn 各整画布刷一次节点标题;运行期 180ms 泵检测到名称表(轴名/IO 名)或设备名称变化时,
    相关节点标题(轴走位/回零/点动/IO 等)自动重算——现场改完「运控卡连接」的轴名称表后,画布标题不再"对不上"。

文档:新增《全局变量与相关节点使用说明》中「全局变量写入 / 全局变量读取」两个节点的专讲章节。

4.1.11(2026-09-21)

修「检测时候 Value cannot be null」真凶:圆/弧卡尺 ROI 深拷贝后同步锁是 null

  • 现象:带圆/弧卡尺 + 定位的检测一跑就抛 Value cannot be null. (Parameter 'obj')。
  • 根因:CFindArcFromROI 的同步锁是 readonly 字段 + 只在构造函数里补一次,而 .NET 10 迁移把
    FClone 从 BinaryFormatter.CloneEx 换成了 DataCodec.DeepClone:
    ① 克隆体用 RuntimeHelpers.GetUninitializedObject 创建 → 字段初始化器不跑;
    ② 字段枚举跳过 readonly 字段(if (f.IsInitOnly) continue;)
    → 克隆体的锁对象是 null,lock (null) 直接抛 ArgumentNullException。
    触发面:定位分支会对每个 ROI/Caliper 做 FClone 后当检测对象用,所以带圆/弧卡尺 + 定位必炸。
  • 修法:CFindArcFromROI 的锁字段去掉 readonly、加 [NonSerialized](与同文件 CFindLineFromROI 对齐),
    新增惰性 LockObj(Interlocked 保证并发下只认第一个),该类 6 处 lock 全部改用它;
    并全仓扫描确认"readonly 实例锁字段"仅此一处。
  • 验证:--persist-selfcheck 新增用例——深拷贝/JSON 回填后原始字段可以为 null,但代码真正 lock 的对象必须非空
    (修复前该断言失败,修复后通过)。

4.1.10(2026-09-21)

「有定位生成外观检测训练图片」一张都不出:ROI 没名字时被静默跳过

  • 现象:点「有定位生成外观检测训练图片」后一直停在「图像处理中…… 0,0%」,Train 目录里一张图都没有;
    「无定位生成」那条链路正常。
  • 根因:无定位链路按模型名建目录(Train\{模型名}\good),有定位链路却只按 ROI 的 Name 建目录,
    并按 if (!string.IsNullOrEmpty(Tag)) 过滤——现场那个 ROI 没有起名字,于是每一张都被判为"无名"直接跳过,
    既不写盘也不报错。
  • 现在:有定位链路与无定位链路对齐,输出目录优先 AI 模型名(训练本来就是按模型名找 Train\{模型名}\good),
    ROI 名作后备、再退到 temp 兜底;每张图的 Cv2.ImWrite 返回值都校验,写失败记错误日志;
    结束时记一行「已生成外观检测训练图片 N 张 → <目录>(共处理 M 张)」,产没产出、产出到哪一目了然。

「检测时候 Value cannot be null」查不到原因:异常不再只弹窗、不落日志

  • 现象:检测时报 Value cannot be null,弹了个框,但系统日志里什么都没有,无从定位。
  • 根因:DetectOne() 的 catch 只弹 ex.Message(就那一句话),没写日志;外层 Unity.SendMessage(Exception)
    也只输出一句 Message,异常类型和内部异常链全丢了。
  • 现在:检测失败把完整异常(异常类型 + 堆栈 + InnerException 链)写进系统日志;SendMessage(Exception)
    同步输出异常类型与内部异常链,Value cannot be null. 的参数名/根因都保留下来。
  • 本次排查结论(修复前的定位线索):代码里会抛这条消息的位置是自研原生包装 FV.FnGetEDLines/FnGetED/FnGetEdge
    (data 为 null 或 Mat 已释放 → ArgumentNullException(nameof(data))),以及
    VectorOfTemplate/VectorOfVectorTemplate/VectorOfFeature(集合为 null);
    定位到具体调用点需要完整堆栈,故先补齐日志。

4.1.9(2026-09-21)

FVT 硬件搜索:手选的类型与名称不再重扫后变回去(光机等没有 UID/SN 的设备)

  • 现象:写了名称、在列表「类型」列把设备改成光机,点重新搜索后又变回「未识别 / 没名字」。
  • 根因三处:① 手选类型只改内存,不落盘;② 名称回填对「未识别」行直接跳过,记录里有名字也不显示;
    ③ AIGJ 光机在发现协议里没有 UID/SN(固件不改),只被 TCP 探测发现时连 UID 都没有,只能按 IP 记名,换 IP 就丢。
  • 现在:手选类型立即写本机记录,重扫时对「未识别」行跨类型回查记录,命中就按记录里的类型显示
    (状态列标注「类型来自本机记忆」)并回填名称;识别光机时顺带用固件早已支持的 LR,MAC,; 取板卡 MAC 当稳定键,
    记录对齐顺序统一为 UID → 序列号/设备码 → MAC → IP(绑 MAC 的设备换 IP 也不丢名)。
  • 界面新增「名称绑定」列,显示名称/类型实际绑在哪个标识上(UID / 序列号 / 设备码 / MAC / IP)。

两个搜索窗:应用(改名/改 IP/MAC)后不再自动重扫

  • 现场要求扫描一律手动点:自动重扫会打乱手工选好的类型/勾选/滚动位置,改 IP 后板卡(相机)正在重连,扫了也不准。
    现在应用后只就地刷新那一行;相机改过名称仍在下次手动扫描时自动核对相机里实际存的名称。

逻辑图右侧节点列表:分组标题改成自绘标题行

  • 原来的标题是 ListView 的分组头,由系统主题绘制、颜色不受控(深色底上是不明显的蓝字),emoji 圆点还会退化成单色空心圈。
    现在用自绘标题行:粗体、有连线橙色 / 无连线灰色 + GDI+ 自绘圆点;标题行不可选中(点它不改变画布选择),空分组不占行。

两个搜索窗:等待光标不再残留

  • 忙碌收尾同时复位窗体、所有子控件与进程级 Cursor.Current;窗口打开期间每 400ms 自检一次,
    非忙碌时发现等待光标立即复位(并写系统日志留痕);忙碌超过 60 秒(操作线程卡死)自动恢复界面,不会永远"沙漏 + 不能点"。

检测算法:圆/弧定位克隆丢环宽 →「有定位生成外观检测训练图片」一张都不出

  • 现象:点「有定位生成外观检测训练图片」后没有任何图片产出;无定位那条链路正常。
  • 根因:FClone(深拷贝 DataCodec.CloneValue)与 JSON 契约此前是同一个毛病——只用
    Type.GetFields(...) 取当前类型字段,派生类型看不到基类的私有字段。CFindArcFromROI : CTwoArc
    的克隆因此丢掉基类的 m_width,克隆体的环宽变成 0;环宽 0 的圆/弧卡尺取不出环带图 →
    圆/弧拟合失败(「线圆/线弧定位不存在」)→ ROI 变换失败 → 没有任何可裁区域 → 训练图片一张都不出。
    (同一根因在 4.1.7 之前表现为 ArgumentException: colStart >= colEnd。)
  • 现在:深拷贝与 JSON 契约统一走沿继承链逐层取字段(派生优先),克隆体环宽/半径/圆心等基类字段全部保真;
    另外把「环宽为 0」的圆/弧裁剪从"跳过"改为按 App 自己创建圆卡尺的口径(半径 1/4)补一个可用环带并提示一次,
    避免再出现"不报错但也什么都不做"。
  • 验证:探针实测 CFindArcFromROI.GetFields(...) 不含 m_width(正是丢字段的原因),修复后克隆体
    Width 与原对象一致(85.09);环宽 0 时能裁出 1269×45 环带;--persist-selfcheck(含"深拷贝字段级等价"用例)全绿。

4.1.8(2026-09-21)

FVT 硬件搜索 / 相机搜索:「应用」只写变化了的字段(不再三个一起动)

  • 名称 / IP / MAC(相机是名称 / IP / 掩码 / 网关)现在各自和当前值比对,只有变了才写。
  • FVT:以前只要 IP 框里有值就会弹「确认写入 IP…」,看着像"改个名也把 IP 动了";现在只有 IP 真变了才问、
    也才做"等板卡重连再重扫"。三项都没变时直接提示「没有需要应用的改动」。
  • 相机:以前是"只要相机是 GigE 就无条件把 IP/掩码/网关重下发一遍",于是只改个名称也会让相机网络白重启一次;
    现在按内容比对,只在下发内容变了时才走静态 IP 流程,名称没变也不再写相机本体。网段不符(不可达)时改名会明确提示先改 IP。

光机名称改不了

  • 根因:AIGJ 光机在发现协议里既没有 SN 也没有用户名字段(固件 discovery.h:本产品无 SN,应答填 0)。
    只被 TCP 探测发现(没答 UDP)的光机连 UID 也没有,旧代码写记录时直接报「UID 与序列号都为空」→ 怎么改都改不了。
  • 现在这类设备按 IP 记名((类型, IP) 键,且只在双方都没有 UID/SN 时才按 IP 比对,避免串到别的机器),
    改名能保存并在重扫后回填。

逻辑图右侧节点列表

  • 去掉占宽又没用的「位置」列,列表只剩「节点 / 类型 / 连线」三列并随面板宽度拉伸(不出横向滚动条);
    行序仍按位置兜底排序,同名同色节点不会串行。
  • 分组标题文字颜色由系统主题决定、现场看不清 → 改为整行文字配色:有连线橙色、无连线灰色,
    统计行同步标注「橙 有连线 / 灰 无连线」。

4.1.7(2026-09-21)

崩溃修复:圆环裁剪报 colStart >= colEnd、有定位算法点图层/训练时整进程退出(重要)

  • 真凶一:255 被当成了内存地址。 BlobDetect.TryGetTemplateMask 里原本写 new Mat(height, width, CV_8UC1, 255)
    (想表达"填充白色"),C# 把字面量 255 绑到了 Mat(rows, cols, type, IntPtr data, long step) 重载
    (IntPtr 有 implicit operator IntPtr(int)),于是 Mat 包的是地址 0x000000FF;
    实测 new Mat(3,3,CV_8UC1,255).Data == 0xFF,而 Scalar.All(255) 才是填充色。Cv2.FillPoly 一往这块内存写就
    访问违例 0xC0000005、整进程退出(原生崩溃,托管 try/catch 拦不住)。已改为 Scalar.All(255),并全仓排查同类写法。
  • 真凶二:空多边形。 Tmplate.Polys 里若留着"没有顶点"的多边形 hash(SetMaskTemplate 原来只按选中状态记录、
    不检查有没有点),FillPoly 会被喂 0 点数组 → 同样 0xC0000005(实测:0 点、[3点,0点] 混合都崩;1/2/3/5 点正常)。
    现在掩膜只取有顶点的多边形,SetMaskTemplate 也不再记录空多边形。
  • 圆环裁剪 colStart >= colEnd:Unity.FnCropImage(Mat, CTwoArc) 在环宽 < 1 像素时算出 0 宽矩形
    (startx == w),OpenCvSharp 抛 ArgumentException: colStart >= colEnd。宽度能在界面上被拖成 0
    (拖动"宽度"手柄时 宽度 = 2×|鼠标到圆心距离 − 半径|,鼠标停在半径位置即为 0)。
    现在:环宽 < 1 时记日志并跳过裁剪、startx 必须落在 (0, w) 内才裁剪;拖动与 Width 属性都保底 1 像素。
  • 顺带加固:多边形列表只物化一次(原来惰性查询被枚举两次,可能长度对不上)、掩膜矩形与画布求交后再取子图、画布显式释放。
  • 验证:分进程探针 —— 环宽 0/0.5 不再抛异常、1/50 正常裁剪;TryGetTemplateMask 正常与"点被清空"两种情形都返回掩膜且不再崩
    (修复前两者均会 0xC0000005);--persist-selfcheck(4 个真实样本)全部通过,dotnet build 0 错误。

4.1.6(2026-09-21)

检测算法(Blob):组合算法「添加了但列表不显示」(重要)

  • 根因在 UI 层:组合算法列表是 ListBox.DataSource = Algs[图层].Select(x => x.Name).ToArray(),
    而 WinForms 的 ListBox 只要数据源里出现 null,整列一行都不显示(实测:[null]→0 行;
    [null,"有定位AI检测1"]→0 行;["A",null]→1 行)。老模板/迁移后的数据里 Name 可能是空,
    于是算法确实加进了模型、列表却始终空白,GetCurBlob 也因选中项为 null 直接返回 false(后续刷新跟着异常)。
  • 现在载入模板(Tmps.BuildLayer)与构建图层算法表时都会给缺名的组合算法补唯一默认名
    (口径与「组合算法 → 添加」一致:有定位AI检测n / 无定位AI检测n / 码识别n / 类型名n,重名自动加 _k);
    Tmp.Add 也保证「有名字、不重名」,顺带消掉「用列表项目数拼名字 → 删除后再添加会重名 →
    按名反查命中旧对象」的隐患。
  • 验证:用现场那份 Name 为空的真实配置跑探针 —— 修复前每层列表 0 行(复现空白),
    修复后 1 行、再添加一个变 2 行且不重名。

相机搜索:改名会静默「改了没改」

  • 相机名写回相机时改走原生接口按 GB2312 字节下发,并在写后读回比对;改名后按新名核对列表与本地记录,
    不再出现「提示成功、相机里还是旧名」,也就不会再出现按新名连接找不到相机。

两个搜索窗:等待光标残留

  • 忙碌收尾复位 Cursor.Current,并把弹框移出忙碌态,鼠标不再一直显示等待圈。

4.1.5(2026-09-21)

数据持久化:模板迁移成 JSON 后字段丢失(重要)

  • 症状:迁移后 BlobDetect 上的 Name 全为 null(组合算法列表项变 null,添加/刷新异常),
    Types/Rois/Caliper/Tmplate/Index/WP/Masks 等同样丢失,配置文件从 262144B 缩到 653B。
  • 根因:JSON 契约只取当前类型的字段(Type.GetFields 在派生类型上看不到基类的私有字段,
    而自动属性的后备字段都是私有的),迁移时把基类上的字段整片丢掉。
  • 现在序列化契约与自检 walker 都沿继承链逐层取(派生优先),并修掉三处连带问题:
    数组不被当数据类(Template[][] 之前 new 不出数组)、ObjectCreationHandling 改 Replace
    (否则文件里的集合会追加到构造函数预置集合上)、给只能带参构造的类型补无参构造。
    验证:AreaAI.exe --persist-selfcheck 用迁移前备份做样本(config 262144B → 169233B,不再掉到 653B)。

FVT 硬件搜索 / 相机搜索:改一台,结果全都被改成同名

  • 根因:「应用」取作用对象时优先用勾选行,而下方「名称/IP/MAC」编辑器只显示当前选中行。
    只要之前为「一键生成流程节点」勾过几行,改名时同一个名称(相机还含 IP/掩码/网关)就会被写到每一台勾选的设备上。
  • 现在两个窗口的「应用」都只作用于当前选中行;勾选只保留给批量动作
    (生成节点 / 重启 / 恢复 MAC / 测试连接 / 复制),点勾选框时状态栏会显示"已勾选 N 台(勾选只用于…)"。
  • 顺带修复:FVT 硬件搜索应用后按上次的扫描方式重扫(云台搜索过就仍带云台),
    此前固定用 UDP 重扫,改完云台名称后云台行会凭空消失。

相机搜索:状态与官方 MVS 客户端对齐

  • 四态改名与重绘图标:可用(灰白相机机身)/ 不可达(橙色三角感叹号,IP 不在同一网段,只能改 IP)/
    占用(相机机身 + 红色禁止符,被其它软件或进程连接)/ 离线记录(灰空心圆,本工具扩展)。
  • 「不可达」改按官方口径判定:只看发现该相机的那块网卡,不再回退比全部网卡,
    避免"本机恰好还有一块同网段网卡"时把不可达相机误判成可用。

4.1.4(2026-09-21)

FVT 硬件搜索:云台搜索能一次找出全部云台

  • 「🔍 云台搜索」上一版把探测地址收敛成 192.168.4.1 / 192.168.4.32 两个,现场几台云台只能搜到 1 台;
    现在改为与「云台扫描」节点同范围逐台探 192.168.4.1 ~ 192.168.4.32,有几台出几台。
  • 32 个地址并发探测(最多 16 路),点一下约 1~3 秒出结果(不再逐台串行累加超时);
    运控卡/光机仍只走 UDP 广播发现,本机各 /24 不再扫描。

MVS 相机搜索:状态与官方客户端对齐

  • 四个状态改名并重绘图标,对齐官方 MVS 网口相机状态表:可用(灰白相机机身)/
    不可达(橙色三角感叹号,相机 IP 不在同一网段,需改 IP)/ 占用(相机机身 + 红色禁止符,已被其它软件或进程连接)/
    离线记录(灰空心圆,本工具扩展)。
  • 「不可达」判定改为只看发现该相机的那块网卡(官方口径),不再回退比全部网卡,
    避免"本机恰好还有一块同网段网卡"时把不可达相机误判成可用;只有上报网卡地址已不在本机时才回退。

检测算法(Blob)

  • 切换图层时重新载入该图层已保存的模板图(Unicode 安全读,中文路径不受系统代码页影响):
    读不出来明确提示「图层图片读不出来:<全路径>」,成功则记录「图层模板图已加载:<路径>」。

4.1.3(2026-09-21)

检测算法(Blob)模板图片:中文文件名不再受系统代码页影响

  • 图片读写改成 Unicode 安全方式(File.ReadAllBytes + ImDecode / ImEncode + File.WriteAllBytes),
    不再把中文路径交给 OpenCV 的 ANSI 接口:图层模板图保存、模板图/样例图加载、多相机窗口、Train 目录图片共 13 处。
  • 读不出来时提示改为「图层图片读不出来:<全路径>」,成功加载记一行「图层模板图已加载:<路径>」,
    便于现场判断是「文件没有」还是「读不了」。

MVS 相机名称(同一台相机在不同机器上名字不一致 / 按名字连到别的相机)

  • 根因:MVS 托管包装把 chUserDefinedName / chSerialNumber / chModelName 按系统 ANSI 代码页收发,
    而相机里存的是官方客户端写入的 GB2312 字节;在开启「使用 Unicode UTF-8 提供全球语言支持」(ACP=65001)的机器上
    会被当成 UTF-8 解码 → 中文名乱码、按名称连接会找不到相机或连到另一台。
  • 现在一律取原始字节显式解码(UTF-8 严格 → GB2312 回退),写 DeviceUserID 走原生接口按 GB2312 下发并读回比对;
    覆盖 GigE/USB 枚举、相机连接节点目录(MvCameraController)与「相机搜索」窗。
  • 「相机搜索」状态改为四态(对齐海康官方客户端):可连接(绿) / 网段不符(橙,优先于占用) / 已被占用(红) / 离线记录(灰);
    新增「发现网卡」列与同网段判定(一卡多 IP 全纳入);网段不符只允许改 IP,只有「可连接」的相机能一键生成流程节点;
    状态图标改 GDI+ 自绘(不用 emoji/符号字符,避免字体缺字形显示成怪符号)。

FVT 硬件搜索

  • 「深扫描」改为「🔍 云台搜索」:只探 192.168.4.1 / 192.168.4.32 补出云台(云台不答 UDP 探测),
    不再对整段 /24 全量扫描(更快、也更少误报);上次保存的别名会自动回填到新扫描结果。

4.1.2(2026-09-21)

修复

  • 检测算法(Blob)窗口「模板图片保存」点了没反应:原实现有三处静默 return(画布没图像 / 图层列表没选中 / 名称在图层表里找不到),
    条件不满足时既不提示也不写日志,现场表现为「用不了」。现在全部改成明确提示;画布图像为空或已被算法侧释放时,
    回退用画布当前显示的位图保存(所见即所存)。
  • 图层列表右键不选中:WinForms 右键不改变选中项,「模板图片保存 / 删除图层 / 复制图层 / 模板参数 …」原来会作用到未选中
    或上一次选中的图层。现在右键会先选中光标下的图层(左键行为不变)。
  • 写盘结果不再假装成功:Cv2.ImWrite 的返回值原先被忽略,无权限 / 盘满 / 路径非法时也会打印「图层图片保存成功」。
    现在真实校验并记录错误日志;图层改名改为「先写新图、成功后再删旧图」,写失败回滚图层名,不会出现「改名了但模板图没了」。
  • 图层改名后立即保存产品模板:否则图层名已改、盘上是新文件名,而 config_&lt;产品>.dat 里仍是旧名,
    下次打开会报「图层图片不存在」,并连带定位模板报「…定位模板没有找到目标」。
  • 同菜单的**「批量模板图片保存」**补上结果反馈(成功 / 已存在跳过 / 源目录未找到 / 失败计数并写日志),原来完全无提示。

4.1.1(2026-09-21)

工程清理版:界面与功能无变化,可作为 4.1.0 的补丁直接升级。

清理(内部维护,不影响使用)

  • 删除旧「运控」链路残件:旧运控实现 AreaAI.Motion(FWLib/MotionImplementation.cs,约 4.3k 行)、
    Device/ 下 6 个已无引用的老板卡驱动(DMC2410 / LTDMC3800 / UWC4000 / KeyenceDis×2 / pci9014 / CST)、
    MotionControl/ 下 10 个旧运控参数窗体。
  • 删除官方示例工程 NodeFlow/WinNodeEditorDemo(27 文件,早已移出解决方案,发布包也一直不带它)。
  • 「零引用即删」收尾:删除 10 个零引用旧窗体(Motion / FormYTDict / 筛选机设置 / Form4 / Form5 / FormPP /
    AboutBox1 / DatePick / ProductManage / HistShow)与若干零引用类型、方法、字段及失效 using。
  • 恢复共享 UI 基类 FWVision.UIPanel(Blob 分析、伪彩面板的基类)到 Control/UIPanel.cs,
    修正上述删除过程中出现的一处编译中断(该基类被误删会让算法面板改继承源,属行为级破坏)。

验证

  • dotnet build AreaAI.csproj -c Debug → 0 错误;NodeFlow.Tests → 467 项全过;
    AreaAI.exe --graph-selfcheck → 通过。

4.1.0(2026-09-21)

这是运行平台升级版:必须用安装包升级(不能只打轻量补丁)。 客户端检测到本版会自动改走安装包,并提示原因。

平台升级

  • .NET 6 → .NET 10 LTS(net10.0-windows,全部子工程/工具同步升级)。.NET 6 已于 2024-11 结束支持,
    升级同时解决长期安全补丁问题。
  • 运行环境要求提高到 Windows 10 1607 及以上(.NET 10 不再支持 Windows 7/8.1);安装器门槛同步抬高,
    Win7 机器请继续使用 4.0.x。
  • 程序仍为框架依赖部署:安装包内置 .NET 10 桌面运行时离线包,目标机缺失时自动静默安装(离线现场也能装)。

数据格式(自动迁移,无需人工操作)

  • 配置 / 模板 / 算法参数从老二进制格式改为 JSON(data\Config.dat、config_&lt;产品>.dat、Model.cfg、rule.cfg)。
    原因:老格式依赖的 BinaryFormatter 在新运行时已被移除。
  • 首次读取旧文件时自动迁移:先把原文件备份成 *.legacy.bak(只备份一次),再按新格式写回,并写系统日志。
    迁移已用现场真实数据验证(模板/算法/配置逐个逐字段比对一致,含图像模板的像素数据)。
  • 读不出来的文件不再被默认值覆盖:会先隔离为 *.&lt;时间戳>.unreadable,可人工找回。
  • ⚠️ 迁移后旧版本程序读不了新文件;如需回退旧版本,先把 *.legacy.bak 复制回原名。

加密保护

  • 已升级 SenseShield/Virbox Protector 并恢复最强加密(JIT 加密 + 镜像加密 + 反调试 + 授权运行库绑定),
    加壳产物经 --version / --graph-selfcheck / --persist-selfcheck 验证可正常运行。

升级方式说明

  • 本版在 version.txt 里写入 AppFramework=net10.0-windows,补丁清单里写入 framework/runtime:
    客户端升级器据此判定"换了 .NET 运行时、不可直升",自动改用同目录安装包——
    避免出现"打完补丁程序起不来"。4.0.x 的现场装一次本版安装包即可,之后补丁升级照旧。

4.0.23(2026-09-20)

新增

  • TCP 通讯(逻辑图节点 + 监视窗口):/通讯 分类新增 9 个节点,可与 MES/PLC/看板/称重仪表等外部系统
    自定义协议对接:TCP客户端连接 / TCP客户端断开 / TCP服务端启动 / TCP服务端停止 / TCP发送 / TCP等待接收 / TCP接收事件 / TCP自动应答 / TCP状态。
    • 客户端与服务端都能当,各支持多实例(用「设备名称」区分,改名自动跟随、跨 stn 同步);
      服务端允许多个客户端同时连接,可广播或按客户端编号 / IP 指定发送。
    • 协议自定义:结束符分帧(\r\n、\n 或自定义文本,支持 0D0A 这类 HEX 写法);
      没有结束符时按「静默超时」切包(默认 50ms,可配);文本编码 UTF-8 / ASCII / GBK;
      粘包自动拆帧、半包等待、超长帧丢弃告警。
    • 发送:内容支持 {变量} 占位符({pid:X2} 这类格式说明符也支持,拼 HEX 报文很方便),
      可选 HEX 原文发送、自动追加结束符、发送字节数写回变量。
    • 接收:TCP接收事件(无输入起点,收到即触发挂接子流程,两个输出端口「匹配 ▶ / 不匹配 ▶」可改名)
      与 TCP等待接收(一问一答协议用,收到走「收到 ▶」、超时走「超时 ▶」);载荷 tcp.data / tcp.hex / tcp.ip / tcp.port / tcp.bytes / tcp.time / tcp.count,勾「发布全局变量」即写 g.tcp.*。
    • 自动应答:TCP自动应答 节点一行一条规则(匹配=>回复,re: 前缀按正则,回复可用 {0}/{1} 捕获组
      与 {g.变量}),点运行即注册到对应实例,收到即回包,不用占用流程。
    • 📡 TCP 通讯监视窗口(Graph 标题栏菜单 + 主窗口「系统参数设置」下):实例连接状态/客户端数/待取帧数、
      收发日志(文本 + HEX、可暂停/清空/另存)、手动发测试帧。
  • FVT 编辑授权(子 stn 白名单 + 折叠分组锁定):FVT 厂家账户在主菜单「系统参数设置 → 逻辑图编辑授权…」
    按当前产品勾选:① 允许管理员/工程师打开的子流程 stn(未勾选即使被引用也拒绝);
    ② 允许管理员操作的折叠分组(未勾选在画布上不可选中/拖动/展开/删除/改名/单步,点了给提示,但仍照常参与运行)。
    授权表按产品目录保存(stn-permissions.xml,随产品目录一起拷走)。管理员自己折叠出来的分组默认归管理员开放;
    FVT 展开后重新折叠的分组按「同名唯一」自动继承授权。
  • 3D 线扫激光轮廓仪节点:新增 /硬件 下的轮廓仪连接/断开/采集/参数/预览节点与真机实现,
    与 2D 相机共用设备编号空间(2D/3D 混排同一列表),深度帧贯通到检测引擎(按图层 Ref3D/MaxHeight 归一化),
    既有「拍照点 / 图像缓存 / 图像处理」链路对 3D 设备零改动可用。
  • 节点属性表达式(=表达式):属性窗口里把值填成 =g.节拍ms、=speed*1.2、=count > 0 即按表达式求值,
    每个节点执行前用当时的变量重新计算并写回属性——循环体每圈、事件分支每次触发都取最新值;
    不填 = 仍是普通字面量(旧图行为不变)。

说明

  • 程序退出与关闭产品时会兜底释放全部 TCP 实例(客户端断开、服务端停止监听,端口不残留);
    点「停止」流程不会自动断开,按惯例由 hw.stn 的关闭分支或监视窗口手动断开。
  • GBK 编码依赖随包新增的 System.Text.Encoding.CodePages.dll(约 740KB),安装包/补丁自动带上。

4.0.22(2026-09-20)

修复

  • 逻辑图左右侧栏打不开(Graph):打开任意逻辑图时抛
    InvalidOperationException: SplitterDistance 必须在 Panel1MinSize 和 Width - Panel2MinSize 之间,
    右侧「节点列表」栏与左侧「节点树/属性」栏都无法显示。原因是划分左右栏的 SplitContainer
    在构造期(此时控件宽度还是默认 150)就设置了面板最小尺寸,WinForms 立即校验分割线位置而失败。
    现在面板最小尺寸与分割线位置一律延迟到控件有真实宽度后才应用(先把下限归零 → 定位分割线 →
    回设下限,全程容错);窗口缩放时保留已合法的手工分栏宽度,窄窗口下展开右侧栏也不会再抛异常。

4.0.21(2026-09-20)

新增

  • 📷 相机搜索(Graph):Graph 标题栏菜单与画布空白右键菜单都加了「📷 相机搜索…」,打开即自动扫描 MVS 相机
    (GigE + USB),列出 状态 / 名称(DeviceUserID) / 序列号 / 型号 / 接口 / 当前 IP / 掩码 / 网关,支持多选:
    • 改名与改静态 IP(两者都写):名称写进相机 DeviceUserID(并尽力 UserSetSave 掉电保留),
      IP/掩码/网关写相机静态 IP(MV_IP_CFG_STATIC + ForceIpEx,仅 GigE;USB 相机该项置灰);
      同时写一份上位机记录 data\cameracfg.xml(按序列号对齐,相机离线也能看到/预编辑),
      并登记到全局名称表——hw.stn/product.stn 的「设备名称」下拉立刻可选。改完名称/IP 自动刷新程序内相机枚举缓存,
      按新名称即可连接(否则会报「未找到相机」)。
    • 可连接判定:可连接 / 已被占用(本程序或其它程序在用,不抢占);「🔌 测试连接」= 打开→立即关闭,不长期占用、不预览。
    • 🧩 一键生成流程节点:勾选可连接的相机 → 每台生成一组「相机连接 → 相机断开」并自动连线
      (连接在上、断开在下),多台横向错开且自动避开已有节点,插入当前画布并选中;相机连接为真实模式、按名称连接。
    • 名称校验(非空、≤16 字节、不重名);改名前若当前画布已引用旧名会先确认(不会自动改画布里的旧引用)。
  • 逻辑图母版(stn 模板):母版库固定在 data\stn-templates\(hw\/product\/teach\ 按类型,sets\{套名}\ 为整套)。
    • 新建产品可弹窗选母版:三类各一个下拉(默认「空模板」),也可一键带出「整套母版」;未选/母版缺失按空 stn 建
      (hw 仍预置 init + 无名两个开始节点),套用 hw 母版后若缺名为 init 的开始节点会给提示。
    • Graph 标题栏菜单:加载母版到当前画布… / ✏ 编辑母版… / 💾 保存为母版… / 💾 保存整套母版… / 📂 打开母版目录;
      母版编辑窗口用独立窗口打开(母版文件名不是 hw/product/teach,菜单/权限按窗口类型判定);同名保存会提示覆盖或改名。
    • 发布:安装包 overlay 带 data\stn-templates 素材(仅全新安装时种入,升级与轻量补丁不覆盖现场母版)。

4.0.20(2026-09-20)

新增

  • 逻辑图「视图三件套」(Graph 窗口):
    • 右侧「节点列表」栏:按连通分组列出全部节点,支持排序/筛选/统计(节点数、孤立节点、分组数),
      与画布选中双向同步,点条目即定位到该节点;栏宽可拖、可折叠(宽度记忆)。
    • 右下角「鸟瞰图」:整图缩略 + 当前视口框,随画布缩放/平移实时更新,点击/拖动可直接跳转视野。
    • 左右侧栏显隐:Ctrl+B 切换(也能从「视图」菜单点),隐藏左侧节点树/属性列时画布占满整宽,
      显隐状态按会话记忆。
  • FVT 运控卡回零增强:
    • 反向回退脉冲数可按轴配置并下发(回零 0x03 的 backoff 参数,0=固件默认 2000),
      回零节点/示教面板回零共用同一份参数。
    • 回零参数可写板卡 Flash、可读回:⚙ 参数配置… 轴表新增「回退脉冲数」「回零参数来源」两列,
      并新增按钮 「保存回零参数到板卡Flash」(0x18 kind=1 + 0x1A)、「读取板卡回零参数」(0x05 STS_CONFIG 读回方向/速度/加速度/回退脉冲)。
      「回零参数来源=板卡」时回零下发 fast_vel=0 由固件取 Flash 参数;需固件 v2.4.11+(STS_CAPS bit15),
      老固件自动回退按上位机参数执行并告警一次。

改进

  • 运控卡示教面板速度档:档位改为 最低速 5% / 低速 20% / 中速 50% / 高速 80% / 超高速 100%,
    默认改为最低速 5%(原来默认 100% 超高速,示教时一点动就高速冲出);点按钮循环切档,
    走点/点动/整体走点都用当前档(速度=连接节点该轴最大速度×档位)。
  • 「单轴定点移动」节点标题:改为 {轴名}轴移动到{目标位置}(如 X轴移动到100、A·轴2移动到100.5),
    轴名取运控卡连接的轴表(无名称回退 轴N);改「轴编号/目标位置」标题即时刷新,设备名称前缀保持不变。

提示

  • 示教面板「示教」按钮会把当前速度档一并写进示教点位的速度(默认最低速 → 新示教点位速度为 5%);
    需要示教点位速度与面板档位脱钩请反馈。

4.0.19(2026-09-20)

新增

  • 属性面板「无效即灰显只读」:依赖条件不成立的属性不再隐藏——行保留、原值可见但点不动,
    面板底部说明区直接给出原因(如「当前「输出形式」= 开,不使用该属性」);切换驱动属性(如「输出形式」)后
    面板立即重建刷新。覆盖:输出(值/脉宽)、云台连接(云台类型)、云台走位(点位名称 ↔ 焦距/光圈/视野/水平/俯仰)、
    EtherCAT(写值/变量名/模式)、触发延时(脉宽/单位)、HDR(曝光时间)、
    显示刷新(产品号变量)、拍照点(触发方式/触发百分比/复位百分比/V2 六项/到位脉宽/运动方式/过渡半径)、
    筛选机(产品号起始)。节点上的「⇄ 切换为飞拍/静止」这类按钮改状态后也会请求面板刷新。
  • 比较输出 CMP0~7 支持改名:名称存在「运控卡连接」节点里(与轴/DI/DO 同一入口:⚙ 参数配置… 新增
    「比较输出名」8 行 + 前缀填充),随 .stn 与 data\cardcfg_{设备号}.xml 保存/导入,跨 stn 共享;
    输出节点标题、IO变化事件 下拉、运行日志里的通道名统一显示自定义名,未命名回退 CMP0~7。
    说明:CMP 名称仅用于上位机显示,不下发固件(卡名称表只有 DI/DO 两域)。
  • IO 名称下拉首项改为「✎ 改名/输入新名称…」:DI/DO/CMP 一致,改名/新建入口从列表末尾提到第一位
    (预填当前名,留空=不改)。

交互

  • 逻辑图节点编辑:Ctrl+A 全选、方向键移动选中节点、Ctrl+点击 切换选中、中键拖动平移时保持选中。

4.0.18(2026-09-20)

新增

  • 折叠分组「✏ 编辑分组(新窗口)…」:逻辑图里右键折叠分组节点即可在独立画布里编辑它的内部图——
    运行/停止/单步、属性面板、节点树、复制粘贴/连线与 product.stn 完全一致;保存=写回该分组节点(另存为禁用并提示)。
    • 内部图没有「开始」节点时,自动合成一个「(分组入口)」接到唯一无入边节点,方便窗口内直接运行;该合成节点不写回分组。
    • 内部节点被删除导致分组外部端点失效时:明确提示并断开该端点对应的外部连线(绝不静默丢线);保留端点重建端口后按原下标接回。
    • 分组编辑窗口内禁止再折叠(分组内部不支持嵌套分组写回,请改用「子 stn」)。
  • 节点「注释」属性(普通节点 + 折叠分组):填了注释后,节点底部按钮显示 ▶ 注释文字(不再显示「单步执行」四个字);
    注释过长按按钮宽度截断(末尾 …),随 .stn 持久化;留空则保持「▶ 单步执行」。

加固

  • 分组编辑写回、展开/折叠的"不丢线"保证继续生效(外部连线要么保留、要么显式提示断开)。

4.0.17(2026-09-19)

  • 相机预览「💾 存图」:节点按钮 + 右键「保存当前帧」手动存一张(文件名带相机名/时间戳,重复自动加序号);
    新增跨节点/跨画布重复存图告警(同相机 + 同保存路径被多个预览节点同时存图时提示,隐藏画布 + 逻辑图窗口双份是常见原因);面板日志接线。
  • 拍照元数据:拍照点新增显式相机引用「相机名称/相机编号」(机械臂编号不再需要等于相机编号);
    产品号来源优先级=拍照点「产品号变量」→ 该相机「图像缓存」节点登记的变量名;变量名 g. 开头时回退全局变量表最新值;
    未登记 / 取不到值时输出一次节流诊断,直接说明该去哪配。
  • 机械臂 DO→相机映射(ArmDoCameraRegistry / ArmDoCameraMap + 测试)。
  • 发布:三件套工具随包带最新 OTA 固件(缺失即失败);投放规则统一为「局域网共享 + 本地镜像 D:\work\publish」双投。
  • 安装包:data\log4net.config 缺失即补(老机器升级上来的目录从没种子过)。

4.0.16(2026-09-19)

  • 修复 ONNX CUDA 依赖预加载(按完整路径加载 {app}\Cuda 下 DLL,修复 GPU 推理 Failed to load shared library)。
  • 修复 BlobWnd emSize=0 字体异常(排版字体/MarkSize 未初始化)。

4.0.15(2026-09-18)

  • 全局变量表(g. 前缀):跨事件 / 跨分支 / 跨会话可见(进程级最新值);
    「变量设置」新增作用域(本分支 / 本分支加全局 / 仅全局);新增「全局变量写入」「全局变量读取」节点;
    7 个事件起点节点新增「发布全局变量」;「变量变化事件」可监视 g.*;新增全局变量窗口(查看/改值/清空,主菜单「参数设置 → 全局变量…」与画布右键)。
    使用说明见 docs/全局变量与相关节点使用说明.md。
  • 窗口热键:Alt+1 主界面、Alt+2 hw.stn、Alt+3 product.stn、Alt+4 teach.stn、Alt+5 子 stn 轮转
    (原 Alt+1..4 切换结果显示页签改为 Alt+Shift+1..4)。
  • 子流程:没有「开始」节点也能执行——自动取唯一无入边节点当入口(多个/环形/只有事件节点则报中文错误)。
  • 安装包修复:Inno Setup 的 {app} 常量过早展开导致"安装包一点就报 Runtime error",旧目录检测推迟到安装阶段。

4.0.13(2026-09-18)

  • 筛选机停止时比较输出支持「只清缓冲、不改引脚」(固件 v2.4.9 / STS_CAPS bit13)。

4.0.11(2026-09-18)

  • 子流程抽取隐式入口 + 事件起点契约 + 升级投放目录重构(子 stn 缺失自动建空、按引用递归收集)。

客户端在线升级(可选)

软件启动时会先检查局域网升级目录(厂内共享),检测不到时再访问官网升级源。若现场需要走官网升级, 在客户端设置环境变量 FVISION_UPDATE_URL 指向下面的地址即可:

https://cdn.fvision.tech/up/version.txt

排查命令:AreaAI.exe --check-update(局域网)、AreaAI.exe --check-update-online(官网)。