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?
A. A line could contain more than one command. Bobc (talk)
Would it be more compact to encode all integers as something like a Wikipedia: variable-length quantity ?
A. Simple answer, no. Bobc (talk)
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?
A. It would be fantastic to use something like zip, but there is nowhere near enough RAM. I spent some time looking for a general purpose decoding algorithm that has a tiny footprint and would fit in a few kB. All the ones I found typical require 100kB + to achieve decent compression. But we don't need to compress general text, so an application specific encoding is a better option. Bobc (talk)