Packed Binary GCode
Contents
Packed Binary GCode (PBG)
Bob Cousins
28 August 2012
Version 0.4
Goals:
- reduce size of G-code data
- compatible with RS274/NGC spec for all types of machine, e.g. for printers, milling, lasers etc
- should be able to completely recreate ASCII GCode from compressed GCode with no loss of precision/data, comments
- independent of machine, i.e. does not use machine units
- extension for string parameters
- doesn't require significant extra RAM for decoding
- streamable format, not context dependent
Todo: embed binary data?
Todo: add bcd, or double?
Method
- GCode blocks are generally a list of <word letter> <number>, e.g. "G1", "Z1.5".
- There are 26 letters, plus a few other items like comments, checksum
- Therefore code letter is stored in 5 bits (0-31).
- Integers can be stored in 1,2 or 4 bytes, signed or unsigned
- Signed decimals stored in float (4 bytes)
- Comments and uncompressed data stored as null terminated string
- Therefore type stored in 3 bits (0-7)
Syntax
BNF syntax: gcode_line ::= { gcode_command … } EOL_MARK; gcode_command ::= { gcode_word ... } EOC_MARK ; gcode_word ::= code_type {parameter}; code_type ::= BYTE ( code << 3 | type ); code ::= 0..30; type ::= 0..7; parameter ::= BYTE … ; // 1,2,4 bytes or zero terminated string EOC_MARK ::= 0xF8 EOL_MARK ::= 0xF9
GCode word encoding
+--- 1 byte ---+-/ 0 to N bytes /-+ | CODE . TYPE | data | +--------------+-/ /--------------+
CODE + TYPE stored in 1 byte:
0000 0ttt CODE 0 = Checksum (*) (numeric data) 0000 1ttt CODE 1 = A (numeric data) ... 1101 0ttt CODE 26 = Z (numeric data) 1101 1ttt CODE 27 = spare 1110 0111 CODE 28 = Comment (type=string) 1110 1111 CODE 29 = Uncompressed text (type=string) 1111 0111 CODE 30 = String parameter (no word letter) 1111 1000 CODE 31 = No data, where: 1111 1000 0xF8 = End of command 1111 1001 0xF9 = End of line marker 1111 1010 0xFA- 1111 1111 0xFF spare
todo: block delete?
TYPE: 0 : unsigned byte (1 byte) 1 : signed byte (1) 2 : unsigned short (2 byte) //?? 3 : signed short (2 byte) 4 : signed int (4 byte) 5 : BCD decimal 6 : float (4 bytes) 7 : string (N+1 bytes) BCD = 0x0 .. 0x9 == 0..9 0xA == '.' 0xB == '-' 0xF == end
Comparison of sizes:
Command 1: G1 E10810.1 F1000
Original size: 21 Bytes
Updated for errorcheck: N6654 G1 E10810.1 F1000 *65
Errorcheck size: 29 Bytes
repetier-protocol: 15 Bytes
3+2+5+3+2+2
Packed Binary Gcode: 17 bytes
What is the purpose of the EOC_MARK ? Is there ever a situation where we couldn't replace it with a EOL_MARK instead?
Would it be more compact to encode all integers as something like a Wikipedia: variable-length quantity ?
An adaptive compression algorithm would be even more compact. Is there a Wikibooks: Data Compression implementation that fits in the very limited amount of SRAM available in the Arduino not already used by the RepRap firmware?