Packed Binary GCode

From RepRap
Revision as of 02:01, 11 November 2013 by DavidCary (talk | contribs) (ideas that may give even better compression)
Jump to: navigation, search

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

  1. GCode blocks are generally a list of <word letter> <number>, e.g. "G1", "Z1.5".
  2. There are 26 letters, plus a few other items like comments, checksum
  3. Therefore code letter is stored in 5 bits (0-31).
  4. Integers can be stored in 1,2 or 4 bytes, signed or unsigned
  5. Signed decimals stored in float (4 bytes)
  6. Comments and uncompressed data stored as null terminated string
  7. 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?