You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
haoliang-net/docs/07-发那科数据结构变更调整方案.md

19 KiB

发那科采集数据结构变更 - 系统调整方案

创建时间2026-05-11 触发原因:发那科系统采集示例文件(根目录 发那科系统采集示例.txt更新实际FANUC采集数据结构与系统原有设计存在差异 涉及模块CncSimulator模拟器、数据库设计、采集服务设计、后台管理功能


一、实际FANUC数据结构2026-05-11 采自生产环境)

1.1 顶层结构

[
  {
    "device": "fanake-1.2_1.2",   // 设备编码,匹配 cnc_machine.device_code
    "desc": "西-1.2",              // 设备描述
    "tags": [ ... ]                // 10个Tag
  },
  ...
]

共32台设备每台10个Tag。其中25台在线、7台离线。

1.2 Tag清单10个

# Tag ID desc中文 类型 示例值 备注
1 _io_status 设备状态 数值 0.00000 / 1.00000 0=离线, 1=在线;始终有效
2 Tag5 执行的NC主程序名 字符串 O1, O9001, 1370.NC, 7, 1027, O2, 037.NC 可为空
3 Tag6 执行的NC主程序号 字符串 N0, N1, N9, N20
4 Tag7 当前加工程序内容 字符串 G代码片段 可为空
5 Tag8 当前加工零件数 数值 35.00000 当前程序的零件计数
6 Tag9 运行状态 数值 0.00000 / 1.00000 / 3.00000 0=待机, 1=运行, 3=加工中
7 Tag11 操作模式 数值 1 / 4 / 5 / 10 1=MEM, 4=?, 5=?, 10=JOG
8 Tag22 开机时间 数值 45129840.00000 秒,历史累计
9 Tag23 运行时间 数值 12201.00000 秒,历史累计
10 Tag1 加工零件总数 数值 45930.00000 历史终身累计,新增字段

1.3 数据有效性规则

规则1Quality字段

quality值 含义 处理方式
"0" 数据有效 正常解析
"1" 数据无效(采集失败/设备离线) 忽略该tag的value

规则2Time字段采集失败标记

time值 含义 处理方式
1970-01-01 08:00:00 采集失败 忽略该tag的value
其他正常时间 数据时间戳 正常使用

规则3_io_status 特殊处理

_io_status tag 不受规则1和规则2约束始终读取value判断设备在线/离线:

  • 即使设备离线,_io_status 的 quality=0、time=真实时间、value=0

规则4Time与Value独立变化

每个tag的 timevalue 更新频率不固定:

  • time变了、value没变
  • value变了、time没变
  • 都变了
  • 都没变

采集服务的变更检测必须对比value值不能依赖time变化作为变更信号。

1.4 离线设备特征

以 fanake-1.10 为例:

_io_status: quality=0, value=0.00000, time=2026-05-11 17:06:34   ← 始终有效
Tag5:       quality=1, value="",       time=1970-01-01 08:00:00  ← 无效
Tag6:       quality=1, value="",       time=1970-01-01 08:00:00  ← 无效
Tag7:       quality=1, value="",       time=1970-01-01 08:00:00  ← 无效
Tag8:       quality=1, value=0.00000,  time=1970-01-01 08:00:00  ← 无效
Tag9:       quality=1, value=0.00000,  time=1970-01-01 08:00:00  ← 无效
Tag11:      quality=1, value=0.00000,  time=1970-01-01 08:00:00  ← 无效
Tag22:      quality=1, value=0.00000,  time=1970-01-01 08:00:00  ← 无效
Tag23:      quality=1, value=0.00000,  time=1970-01-01 08:00:00  ← 无效
Tag1:       quality=1, value=0.00000,  time=1970-01-01 08:00:00  ← 无效

二、与现有设计的差异对比

2.1 模拟器FanucDataGenerator差异

差异项 现有模拟器18个Tag 实际FANUC10个Tag 影响
Tag2 (当前轴数) 不存在 模拟器多余
Tag14 (主轴倍率) 不存在 模拟器多余
Tag17 (主轴设定速度) 不存在 模拟器多余
Tag18 (进给设定速度) 不存在 模拟器多余
Tag19 (主轴实际速度) 不存在 模拟器多余
Tag20 (进给实际转速) 不存在 模拟器多余
Tag21 (主轴负载) 不存在 模拟器多余
Tag24 (切削时间) 不存在 模拟器多余
Tag25 (循环时间) 不存在 模拟器多余
Tag26 (加工状态) 不存在 模拟器多余
Tag1 (加工零件总数) 缺少 模拟器缺少,需新增
Tag6 desc "执行的NC主程序号" "执行的NC主程序号" 一致

2.2 数据库设计差异

差异项 现有设计 实际需求
标准字段 total_part_count 需要新增对应Tag1
cnc_collect_record.total_part_count 需要新增列
cnc_machine.last_total_part_count 需要新增列

2.3 采集服务设计差异

差异项 现有设计假设 实际行为
数据有效性判断 未明确quality处理 需按quality+time双规则过滤
_io_status处理 未明确特殊性 始终有效不受quality/time约束
变更检测 未明确time/value独立性 必须对比value不看time
Tag1(总零件数) 无此字段 需解析并存储

2.4 后台管理差异

差异项 现有设计 实际需求
速度/倍率/负载字段 设计了展示 FANUC设备这些字段为NULL需处理空值
加工零件总数 未设计展示 可选展示
操作模式枚举 仅定义1=MEM, 10=JOG 实际还有4、5值需补充定义

三、调整方案

3.1 CncSimulator 模拟器调整(优先级:高)

目标让模拟器生成的数据结构与实际FANUC完全一致

3.1.1 DeviceState.cs 修改

  public class DeviceState
  {
      // ===== 固定信息(来自配置) =====
      public string DeviceCode { get; set; }
      public string Desc { get; set; }

      // ===== 动态状态 =====
      public string CurrentScenario { get; set; } = "idle";
      public bool IsOnline { get; set; } = true;
      public string ProgramName { get; set; } = "O0001";
      public int PartCount { get; set; } = 0;
+     /// <summary>历史终身累计零件总数对应Tag1</summary>
+     public decimal TotalPartCount { get; set; } = 0;
      public int DeviceStatus { get; set; } = 1;
      public int RunStatus { get; set; } = 0;
      public int OperateMode { get; set; } = 1;
-     public decimal SpindleSpeedSet { get; set; } = 450;
-     public decimal FeedSpeedSet { get; set; } = 60;
-     public decimal SpindleSpeedActual { get; set; } = 0;
-     public decimal FeedSpeedActual { get; set; } = 0;
-     public decimal SpindleLoad { get; set; } = 0;
-     public decimal SpindleOverride { get; set; } = 100;
      public decimal PowerOnTime { get; set; } = 0;
      public decimal RunTime { get; set; } = 0;
-     public decimal CuttingTime { get; set; } = 0;
-     public decimal CycleTime { get; set; } = 0;
-     public string MachiningStatus { get; set; } = "";
      public string ProgramContent { get; set; } = "";
      // ... 其余字段保留不变
  }

说明移除实际FANUC不存在的字段SpindleSpeedSet、FeedSpeedSet、SpindleSpeedActual、FeedSpeedActual、SpindleLoad、SpindleOverride、CuttingTime、CycleTime、MachiningStatus新增TotalPartCount。

3.1.2 FanucDataGenerator.cs 修改

  private JArray GenerateTags(DeviceState state)
  {
      var tags = new JArray();
      DateTime baseTime = DateTime.Now;

      // 每个tag的时间基准上随机偏移 -5~0 秒
      DateTime TagTime()
      {
          return baseTime.AddSeconds(-_rng.Next(0, 6));
      }

      void AddNumericTag(string id, string desc, decimal value) { /* 不变 */ }
      void AddStringTag(string id, string desc, string value) { /* 不变 */ }

-     // 18个tag → 10个tag与实际FANUC完全一致
      AddNumericTag("_io_status", "设备状态", state.DeviceStatus);
-     AddNumericTag("Tag2", "当前轴数", 4);
+     AddNumericTag("Tag1", "加工零件总数", state.TotalPartCount);
      AddStringTag("Tag5", "执行的NC主程序名", state.ProgramName);
      AddStringTag("Tag6", "执行的NC主程序号", "N0");
      AddStringTag("Tag7", "当前加工程序内容", /* ... */);
      AddNumericTag("Tag8", "当前加工零件数", state.PartCount);
      AddNumericTag("Tag9", "运行状态", state.RunStatus);
      AddNumericTag("Tag11", "操作模式", state.OperateMode);
-     AddNumericTag("Tag14", "当前主轴倍率", state.SpindleOverride);
-     AddNumericTag("Tag17", "主轴设定速度", state.SpindleSpeedSet);
-     AddNumericTag("Tag18", "进给设定速度", state.FeedSpeedSet);
-     AddNumericTag("Tag19", "主轴实际速度", state.SpindleSpeedActual);
-     AddNumericTag("Tag20", "进给实际转速", state.FeedSpeedActual);
-     AddNumericTag("Tag21", "主轴负载", state.SpindleLoad);
      AddNumericTag("Tag22", "开机时间", state.PowerOnTime);
      AddNumericTag("Tag23", "运行时间", state.RunTime);
-     AddNumericTag("Tag24", "切削时间", state.CuttingTime);
-     AddNumericTag("Tag25", "循环时间", state.CycleTime);
-     AddStringTag("Tag26", "加工状态", state.MachiningStatus);

      return tags;
  }

3.1.3 DeviceSimulator.cs 修改

  • 构造函数:新增 TotalPartCount 初始值配置从simulator.json读取
  • machining 场景:TotalPartCount++
  • ApplyProgramChange()TotalPartCount 不清零(终身累计)
  • ApplyManualReset()TotalPartCount 不清零
  • ApplyPowerOn()TotalPartCount 不清零
  • 移除所有已删除字段SpindleSpeed*、SpindleLoad、SpindleOverride、CuttingTime、CycleTime、MachiningStatus的模拟逻辑

3.1.4 simulator.json 修改

devices配置中新增 initialTotalPartCount 字段:

{
  "deviceCode": "CNC-A001",
  "desc": "西栋1号",
  "initialProgram": "O0001",
  "initialPartCount": 50,
  "initialTotalPartCount": 45000
}

3.1.5 模拟器离线行为

当设备断电power_off需要生成与实际一致的离线数据

  • _io_statusquality=0, value=0, time=当前时间
  • 其他所有tagquality=1, value="" 或 "0.00000", time="1970-01-01 08:00:00"

3.2 数据库设计调整(优先级:高)

3.2.1 cnc_brand_field_mapping 标准字段约定

docs/01-数据库设计.md 的标准字段约定表中新增:

standard_field 含义 data_type
total_part_count 历史累计加工零件总数 number

3.2.2 cnc_collect_record 表

新增列:

ALTER TABLE cnc_collect_record
  ADD COLUMN total_part_count DECIMAL(15,5) NULL COMMENT '历史累计加工零件总数'
  AFTER part_count;

完整DDL变更位置part_count 列之后增加 total_part_count 列。

3.2.3 cnc_machine 表

新增列:

ALTER TABLE cnc_machine
  ADD COLUMN last_total_part_count DECIMAL(15,5) NULL COMMENT '最新历史累计加工零件总数'
  AFTER last_part_count;

3.2.4 FANUC品牌预置映射数据

database/ 预置数据脚本中FANUC品牌的 field_mapping 新增一行:

brand_id standard_field field_name match_by data_type is_required
(FANUC) total_part_count Tag1 id number 0

同时以下标准字段在实际FANUC中不存在映射记录应标记 is_required=0 或不创建映射(由采集服务按实际数据决定):

  • spindle_speed_set → 无对应Tag
  • feed_speed_set → 无对应Tag
  • spindle_speed_actual → 无对应Tag
  • feed_speed_actual → 无对应Tag
  • spindle_load → 无对应Tag
  • spindle_override → 无对应Tag
  • cutting_time → 无对应Tag
  • cycle_time → 无对应Tag
  • machining_status → 无对应Tag

3.3 采集服务设计调整(优先级:高)

3.3.1 采集循环核心逻辑(伪代码)

每次采集循环(按采集地址配置的间隔):

1. Ping目标地址
   - Ping失败 → 更新 cnc_collect_address.fail_count++
   - 连续5次失败 → 写告警
   - 跳过本次采集

2. HTTP GET 拉取JSON数组

3. 原始JSON存日志库cnc_raw_log每次都存不管有没有变化

4. 逐设备处理JSON数组中的每个元素

   4.1 用 device 值匹配 cnc_machine.device_code
       - 未匹配到 → 记录告警"发现未知设备",跳过

   4.2 解析 _io_status特殊处理
       → 直接读取 value不管 quality 和 time
       → value=1 → 设备在线
       → value=0 → 设备离线

   4.3 解析其他tag标准处理
       for each tag in tags (排除 _io_status):
         if tag.quality != "0"               → 跳过(数据无效)
         if tag.time 以 "1970-01-01" 开头     → 跳过(采集失败)
         否则 → 按 brand_field_mapping 映射为标准字段,解析 value

   4.4 写入结构化采集记录:
       → INSERT INTO cnc_collect_record (每台设备每次采集一条)
       → total_part_count 列写入 Tag1 的值(如果有效)
       → 速度/倍率/负载等字段写 NULLFANUC无此数据

   4.5 业务变更检测(只对比 value不看 time

       a. NC程序名变更检测
          if 新Tag5.value != 旧 cnc_machine.last_program_name:
              → 结账当前产量段 (close_reason='program_change')
              → 开新产量段

       b. 零件数下降检测(手动清零):
          if 新Tag8.value < 旧 cnc_machine.last_part_count
             AND 新Tag5.value == 旧 cnc_machine.last_program_name:
              → 结账当前产量段 (close_reason='manual_reset')
              → 开新产量段part_count 从新值开始

       c. 运行状态变更:
          if 新Tag9.value != 旧 cnc_machine.last_run_status:
              → 仅更新实时状态,不触发产量段逻辑

       d. 总零件数:仅记录,不触发任何业务逻辑

   4.6 更新机床实时状态cnc_machine 的 last_* 字段):
       → last_program_name = Tag5.value
       → last_part_count = Tag8.value
       → last_total_part_count = Tag1.value
       → last_run_status = Tag9.value
       → last_operate_mode = Tag11.value
       → last_device_status = _io_status.value
       → is_online = (_io_status.value == 1)
       → last_collect_time = 当前服务器时间

5. 更新采集地址状态:
   → last_collect_time = 当前时间
   → last_collect_status = 'success'
   → fail_count = 0

3.3.2 数据有效性判断流程图

收到一个tag
    │
    ├── tag.id == "_io_status" ?
    │       ├── YES → 始终有效,直接读 value
    │       └── NO  → 进入标准判断 ↓
    │
    ├── tag.quality != "0" ?
    │       ├── YES → 无效,跳过
    │       └── NO  → 继续判断 ↓
    │
    └── tag.time 以 "1970-01-01" 开头 ?
            ├── YES → 无效,跳过
            └── NO  → 有效,解析 tag.value

3.4 后台管理功能调整(优先级:中)

3.4.1 设备状态展示

cnc_machine 表已有 last_device_statuslast_run_status 等字段,展示逻辑不变。新增:

  • 设备详情中可选展示"累计加工总数"(来自 last_total_part_count

3.4.2 大屏看板空值处理

FANUC设备的以下字段恒为NULL

  • 主轴设定速度、进给设定速度
  • 主轴实际速度、进给实际速度
  • 主轴负载、主轴倍率
  • 切削时间、循环时间
  • 加工状态

大屏如果展示这些指标:

  • 数值型 → 显示 --N/A
  • 图表型 → 该FANUC设备的线不画

3.4.3 品牌字段映射管理

映射配置页面需支持新增的 total_part_count 标准字段。FANUC品牌预置映射中需包含 Tag1 → total_part_count

3.4.4 前端Mock数据同步

前端Mock数据中与FANUC相关的设备状态Mock应同步为10个Tag的字段集移除速度/负载等新增total_part_count


3.5 设计文档更新(优先级:中)

文档 更新内容
docs/01-数据库设计.md 标准字段约定表增加 total_part_countcnc_collect_record 和 cnc_machine 的DDL增加新列
docs/00-需求与设计文档.md 4.2数据格式章节补充quality/1970-time/Tag1说明
docs/03-API接口设计.md 如果有涉及采集记录字段的API响应格式需同步增加 total_part_count
database/ ALTER TABLE脚本 + FANUC预置映射数据新增

四、不需要调整的部分

项目 原因
顶层JSON结构 [{device, desc, tags}] 实际数据与设计一致
device字段匹配机床逻辑 设计正确device值匹配device_code
零件分段计数核心逻辑基于Tag8 不受影响仍基于NC程序名切换+清零
产量分段记录表 cnc_production_segment 结构不变total_part_count不影响分段计算
采集地址/品牌管理配置架构 不变
双库分离设计原始JSON存日志库 不变
采集间隔配置(地址级统一间隔) 不变
日终汇总逻辑 不变

五、执行顺序

阶段1模拟器适配让测试数据与实际一致
  ├── 1.1 DeviceState.cs 新增 TotalPartCount移除多余字段
  ├── 1.2 FanucDataGenerator.cs 改为10个Tag
  ├── 1.3 DeviceSimulator.cs 调整场景逻辑
  ├── 1.4 simulator.json 新增 initialTotalPartCount
  └── 1.5 编译验证

阶段2数据库变更数据基础
  ├── 2.1 cnc_collect_record 增加 total_part_count 列
  ├── 2.2 cnc_machine 增加 last_total_part_count 列
  ├── 2.3 标准字段约定表增加 total_part_count
  ├── 2.4 FANUC预置映射数据增加 Tag1 映射
  └── 2.5 设计文档同步更新

阶段3采集服务设计定稿核心逻辑
  ├── 3.1 编写采集服务数据解析逻辑含quality/time过滤
  ├── 3.2 编写变更检测逻辑只看value不看time
  └── 3.3 编写Tag1存储逻辑total_part_count仅记录不触发业务

阶段4后台管理适配展示层
  ├── 4.1 大屏空值处理FANUC设备速度/负载为NULL时显示N/A
  ├── 4.2 前端Mock数据同步为10个Tag结构
  └── 4.3 品牌映射管理支持total_part_count字段

六、补充说明

6.1 操作模式枚举值

实际数据中出现了以下操作模式值,具体含义需与现场确认:

已知含义 出现设备
1 MEM内存运行 加工中的设备
4 待确认 fanake-1.19(运行状态=1
5 待确认 fanake-1.24(运行状态=0
10 JOG手动 待机中的设备

6.2 device字段格式

实际数据格式为 fanake-1.2_1.2(品牌-编号_编号机床表的 device_code 需按此格式录入。

6.3 数值精度

所有数值型Tag的value都带5位小数35.00000),采集服务解析时需 Convert.ToDecimal 后存储到 DECIMAL(15,5) 列。

6.4 time字段格式

统一格式 yyyy-MM-dd HH:mm:ss,需要按此格式解析。设备离线时为 1970-01-01 08:00:00UTC+8时区下的epoch时间