3、G-code语法与格式规范:行结构、词地址(字母+数字)、注释格式、参数单位与精度要求
G-code是3D打印机最底层的运动控制指令集,解析器能否正确、高效、鲁棒地处理G-code文本,直接决定了打印质量与设备安全。本章从语法规范出发,系统拆解G-code的行结构、词地址(Word Address)构成、注释规则、参数单位与精度要求,并给出解析器设计时应遵循的工程约束。理解这些规范,是后续实现词法分析器、语法检查器与运动规划器的基础。
3.1 行结构:从物理行到逻辑指令
3.1.1 核心原理:行的边界与语义
G-code文件本质上是文本流,每一行(Line)代表一条完整的指令。行结构由三个可选部分组成:行号(N)、词地址序列和注释。行号在早期数控系统中用于跳转和排序,现代3D打印机固件(如Marlin、Klipper)通常忽略行号,但解析器仍需兼容。词地址序列是行的核心,由一个或多个“字母+数字”对组成,例如 G1 X10.5 Y20.3 F1800 包含四个词:G1、X10.5、Y20.3、F1800。注释以分号(;)或圆括号(())开头,解析器应在词法分析前剥离注释,避免干扰数值解析。
3.1.2 判断方法与操作流程:行解析的工程步骤
解析器处理一行的标准流程如下:
- 读取原始行:按换行符(
\n)或回车换行(\r\n)切分文件,注意处理文件末尾无换行符的情况。 - 去除首尾空白:使用
trim()或等价操作,避免空格/Tab干扰。 - 剥离注释:先查找分号(;),若存在则截断;再查找圆括号对,删除括号内内容。注意:圆括号可能跨行(不推荐,但需兼容)。
- 空行检查:若剥离注释后为空,则跳过该行,不产生任何动作。
- 词法切分:按空格或Tab将剩余文本拆分为词(Token)。
- 语法校验:每个词必须匹配“字母+数字”模式,字母为A-Z(大小写不敏感),数字可为整数或小数,允许正负号。
N10 G1 X10.5 Y20.3 F1800 ; move to start剥离注释后:
N10 G1 X10.5 Y20.3 F1800切分结果:
["N10", "G1", "X10.5", "Y20.3", "F1800"]解析器应忽略N10(行号),提取G1、X、Y、F的值。
3.1.3 案例拆解:多词行与连续行处理
考虑以下切片器输出的典型片段:
G0 Z0.3
G1 X10.5 Y20.3 F1800
G1 X11.2 Y21.0 E0.042
M104 S200
; layer 2
G1 Z0.6 F300
解析器逐行处理:第一行 G0 Z0.3 表示快速移动到Z=0.3mm;第二行 G1 X10.5 Y20.3 F1800 设置进给率1800mm/min并移动到目标点;第三行增加E参数表示挤出量0.042mm;第四行M104设置喷嘴温度200°C;第五行是纯注释,直接跳过;第六行再次移动Z轴。注意:G0和G1都是运动指令,但G0不挤出,G1可挤出,解析器需区分。
3.1.4 常见误区与总结
- 误区1:忽略行号导致错误——某些固件用N号做缓冲管理,解析器应提取但不必执行。
- 误区2:注释剥离不彻底——分号出现在字符串中(极少见)或圆括号未闭合,应做防御性处理。
- 误区3:大小写敏感——G和g应视为相同,统一转为大写。
3.2 词地址:字母+数字的语义映射
3.2.1 核心原理:地址字母的分类
词地址由一个大写字母(A-Z)后跟一个数值组成。字母决定语义类别,数值是该类别的参数。常见地址分类如下:
| 地址 | 含义 | 典型范围/示例 |
|---|---|---|
| G | 准备功能(运动模式) | G0/G1/G28/G90/G91 |
| M | 辅助功能(机器控制) | M104/M106/M140/M190 |
| X/Y/Z | 线性轴目标坐标(mm) | X10.5, Y-3.2, Z0.3 |
| E | 挤出量(mm或mm³) | E0.042, E-0.01 |
| F | 进给率(mm/min) | F1800, F300 |
| S | 温度/速度/亮度等 | S200(温度), S255(风扇) |
| P | 参数/时间/索引 | P0(等待温度), P1(PID) |
| I/J | 圆弧中心偏移(相对起点) | I5.0 J0.0 |
| R | 圆弧半径或温度回退 | R10.0 |
| T | 工具/挤出机选择 | T0, T1 |
3.2.2 判断方法与操作流程:词法解析规则
解析词地址时,需遵循以下规则:
- 字母提取:取词的首字符,转为大写,判断是否为A-Z。
- 数值提取:剩余部分必须为合法数字,支持科学计数法(如
1.5e3)但建议禁用,因为切片器不输出。 - 重复地址处理:同一行中同一字母出现多次(如
X10 X20),按规范应报错,但部分固件取最后一个值。解析器应选择“报错并跳过”或“取最后值”策略,并在文档中说明。 - 未知地址:遇到未定义的字母(如
Q),应忽略并记录警告,不应中断解析。
GCodeWord { char letter; double value; },便于后续语义分析。
3.2.3 案例拆解:圆弧指令的I/J/R解析
圆弧插补指令 G2 X10 Y10 I5 J0 中,I和J表示圆心相对于起点的偏移量。解析器需同时处理X/Y目标坐标和I/J偏移,并计算圆心绝对坐标。若使用R格式 G2 X10 Y10 R5,则需根据起点、终点和半径计算圆心(存在两解,需根据G2/G3方向选择)。解析器应提供两种模式的转换接口,供运动规划模块调用。
3.2.4 常见误区与总结
- 误区1:将G和M混淆——G控制运动模式,M控制机器状态(如温度、风扇),语义完全不同。
- 误区2:忽略E值的正负——负E值表示回抽(Retraction),解析器必须保留符号。
- 误区3:F值单位错误——F的单位是mm/min,不是mm/s,换算时需除以60。
3.3 注释格式:剥离策略与边界情况
3.3.1 核心原理:三种注释风格
G-code注释有三种常见格式:
- 分号注释(;):从分号到行尾全部忽略,最常用。
- 圆括号注释(()):括号内内容忽略,可跨行(不推荐)。
- 块注释(/* */):部分固件支持,类似C语言风格。
解析器应优先支持分号和圆括号,块注释可选。注释内可能包含任意字符(包括数字和字母),剥离时必须完整删除,不能残留。
3.3.2 操作流程:注释剥离算法
function stripComments(line):
# 先处理圆括号(可能跨行,需状态机)
while line contains '(':
start = line.indexOf('(')
end = line.indexOf(')', start)
if end == -1: # 未闭合,删除到行尾
line = line.substring(0, start)
break
line = line.substring(0, start) + line.substring(end+1)
# 再处理分号
semi = line.indexOf(';')
if semi != -1:
line = line.substring(0, semi)
return line.trim()
3.3.3 案例拆解:复杂注释行
输入行:G1 X10 ; move X (this is a comment) Y20
剥离分号后:G1 X10 ,圆括号内容已被分号截断,因此Y20被忽略。若先剥离圆括号:G1 X10 ; move X Y20,再剥离分号:G1 X10 。两种顺序结果相同,但若圆括号在分号前:G1 X10 (comment ; still comment) Y20,先剥离圆括号得 G1 X10 Y20,先剥离分号得 G1 X10 (comment ,导致错误。因此必须先剥离圆括号,再剥离分号。
3.3.4 常见误区与总结
- 误区1:注释嵌套——G-code不支持嵌套注释,遇到
(;)应视为普通字符。 - 误区2:注释中的引号——注释内出现引号不改变注释语义,无需特殊处理。
- 误区3:性能问题——逐字符扫描注释会降低解析速度,建议使用正则表达式或状态机优化。
3.4 参数单位与精度要求:毫米、英寸与浮点容差
3.4.1 核心原理:单位制与精度标准
3D打印G-code默认使用毫米(mm)作为长度单位,进给率单位为毫米/分钟(mm/min),温度单位为摄氏度(°C)。但G20指令可切换为英寸(inch),解析器必须跟踪当前单位状态。精度方面,切片器(如Cura、PrusaSlicer)通常输出3位小数(0.001mm),但解析器应支持更高精度(如6位小数),并采用双精度浮点(double)存储,避免累积误差。
3.4.2 判断方法与操作流程:单位换算与容差处理
- 单位状态跟踪:解析器维护一个全局变量
unitMode(0=毫米,1=英寸),遇到G20/G21时切换。 - 换算公式:1英寸 = 25.4mm。解析时,若当前为英寸模式,所有坐标值乘以25.4转换为毫米;F值也需换算(1 inch/min = 25.4 mm/min)。
- 精度容差:由于浮点运算误差,比较两个坐标是否相等时,应使用
abs(a-b) < 1e-6作为容差,而非==。 - 整数与小数:词地址的数值部分允许整数(如
X10)和小数(如X10.5),解析器应统一转为double。
G1 X2.5 F100 应转换为 X=2.5*25.4=63.5mm,F=100*25.4=2540mm/min。
3.4.3 案例拆解:精度对打印质量的影响
假设切片器输出 G1 X100.123 Y50.456 E0.789,解析器若使用单精度浮点(float),有效位数约7位,100.123可能存储为100.12299,导致0.00001mm的误差。虽然单层误差微小,但累积数千层后可能产生可见偏差。因此,解析器必须使用double类型,并在运动规划中采用增量式累加,避免重复计算起点到终点的绝对坐标。
3.4.4 常见误区与总结
- 误区1:忽略G20/G21切换——若切片器在文件开头输出G21,解析器未处理,后续坐标全部错误。
- 误区2:F值单位混淆——部分固件支持F值单位为mm/s(如Klipper的
F实际为mm/s),解析器需根据固件配置调整。 - 误区3:负零问题——
-0.0与0.0在浮点中不同,应统一归零。
3.5 综合案例:从原始G-code到运动指令的完整解析
下面通过一个完整案例,串联本章所有知识点。假设输入文件 test.gcode 内容如下:
; generated by Cura 5.0
G21 ; set units to mm
G90 ; absolute positioning
M104 S200 ; set nozzle temp
G28 X Y ; home X and Y
G1 Z0.3 F300 ; move Z to 0.3mm
G1 X10.5 Y20.3 F1800 ; move to start point
G1 X11.2 Y21.0 E0.042 ; extrude 0.042mm
M106 S255 ; fan on full
G1 X12.0 Y22.0 E0.084
M104 S0 ; turn off nozzle
M140 S0 ; turn off bed
M107 ; fan off
M84 ; disable motors
解析过程:
- 逐行读取,剥离注释(分号后内容删除)。
- 第一行
G21设置单位为毫米;第二行G90设置绝对定位。 M104 S200设置喷嘴温度200°C,解析器将温度值存入状态变量。G28 X Y触发回原点,解析器应标记X和Y轴需要归零。G1 Z0.3 F300设置Z轴目标0.3mm,进给率300mm/min。G1 X10.5 Y20.3 F1800设置X/Y目标,F更新为1800。G1 X11.2 Y21.0 E0.042增加E值,解析器需计算挤出增量(0.042-0=0.042)。- 后续行类似,直到
M84禁用电机。
结果对比:解析器输出结构化指令序列,每个运动指令包含目标坐标、进给率、挤出量,以及温度/风扇等辅助指令。若解析器未处理G21,则所有坐标被误认为英寸,实际移动距离放大25.4倍,导致打印尺寸严重错误。
风险与代价:单位错误是3D打印最常见的事故之一,轻则打印失败,重则撞机损坏热床。因此,解析器必须在文件开头检测单位指令,并在每次切换时输出警告。
复盘经验:建议在解析器测试套件中加入“单位切换”和“注释剥离”的边界测试用例,例如:G20 G1 X1 ; comment、(multi\nline) G1 X2 等。
3.6 本章总结与工程清单
G-code语法规范是解析器设计的基石。本章核心要点如下:
| 模块 | 关键规范 | 解析器要求 |
|---|---|---|
| 行结构 | 行号可选,词地址序列+注释 | 剥离注释,忽略行号,容错空行 |
| 词地址 | 字母+数字,大小写不敏感 | 提取字母和数值,处理重复/未知地址 |
| 注释 | 分号、圆括号、块注释 | 先剥离圆括号,再剥离分号 |
| 单位 | G20英寸/G21毫米,默认毫米 | 跟踪单位状态,换算坐标和F值 |
| 精度 | 双精度浮点,容差1e-6 | 使用double,避免累积误差 |
--strict 模式,在严格模式下任何语法错误都停止打印,在宽松模式下跳过错误行并继续。