G-code

From RepRap
Revision as of 07:26, 16 February 2010 by Adrianbowyer (talk | contribs) (New page: == Introduction == This page describes the G Codes that the RepRap firmware uses, what they mean, and how they work. The list of what can be done is extensible. But check here first, a...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Introduction

This page describes the G Codes that the RepRap firmware uses, what they mean, and how they work.

The list of what can be done is extensible. But check here first, and add your extension here first before you implement it.

A typical piece of GCode as sent to a RepRap machine might look like this:

N3 T0 *86
N4 G92 E0 *102
N5 G28 *13
N6 G1 F1500.0 *117
N7 G1 X2.0 Y2.0 F3000.0 *71
N8 G1 X3.0 Y3.0 *39


RepRap G Code Fields

This section explains the letter-preceded fields. The numbers in the fields are represented by nnn. Numbers can be integers, or can contain a decimal point, depending on context. For example clearly an X coordinate can be integer or fractional, whereas selecting extruder number 2.76 makes no sense.

In the section below, individual commands are distinguished.

Letter Meaning
Gnnn Standard GCode command, such as move to a point
Mnnn RepRap-defined command, such as turn on a cooling fan
Tnnn Select tool nnn. In RepRap, tools are extruders
Snnn Command parameter, such as the voltage to send to a motor
Pnnn Command parameter, such as a time in milliseconds
Xnnn An X coordinate, usually to move to
Ynnn A Y coordinate, usually to move to
Znnn A Z coordinate, usually to move to
Innn Parameter - not currently used
Jnnn Parameter - not currently used
Fnnn Feedrate in mm per minute.
Rnnn Parameter - not currently used
Qnnn Parameter - not currently used
Ennn Length of extrudate in mm. This is exactly like X, Y and Z, but for the length of filament to extrude.
Nnnn Line number. Used to request repeat transmission in the case of communications errors.
*nnn Checksum. Used to check for communications errors.

Checksums for a GCode cmd (including its line number) are computed as follows:

for(int i = 0; i < cmd.length(); i++)
   cs = cs ^ cmd.charAt(i);
cs &= 0xff;

and the value is appended to the command after a '*' character.

//the character / means delete block... used for comments and stuff. if (instruction[0] == '/') return;

       float fr;
       

fp.x = 0.0; fp.y = 0.0; fp.z = 0.0;

       fp.e = 0.0;
       fp.f = 0.0;

//get all our parameters! parse_string(&gc, instruction, size);


       // Do we have lineNr and checksums in this gcode?
       if((bool)(gc.seen & GCODE_CHECKSUM) | (bool)(gc.seen & GCODE_N))
       {
         // Check that if recieved a L code, we also got a C code. If not, one of them has been lost, and we have to reset queue
         if( (bool)(gc.seen & GCODE_CHECKSUM) != (bool)(gc.seen & GCODE_N) )
         {
          if(SendDebug & DEBUG_ERRORS)
            Serial.println("Serial Error:Recieved a LineNr code without a Checksum code or Checksum without LineNr");
          FlushSerialRequestResend();
          return;
         }
         // Check checksum of this string. Flush buffers and re-request line of error is found
         if(gc.seen & GCODE_CHECKSUM)  // if we recieved a line nr, we know we also recieved a Checksum, so check it
           {
           // Calc checksum.
           byte checksum = 0;
           byte count=0;
           while(instruction[count] != '*')
             checksum = checksum^instruction[count++];
           // Check checksum.
           if(gc.Checksum != (int)checksum)
             {
             if(SendDebug & DEBUG_ERRORS)
               Serial.println("Serial Error: checksum mismatch");
             FlushSerialRequestResend();
             return;
             }
         // Check that this lineNr is LastLineNrRecieved+1. If not, flush
         if(!( (bool)(gc.seen & GCODE_M) && gc.M == 110)) // unless this is a reset-lineNr command
           if(gc.N != gc.LastLineNrRecieved+1)
               {
               if(SendDebug & DEBUG_ERRORS)
                 Serial.println("Serial Error: LineNr is not the last lineNr+1");
               FlushSerialRequestResend();
               return;
               }
          //If we reach this point, communication is a succes, update our "last good line nr" and continue
          gc.LastLineNrRecieved = gc.N;
         }
       }


/* if no command was seen, but parameters were, then use the last G code as * the current command */ if ((!(gc.seen & (GCODE_G | GCODE_M | GCODE_T))) && ((gc.seen != 0) && (last_gcode_g >= 0))) { /* yes - so use the previous command with the new parameters */ gc.G = last_gcode_g; gc.seen |= GCODE_G; } //did we get a gcode? if (gc.seen & GCODE_G)

 	{

last_gcode_g = gc.G; /* remember this for future instructions */ fp = where_i_am; if (abs_mode) { if (gc.seen & GCODE_X) fp.x = gc.X; if (gc.seen & GCODE_Y) fp.y = gc.Y; if (gc.seen & GCODE_Z) fp.z = gc.Z; if (gc.seen & GCODE_E) fp.e = gc.E; } else { if (gc.seen & GCODE_X) fp.x += gc.X; if (gc.seen & GCODE_Y) fp.y += gc.Y; if (gc.seen & GCODE_Z) fp.z += gc.Z; if (gc.seen & GCODE_E) fp.e += gc.E; }

// Get feedrate if supplied - feedrates are always absolute??? if ( gc.seen & GCODE_F ) fp.f = gc.F;

               // Process the buffered move commands first
               // If we get one, return immediately

switch (gc.G)

               {

//Rapid move case 0:

                               fr = fp.f;
                               fp.f = FAST_XY_FEEDRATE;
                               qMove(fp);
                               fp.f = fr;
                               return;
                               
                       // Controlled move

case 1:

                               qMove(fp);
                               return;
                               
                       //go home.

case 28:

                               where_i_am.f = SLOW_XY_FEEDRATE;
                               specialMoveX(where_i_am.x - 5, FAST_XY_FEEDRATE);
                               specialMoveX(where_i_am.x - 250, FAST_XY_FEEDRATE);
                               where_i_am.x = 0;
                               where_i_am.f = SLOW_XY_FEEDRATE;
                               specialMoveX(where_i_am.x + 1, SLOW_XY_FEEDRATE);
                               specialMoveX(where_i_am.x - 10, SLOW_XY_FEEDRATE);                                
                               where_i_am.x = 0;
                               
                               specialMoveY(where_i_am.y - 5, FAST_XY_FEEDRATE);
                               specialMoveY(where_i_am.y - 250, FAST_XY_FEEDRATE);
                               where_i_am.y = 0;
                               where_i_am.f = SLOW_XY_FEEDRATE;
                               specialMoveY(where_i_am.y + 1, SLOW_XY_FEEDRATE);
                               specialMoveY(where_i_am.y - 10, SLOW_XY_FEEDRATE);                                
                               where_i_am.y = 0; 

                               where_i_am.f = SLOW_Z_FEEDRATE;
                               specialMoveZ(where_i_am.z - 0.5, FAST_Z_FEEDRATE);
                               specialMoveZ(where_i_am.z - 250, FAST_Z_FEEDRATE);
                               where_i_am.z = 0;
                               where_i_am.f = SLOW_Z_FEEDRATE;
                               specialMoveZ(where_i_am.z + 1, SLOW_Z_FEEDRATE);
                               specialMoveZ(where_i_am.z - 2, SLOW_Z_FEEDRATE);                                
                               where_i_am.z = 0;
                               where_i_am.f = SLOW_XY_FEEDRATE;     // Most sensible feedrate to leave it in                    

return;


                 default:
                               break;
               }
               

// Non-buffered G commands

               // Wait till the buffer q is empty first
                   
                 while(!qEmpty()) delay(WAITING_DELAY);
                 //delay(2*WAITING_DELAY); // For luck

switch (gc.G) {

 			 //Dwell

case 4: delay((int)(gc.P + 0.5)); break;

//Inches for Units case 20:

                               setUnits(false);

break;

//mm for Units case 21:

                               setUnits(true);

break;

//Absolute Positioning case 90: abs_mode = true; break;

//Incremental Positioning case 91: abs_mode = false; break;

//Set position as fp case 92:

                               setPosition(fp);

break;

default: if(SendDebug & DEBUG_ERRORS)

                               {
                               Serial.print("huh? G");

Serial.println(gc.G, DEC);

                               FlushSerialRequestResend();
                               }

} }



//find us an m code. if (gc.seen & GCODE_M) {

           // Wait till the q is empty first
           while(!qEmpty()) delay(WAITING_DELAY);
           //delay(2*WAITING_DELAY);

switch (gc.M) { //TODO: this is a bug because search_string returns 0. gotta fix that. case 0: break; /* case 0: //todo: stop program break;

case 1: //todo: optional stop break;

case 2: //todo: program end break; */

// Now, with E codes, there is no longer any idea of turning the extruder on or off. // (But see valve on/off below.)

/* //turn extruder on, forward case 101: ex[extruder_in_use]->setDirection(1); ex[extruder_in_use]->setSpeed(extruder_speed); break;

//turn extruder on, reverse case 102: ex[extruder_in_use]->setDirection(0); ex[extruder_in_use]->setSpeed(extruder_speed); break;

//turn extruder off

  • /

//custom code for temperature control case 104: if (gc.seen & GCODE_S) { ex[extruder_in_use]->setTemperature((int)gc.S); } break;

//custom code for temperature reading case 105: Serial.print("T:"); Serial.println(ex[extruder_in_use]->getTemperature()); break;

//turn fan on case 106: ex[extruder_in_use]->setCooler(255); break;

//turn fan off case 107: ex[extruder_in_use]->setCooler(0); break;

//set PWM to extruder stepper case 108:

  1. if MOTHERBOARD > 1

if (gc.seen & GCODE_S)

                                       ex[extruder_in_use]->setPWM((int)(255.0*gc.S + 0.5));
  1. endif

break;

                       // Set the temperature and wait for it to get there

case 109: ex[extruder_in_use]->setTemperature((int)gc.S);

                               ex[extruder_in_use]->waitForTemperature();

break;

                       // Starting a new print, reset the gc.LastLineNrRecieved counter

case 110: if (gc.seen & GCODE_N) { gc.LastLineNrRecieved = gc.N;

				  if(SendDebug & DEBUG_INFO)
                                   Serial.println("DEBUG:LineNr set");

} break; case 111: SendDebug = gc.S; break; case 112: // STOP!

                              {
                                int a=50;
                               while(a--)
                                 {blink(); delay(50);}
                              }

cancelAndClearQueue(); break;

                      case 113:
                           #if MOTHERBOARD > 1
                               ex[extruder_in_use]->usePotForMotor();
                           #endif

break;


// The valve (real, or virtual...) is now the way to control any extruder (such as // a pressurised paste extruder) that cannot move using E codes.

                       // Open the valve
                       case 126:
                               ex[extruder_in_use]->valveSet(true, (int)(gc.P + 0.5));
                               break;
                               
                       // Close the valve
                       case 127:
                               ex[extruder_in_use]->valveSet(false, (int)(gc.P + 0.5));
                               break;
                                                               

default: if(SendDebug & DEBUG_ERRORS)

                                 {
                                 Serial.print("Huh? M");

Serial.println(gc.M, DEC);

                                 FlushSerialRequestResend();
                                 }

}


}

// Tool (i.e. extruder) change?

       if (gc.seen & GCODE_T)
       {
           while(!qEmpty()) delay(WAITING_DELAY);
           //delay(2*WAITING_DELAY);
           newExtruder(gc.T);
       }