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 用語義名稱(Unit、Feedrate、Motion ...)跨廠牌一致;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來自 FeedrateSyntax,MachineCoordinate來自 McXyzSyntax。 ProgramXyz與MachineCoordinate並陳:原始 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 在內部分流。
- 新增廠牌 / 自訂語法 = 修改 HardNcLine、HardNcEnv、NcProc 三處。
- 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 / 跨行邏輯 | HardNcLine 內 last: 參考 |
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 介面已備好,待建構 | 待建構 |
| 數學 / 邏輯函式 | HardNcLine 內 IsoNC_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 / TRAFOOF、CYCLE800 傾斜、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 DEF、TCH 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 在管線中被展開為多個。已有 HeidenhainCallSyntax、HeidenhainLblSyntax 在 ParsingSyntax 層解析出 Parsing.CALL / Parsing.LBL 結構但尚未連到 expander。
5.2.3 數學 / 邏輯函式(macro / control flow)
| 對象 | 描述 |
|---|---|
| Fanuc Custom Macro B | #100=...、IF [...] GOTO n、WHILE [...] DO n / END n |
| Heidenhain Q-Parameter | Q1 = Q2 + Q3、FN0 ~ FN26、IF Q1 EQU 0 GOTO LBL |
| Siemens R-parameter / GUD | R1 = R2 * SIN(R3)、IF / GOTOB / GOTOF |
HeidenhainFnAssignmentSyntax 與 NamedVarAssignmentSyntax 已能將指派寫入 JSON;但 expression evaluator、條件跳轉、迴圈展開尚未實作。
5.2.4 NcOpt 模組重寫
目前 Hi.NcOpt(NcOptProc、NcOptOption)仍綁定舊系統:透過 HardNcLine 鏈結串列做最佳化(feedrate、深度切分、加速度限制等)。此模組尚未深入規劃,仍可能有未知工作量需釐清。
6. 客戶可重組性(Reconfigurable)展示
新系統下,下列三類客製化全部 不需重編譯:
6.1 切換廠牌(內建 5 組 preset)
var runner = SoftNcRunner.HeidenhainNcRunner;
runner.ConfigureByMachiningChain(machine.Chain);
亦可由 XML 載入由專案反序列化挑選。詳見 SoftNcRunner。
6.2 客製某廠牌特定語法(不影響其他廠牌)
例如某客戶 Fanuc 機台用了非標準 M168 進行夾具控制:
- 新增一個
MyClampMSyntax :ISituNcSyntax 類別。 - 在客戶專案的 SoftNcRunner XML 中插入一行
<MyClampMSyntax/>。 - 不需改動 HiAPIs 任何原始檔。
6.3 跨廠牌共用機構配置
ConfigureByMachiningChain 把機台軸序、旋轉軸 / 線性軸區分、NcKinematicsDependency 的注入交由 IMachiningChain 驅動 — 5 軸機、4 軸機、雙轉台都共用同一條程式路徑。
7. 過渡相容性
為了不破壞既有客戶專案:
| 機制 | 位置 | 用途 |
|---|---|---|
| FromLegacyNcEnvXml | SoftNcRunner 內 Legacy 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 比對結果 |