Packed Binary GCode

From RepRap
Revision as of 05:47, 8 July 2017 by Bobc (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
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?

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)