Table of Contents

HardNc → SoftNc 改寫進度報告

說明: 此頁為從最新 release note 連入的暫時性進度頁面。 內容描述進行中的改寫,未來可能重整、改置或移除,因此並未列入主導覽選單。

HiAPIs 的 NC 解譯器正從早期單體式 HardNcXxx 全面改寫為可重組(reconfigurable)的 SoftNcXxx pipeline。本頁說明改寫動機、架構轉變、目前完成度,以及剩餘工作。

Last Updated: 2026-04-26


1. Executive Summary

指標 內容
客戶需求 NC 解譯器需「Reconfigurable(可重組)」 — 不同廠牌、不同機械架構、不同 G/M code 集合,必須可由設定檔切換而不需重編譯。
改寫策略 將 3,000+ 行的 HardNcLine 單體類別解構為 ISegmenter + INcInitializer + 多層 INcSyntax + INcSemantic + INcDependency 五段 pipeline,全部以介面為主、可由 XML 序列化。
完成度估算 ISO 共通部分接近完成 — 主流 G/M code、modal 行為、ISO 座標系、刀具補償、CL/MC 兩段路徑、Cycle、G43.4 RTCP、G68/G68.2 傾斜、單位/暫停/冷卻、診斷系統皆已上線。其他廠牌(Siemens / Syntec / Mazak / Heidenhain)特定語法尚未深入盤點,不敢稱為接近完成。
仍未動工 (1) 程式呼叫 / 巨集 / 子程式(CALL, M98, LBL CALL) (2) 數學/邏輯函式(#var = expr, IF/GOTO/WHILE, Q-parameter 算式) (3) NcOptProc 模組(仍綁定舊 HardNcLine / HardNcEnv,尚未深入規劃)。
風險評估 程式呼叫 / 數學邏輯:低 — 可在現有 IExpandingNcSyntax / INcSyntax / INcDependency 介面下,以「新增實作」而非「改架構」的方式落地。NcOpt:不算低風險,仍有未知的設計工作待釐清。

Hard → Soft 不是改寫一個類別,而是把「規則寫在程式裡」搬成「規則寫在資料裡」。


2. 設計哲學:三大支柱

SoftNcRunner 的彈性奠基於三個彼此正交的設計原則。任何一條缺失,整個 pipeline 都會退化回 HardNcLine 那種「想改任何東西都要動到中央類別」的狀態。

2.1 XML-configurable — 結構即資料

SoftNcRunner 本身只是一個容器,內部 5 個 List 全部由 XML 載入:

<SoftNcRunner>
  <NcDependencyList>...</NcDependencyList>      <!-- 1. 依賴設定 -->
  <Segmenter>...</Segmenter>                     <!-- 2. 段落切分器 -->
  <NcInitializationList>...</NcInitializationList> <!-- 3. 初始化 -->
  <NcSyntaxList>...</NcSyntaxList>               <!-- 4. 語法層 -->
  <NcSemanticList>...</NcSemanticList>           <!-- 5. 語義層 -->
</SoftNcRunner>

每個 INcSyntax / INcSemantic / INcDependency 都實作 IMakeXmlSource,透過 XFactory.Regs.Add(XName, ...) 自動註冊。新增一個 G code 不需改 SoftNcRunner,只需新增一個 syntax class 並在 XML 加一行。

2.2 DataFlow-transparent — JSON 為共通通貨

每個 Sentence 通過 pipeline 時帶著一個 JsonObject,每一層 syntax 都是「讀某些鍵 → 寫某些鍵 → 移除已消費的鍵」。整段 dataflow 對外可序列化為 JSON,方便:

  • 除錯 — 可在任何一層之間印出 JSON snapshot 看狀態。
  • 測試 — unit test 可直接斷言 JSON 結構,不需 mock 整個 NcEnv。
  • 跨語言整合 — 未來若要做 Web API / Python binding,JSON 即現成傳輸格式。

JSON 鍵名採「Section + Term」雙層結構:section key 用語義名稱(UnitFeedrateMotion ...)跨廠牌一致;NC 代碼實際關鍵字(G21 / G94 / G01、Heidenhain BLK FORM / LBL / PGM 等)放在子物件的 Term 欄位以保留與原始 NC 的對應。

範例 — 一行 NC block 的 JSON 結構

原始 NC(Fanuc 風格):

N162 X-14.696 Y-6.42 Z45.638

該 block 通過 pipeline 後的 SyntaxPiece.JsonObject 內容(截自實機輸出,矩陣數值省略):

{
  "IndexNote": {"Symbol":"N","Number":162},
  "Positioning": {"Term":"G90","Mode":"Absolute"},
  "Unit": {"Term":"G21","System":"Metric"},
  "PlaneSelect": {"Term":"G17","Plane":"XY"},
  "Feedrate": {"FeedrateValue":400,"Term":"G94","Unit":"mm/min"},
  "SpindleSpeed": {"SpindleSpeed_rpm":20000,"Direction":"CW"},
  "Coolant": {"IsOn":true,"Mode":"Flood"},
  "ToolChange": {"ToolId":4,"IsChange":false},
  "TiltTransform": {"Term":"G68.2"},
  "EndPointProgramToMcTransform": [
    {"Source":"TiltTransform",          "Mat4d":[ /* 16 doubles */ ]},
    {"Source":"ToolHeightCompensation", "Mat4d":[ /* 16 doubles */ ]},
    {"Source":"CoordinateOffset",       "Mat4d":[ /* 16 doubles */ ]},
    {"Source":"PivotTransform",         "Mat4d":[ /* 16 doubles */ ]}
  ],
  "ToolHeightCompensation": {"Offset_mm":16,"Term":"G43","OffsetId":4},
  "CoordinateOffset": {"CoordinateId":"G54","Offset_X":72.4,"Offset_Y":-72.4,"Offset_Z":-116.44},
  "ProgramXyz": {"X":-14.696,"Y":-6.42,"Z":45.638},
  "MachineCoordinate": {"X":140.5947...,"Y":-78.8200...,"Z":-124.4559...},
  "MotionState": {"Term":"G01"},
  "MotionEvent": {"Form":"McLinear","IsRapid":false},
  "RadiusCompensation": {"Term":"G40","OffsetId":0,"Radius_mm":0}
}

幾點觀察:

  • 每一個區塊(Positioning, Feedrate, Coolant, ToolChange, ...)都是某一個 syntax 的輸出 — 例如 Feedrate 來自 FeedrateSyntaxMachineCoordinate 來自 McXyzSyntax
  • ProgramXyzMachineCoordinate 並陳:原始 NC 寫的是程式座標,pipeline 終點同時保留兩者,方便 UI / 報表選用。
  • EndPointProgramToMcTransform 把 Program → MC 的成因鏈攤平為四段(Tilt、ToolHeight、CoordinateOffset、Pivot),每段附上來源變換矩陣 — 若 MC 結果不如預期,看這個陣列就知道是哪一段補正在作怪,不需重跑除錯器。
  • modal 狀態(Unit / Positioning / PlaneSelect / 等)即使這一行沒有顯式寫出,也會被前一節的 modal lookback 帶到此處,確保每個 block 的 JSON 都是自足的。

2.3 Interface-based — 消費者導向依賴

舊系統的 HardNcEnv 是一個 God Object — 上百個欄位塞在一起,修改任何一個都可能波及無關的 syntax。新系統反過來:每個 syntax 自己宣告需要什麼介面,由 NcDependencyList.OfType<T>() 拉取:

// 範例:G28 ReferenceReturnSyntax 需要 home 座標
var homeConfig = ncDependencyList.OfType<IHomeMcConfig>().FirstOrDefault();

依賴設定本身也是物件,只要實作對應介面即可注入。新增廠牌只需新增一個 XxxParameterTable : ControllerParameterTableBase


3. 架構對照圖

3.1 舊架構(HardNc)

graph TD
    A[NC raw lines] --> B[HardNcRunner]
    B --> C[new HardNcLine ctor]
    C --> D[HardNcEnv God Object<br/>~80 fields, 4 brands hard-coded]
    C --> E[NcProc.GetActs]
    D -.coupled.-> C
    D -.coupled.-> E
    E --> F[IAct stream]

    style D fill:#fdd,stroke:#c33,color:#000
    style C fill:#fdd,stroke:#c33,color:#000

痛點:

  • HardNcLine 建構子 = 解析 + modal 累計 + MC 計算 + 補償,全部混在 3,000 行內。
  • HardNcEnv 包含所有廠牌設定,CncBrand 切換時用 if/switch 在內部分流。
  • 新增廠牌 / 自訂語法 = 修改 HardNcLineHardNcEnvNcProc 三處。
  • HardNcLine 同時是資料載體、解析狀態機、輸出來源 — 無法在管線中插入第三方步驟。

3.2 新架構(SoftNc)

graph TD
    A[NC raw lines] --> SEG[ISegmenter]
    SEG --> SENT[Sentence stream]
    SENT --> INIT[INcInitializer<br/>HomeMc / Static]
    INIT --> P[ParsingSyntaxs<br/>Layer 1]
    P --> L1[LogicSyntaxs Layer 2<br/>ProgramXyz / McXyz / Motion]
    L1 --> L2[LogicSyntaxs Layer 3<br/>McAbcCyclic / Cleanup]
    L2 --> POST[PostSyntaxs<br/>Cache / Snapshot]
    POST --> SEM[INcSemantic<br/>→ IAct]
    SEM --> OUT[SourcedActEntry]

    DEP[INcDependency List<br/>BrandTable / IsoCoord / ToolOffset / ...]
    DEP -. injected .-> P
    DEP -. injected .-> L1
    DEP -. injected .-> L2
    DEP -. injected .-> SEM

    style P fill:#dfd,stroke:#393,color:#000
    style L1 fill:#dfd,stroke:#393,color:#000
    style L2 fill:#dfd,stroke:#393,color:#000
    style POST fill:#dfd,stroke:#393,color:#000
    style SEM fill:#dfd,stroke:#393,color:#000

每一層的「步驟個數、順序、實作類別」都由 XML 決定。新增 G code = 新增一個 syntax 並在 XML 中插入;汰除舊 G code = 從 XML 拿掉那一行。


4. 元件對照表

角色 HardNc SoftNc 進度
主 Runner HardNcRunner(約 165 行) SoftNcRunner(約 870 行,純編排) 已完成
設定容器 HardNcEnv(約 571 行 God Object) List<INcDependency> 多介面 已完成
NC 行物件 HardNcLine(約 3,118 行) Sentence + SyntaxPiece(JsonObject) 已完成
段落切分 寫死於 HardNcRunner.BuildNcLinesByRawNcLines ISegmenter(3 種實作) 已完成
初始化 RefNcLineOnInit 隱式 INcInitializer 顯式(2 種實作) 已完成
文字解析 HardNcLine 建構子內 regex ParsingSyntaxs/(約 15 種,寫入 Parsing 已完成
Modal / 跨行邏輯 HardNcLinelast: 參考 LogicSyntaxs/(約 36 種,跨節點 lookback) 已完成
廠牌專屬語法 if (CncBrand == ...) 內聯 XxxSyntaxUtil.DefaultSyntaxList 五份 ISO 共通已完成;廠牌特定進行中
Cycle 處理 HardNcLine.cs 內函式群 BoringCycleSyntax / DrillingCycleSyntax / CannedCycleResolveSyntax 已完成
座標系 / 偏移 HardNcEnv.IsoCoordinateTable 等欄位 IsoCoordinateTable / HeidenhainDatumTable / ToolOffsetTable 介面 已完成
廠牌參數表 HardNcEnv.ConfigurationTable 字典 FanucParameterTable / SyntecParameterTable / SiemensMachineDataTable / HeidenhainParameterTable(繼承 ControllerParameterTableBase 已完成
行程界限 HardNcEnv.CheckStrokeLimit IStrokeLimitConfig + StrokeLimitCheckSemantic 已完成
動作輸出 NcProc.GetActs INcSemantic.Resolve(12 種) 已完成
診斷 sessionProgress.ReportError 字串 NcDiagnosticProgress 結構化(severity / category / ID / sentence) 已完成
Cs Script HardNcUtil.GetSimCsScript 字串切割 CsScriptSyntax + CsScriptBeginSemantic / CsScriptEndSemantic 已完成
子程式 / CALL HardNcLine 內部分支處理 IExpandingNcSyntax 介面已備好,待建構 待建構
數學 / 邏輯函式 HardNcLineIsoNC_Proc P/Invoke 待建構 待建構
NcOpt 模組 HardNcLine / HardNcEnv 待建構 待建構

5. 進度狀態

5.1 已完成 — 主路徑全綠

ISO 共通部分皆已就緒:三層 INcSyntax 架構、INcSemantic 動作輸出、INcDependency 注入、廠牌參數表、ISO Logic Syntax、Motion + Compound Motion + Spindle 語義、 Canned Cycle G73–G89、Group-09 Cycle modal 狀態管理、G41/G42 Radius Compensation、 G68/G68.2/G69 傾斜、G43.4 RTCP、G53/G53.1、Mc ABC 旋轉軸最短路徑、ProgramXyz 追蹤、 ISO Coordinate Table 字串 key 遷移、Block Skip 多層管控、Unit / ProgramStop / Coolant Mist、G28 / Comment / CncBrand / 版本 / CsScript、Cache Syntax(modal lookback O(N·Pace))、結構化 NcDiagnosticProgress 診斷、LocalProjectService / MachiningProject 整合,以及 SessionShell Session Events。

5.2 仍未動工

5.2.1 各廠牌特定語法尚未深入盤點

ISO 共通部分接近完成;但每個廠牌都有大量自有語法尚未動工,下表僅是樣本:

廠牌 待動工樣本
Fanuc Custom Macro B 細節、G10 Programmable Data Setting、G50 主軸限制、G31 Skip、Polar 完整支援
Siemens TRAORI / TRAFOOFCYCLE800 傾斜、MSG / STOPRE、Frame 體系(TRANS / ROT / SCALE / MIRROR)、GUD/PUD 變數、SETAL 警報
Syntec 自訂 G 巨集、Pr 系列參數對應、雙頭 / 雙刀塔語法
Mazak Mazatrol 對話式區段、MAZATROL ↔ EIA/ISO 切換、Mazak 特有 G/M 號碼差異
Heidenhain FK Free Contour、SL Cycle、PATTERN DEFTCH PROBE 量測循環、TOOL DEF / TOOL CALL 進階欄位、PLANE 完整 7 種模式

架構上不需改 pipeline;新增廠牌語法 = 新增 INcSyntax 實作 + 註冊 + 加入該廠牌 XxxSyntaxUtil.DefaultSyntaxList。但實作數量大,需依客戶優先序逐項展開。

5.2.2 程式呼叫 — subprogram / macro call

對象 描述
ISO M98 P_ L_ / M99 Fanuc / Syntec / Mazak 子程式呼叫與返回
Heidenhain LBL <n> / CALL LBL <n> REPn 標籤定義與重複呼叫
Heidenhain PGM CALL "<file>" 外部檔案呼叫
Siemens <name> 子程式 自訂子程式名稱呼叫

IExpandingNcSyntax.Expand() 介面正是為此設計 — 允許一個 SyntaxPiece 在管線中被展開為多個。已有 HeidenhainCallSyntaxHeidenhainLblSyntax 在 ParsingSyntax 層解析出 Parsing.CALL / Parsing.LBL 結構但尚未連到 expander。

5.2.3 數學 / 邏輯函式(macro / control flow)

對象 描述
Fanuc Custom Macro B #100=...IF [...] GOTO nWHILE [...] DO n / END n
Heidenhain Q-Parameter Q1 = Q2 + Q3FN0 ~ FN26IF Q1 EQU 0 GOTO LBL
Siemens R-parameter / GUD R1 = R2 * SIN(R3)IF / GOTOB / GOTOF

HeidenhainFnAssignmentSyntaxNamedVarAssignmentSyntax 已能將指派寫入 JSON;但 expression evaluator、條件跳轉、迴圈展開尚未實作。

5.2.4 NcOpt 模組重寫

目前 Hi.NcOptNcOptProcNcOptOption)仍綁定舊系統:透過 HardNcLine 鏈結串列做最佳化(feedrate、深度切分、加速度限制等)。此模組尚未深入規劃,仍可能有未知工作量需釐清。


6. 客戶可重組性(Reconfigurable)展示

新系統下,下列三類客製化全部 不需重編譯

6.1 切換廠牌(內建 5 組 preset)

var runner = SoftNcRunner.HeidenhainNcRunner;
runner.ConfigureByMachiningChain(machine.Chain);

亦可由 XML 載入由專案反序列化挑選。詳見 SoftNcRunner

6.2 客製某廠牌特定語法(不影響其他廠牌)

例如某客戶 Fanuc 機台用了非標準 M168 進行夾具控制:

  1. 新增一個 MyClampMSyntax : ISituNcSyntax 類別。
  2. 在客戶專案的 SoftNcRunner XML 中插入一行 <MyClampMSyntax/>
  3. 不需改動 HiAPIs 任何原始檔。

6.3 跨廠牌共用機構配置

ConfigureByMachiningChain 把機台軸序、旋轉軸 / 線性軸區分、NcKinematicsDependency 的注入交由 IMachiningChain 驅動 — 5 軸機、4 軸機、雙轉台都共用同一條程式路徑。


7. 過渡相容性

為了不破壞既有客戶專案:

機制 位置 用途
FromLegacyNcEnvXml SoftNcRunnerLegacy HardNcEnv XML support 區段 讀舊 HardNcEnv XML 自動建構 SoftNcRunner
XFactory.Regs.Add("NcEnv", ...) HardNcEnv 靜態建構子 舊 XML key NcEnv 也能載入
ApplyLegacyVersionPatches SoftNcRunner ProjectApiVersion 補上後續版本新增的 syntax/semantic(3.1.163 起 4 道補丁)
EnableSoftNcRunner SessionShell 客戶可在 script 中切換新舊 runner 比對結果