GRBL学习
gcode.c/.h
是的没错,不管是打印机还是雕刻机,最终都是需要一个已经切片好的模型或者图片来进行打印,此时核心的过程就是Gcode的解析过程。所以这两个文件简直就是grbl的心脏。
可以先从头文件看起:
开头先是将常用的Gcode定义了一便,事实上不止这几个。
// Define modal group internal numbers for checking multiple command violations and tracking the
// type of command that is called in the block. A modal group is a group of g-code commands that are
// mutually exclusive, or cannot exist on the same line, because they each toggle a state or execute
// a unique motion. These are defined in the NIST RS274-NGC v3 g-code standard, available online,
// and are similar/identical to other g-code interpreters by manufacturers (Haas,Fanuc,Mazak,etc).
// NOTE: Modal group define values must be sequential and starting from zero.
#define MODAL_GROUP_G0 0 // [G4,G10,G28,G28.1,G30,G30.1,G53,G92,G92.1] Non-modal
#define MODAL_GROUP_G1 1 // [G0,G1,G2,G3,G38.2,G38.3,G38.4,G38.5,G80] Motion
#define MODAL_GROUP_G2 2 // [G17,G18,G19] Plane selection
#define MODAL_GROUP_G3 3 // [G90,G91] Distance mode
#define MODAL_GROUP_G4 4 // [G91.1] Arc IJK distance mode
#define MODAL_GROUP_G5 5 // [G93,G94] Feed rate mode
#define MODAL_GROUP_G6 6 // [G20,G21] Units
#define MODAL_GROUP_G7 7 // [G40] Cutter radius compensation mode. G41/42 NOT SUPPORTED.
#define MODAL_GROUP_G8 8 // [G43.1,G49] Tool length offset
#define MODAL_GROUP_G12 9 // [G54,G55,G56,G57,G58,G59] Coordinate system selection
#define MODAL_GROUP_G13 10 // [G61] Control mode
#define MODAL_GROUP_M4 11 // [M0,M1,M2,M30] Stopping
#define MODAL_GROUP_M7 12 // [M3,M4,M5] Spindle turning
#define MODAL_GROUP_M8 13 // [M7,M8,M9] Coolant control
没错可以往后看,在头文件中基本就是针对不同的G码,做一些特定的配置,例如:
#define DISTANCE_MODE_ABSOLUTE 0 // G90 (Default: Must be zero)
#define DISTANCE_MODE_INCREMENTAL 1 // G91
G90和G91两个G码,事实上在打印机上经常能解析到,就是让电机以相对的方式还是以绝对移动的方式去移动。后面其实也是这样的特殊常用的G码的定义。
后面会出现这个结构体,可以很明显看到,这个结构体直接包含系统打印时候所携带的参数以及控制他们相关的G码。
typedef struct {
uint8_t motion; // {G0,G1,G2,G3,G38.2,G80}
uint8_t feed_rate; // {G93,G94}
uint8_t units; // {G20,G21}
uint8_t distance; // {G90,G91}
// uint8_t distance_arc; // {G91.1} NOTE: Don't track. Only default supported.
uint8_t plane_select; // {G17,G18,G19}
// uint8_t cutter_comp; // {G40} NOTE: Don't track. Only default supported.
uint8_t tool_length; // {G43.1,G49}
uint8_t coord_select; // {G54,G55,G56,G57,G58,G59}
// uint8_t control; // {G61} NOTE: Don't track. Only default supported.
uint8_t program_flow; // {M0,M1,M2,M30}
uint8_t coolant; // {M7,M8,M9}
uint8_t spindle; // {M3,M4,M5}
} gc_modal_t;
例如:motion是运动,而G0/G1是可以控制X/Y电机运动的G指令,如:G0 X10 F300,则表示X往正方向走10mm,走的时候速度为300。这样来看,这个结构体就很简单的。
往下这个结构体,是相关数据的存储,同样是以G0 X10 F300这个命令来说,上面的的结构体对这条命令控制的,是G0 X10这部分,那下面这个结构体,控制的就是F300这个指令。事实上他们是同一个指令,但不同部分。所以一个完整的运动指令,应该是由控制指令+数据得到的。
typedef struct {
float f; // Feed
float ijk[3]; // I,J,K Axis arc offsets
uint8_t l; // G10 or canned cycles parameters
int32_t n; // Line number
float p; // G10 or dwell parameters
// float q; // G82 peck drilling
float r; // Arc radius
float s; // Spindle speed
uint8_t t; // Tool selection
float xyz[3]; // X,Y,Z Translational axes
} gc_values_t;
上面的可以说是指令解析器,下面这个就是状态解析的结构体,这个结构体是记录各种重要数据的吗,如打印速度、打印位置、当前位置等等,都是很重要的参数。
typedef struct {
gc_modal_t modal;
float spindle_speed; // RPM
float feed_rate; // Millimeters/min
uint8_t tool; // Tracks tool number. NOT USED.
int32_t line_number; // Last line number sent
float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code
float coord_system[N_AXIS]; // Current work coordinate system (G54+). Stores offset from absolute machine
// position in mm. Loaded from EEPROM when called.
float coord_offset[N_AXIS]; // Retains the G92 coordinate offset (work coordinates) relative to
// machine zero in mm. Non-persistent. Cleared upon reset and boot.
float tool_length_offset; // Tracks tool length offset value when enabled.
} parser_state_t;
extern parser_state_t gc_state;
在GRBL上已经定义好gc_state这样的一个对象,来控制和记录相关信息,如我要获取相关点的坐标,直接从gc_state.position[x]里面获取坐标值,或者偏移值等等。
看到声明的函数,却只有3个。
// Initialize the parser
void gc_init();
// Execute one block of rs275/ngc/g-code
uint8_t gc_execute_line(char *line);
// Set g-code parser position. Input in steps.
void gc_sync_position();
/*************************************************************
再回到.c文件
这里是是用做G码行数限定的,可以忽略
#define MAX_LINE_NUMBER 9999999
两个重要的结构体定义
// Declare gc extern struct
parser_state_t gc_state;
parser_block_t gc_block;
此处是G码的初始化,先把gc_state这个结构体变量直接清空,而很巧的是,这个结构体变量如果清空,那实际就是让机器按照默认值进行配置。
void gc_init()
{
memset(&gc_state, 0, sizeof(parser_state_t));
// Load default G54 coordinate system.
if (!(settings_read_coord_data(gc_state.modal.coord_select,gc_state.coord_system))) {
report_status_message(STATUS_SETTING_READ_FAIL);
}
}
因此在里面使用了这个函数:
settings_read_coord_data
事实上这个函数是从eeprom上读取相关的系统数据出来进行初始化。
这里可以将移动的步数转换成当前坐标点并且记录下来。
void gc_sync_position()
{
system_convert_array_steps_to_mpos(gc_state.position,sys.position);
}
真正解析gcode的,是这个函数:
由于内容过于充实和复杂,只能简略说明一下这个函数。
uint8_t gc_execute_line(char *line)
它可以直接读取发送过来指令,内容包括G码、相关数值(包括有符号浮点值),大小写的区分和已被删除的字符。是的,即使使用小写的指令输入,它依然会帮你转换成大写,输入的值都是按绝对坐标的方式运动的,并且单位都是mm。里面有个运动过程的运算,难度过于真实。。。。