Read G-Code and execute it on Arduino

I need my Arduino to read and execute G-code from a text. I have low programming skills and i need some help.I have tried some ready-made codes but non can work.

What have you tried and what didn't work ?

Which Arduino are you using ?
What CNC hardware are you using ?

1)I am using Arduino UNO.
2)3 Step motors for 3 axis.

The code that i have used was :

#define BAUD (57600) // How fast is the Arduino talking?
#define MAX_BUF (64) // What is the longest message Arduino can store?

char buffer[MAX_BUF]; // where we store the message until we get a ‘;’
int sofar; // how much is in the buffer

/**

  • First thing this machine does on startup. Runs only once.
    */
    void setup() {
    Serial.begin(BAUD); // open coms
    help(); // say hello
    set_feedrate(200); // set default speed
    ready();
    }

/**

  • display helpful information
    */
    void help() {
    Serial.print(F("CNC Robot "));
    Serial.println(VERSION);
    Serial.println(F(“Commands:”));
    Serial.println(F(“G00 [X(steps)] [Y(steps)] [F(feedrate)]; - linear move”));
    Serial.println(F(“G01 [X(steps)] [Y(steps)] [F(feedrate)]; - linear move”));
    Serial.println(F(“G04 P[seconds]; - delay”));
    Serial.println(F(“G90; - absolute mode”));
    Serial.println(F(“G91; - relative mode”));
    Serial.println(F(“G92 [X(steps)] [Y(steps)]; - change logical position”));
    Serial.println(F(“M18; - disable motors”));
    Serial.println(F(“M100; - this help message”));
    Serial.println(F(“M114; - report position and feedrate”));
    }

/**

  • prepares the input buffer to receive a new message and
  • tells the serial connected device it is ready for more.
    /
    void ready() {
    sofar=0; // clear input buffer
    Serial.print(F("> ")); // signal ready to receive input
    }
    /
    *
  • After setup() this machine will repeat loop() forever.
    */
    void loop() {
    // listen for commands
    if( Serial.available() ) { // if something is available
    char c = Serial.read(); // get it
    Serial.print(c); // optional: repeat back what I got for debugging

// store the byte as long as there’s room in the buffer.
// if the buffer is full some data might get lost
if(sofar < MAX_BUF) buffer[sofar++]=c;
// if we got a return character (\n) the message is done.
if(c==’\n’) {
Serial.print(F("\r\n")); // optional: send back a return for debugging

// strings must end with a \0.
buffer[sofar]=0;
processCommand(); // do something with the command
ready();
}
}
}
/**

  • Read the input buffer and find any recognized commands. One G or M command per line.
    */
    void processCommand() {
    // look for commands that start with ‘G’
    int cmd=parsenumber(‘G’,-1);
    switch(cmd) {
    case 0: // move in a line
    case 1: // move in a line
    set_feedrate(parsenumber(‘F’,fr));
    line( parsenumber(‘X’,(mode_abs?px:0)) + (mode_abs?0:px),
    parsenumber(‘Y’,(mode_abs?py:0)) + (mode_abs?0:py) );
    break;
    // case 2: // clockwise arc
    // case 3: // counter-clockwise arc
    case 4: pause(parsenumber(‘P’,0)*1000); break; // wait a while
    case 90: mode_abs=1; break; // absolute mode
    case 91: mode_abs=0; break; // relative mode
    case 92: // set logical position
    position( parsenumber(‘X’,0),
    parsenumber(‘Y’,0) );
    break;
    default: break;
    }

// look for commands that start with ‘M’
cmd=parsenumber(‘M’,-1);
switch(cmd) {
case 18: // turns off power to steppers (releases the grip)
m1.release();
m2.release();
break;
case 100: help(); break;
case 114: where(); break; // prints px, py, fr, and mode.
default: break;
}

// if the string has no G or M commands it will get here and the Arduino will silently ignore it
}
parsenumber(key,default)
/**

  • Uses Bresenham’s line algorithm to move both motors
  • @input newx the destination x position
  • @input newy the destination y position
    **/
    void line(float newx,float newy) {
    long dx=newx-px; // distance to move (delta)
    long dy=newy-py;
    int dirx=dx > 0?1:-1; // direction to move
    int diry=dy > 0?1:-1;
    dx=abs(dx); // absolute delta
    dy=abs(dy);

long i;
long over=0;

if(dx > dy) {
for(i=0;i < dx;++i) {
m1.onestep(dirx);
over+=dy;
if(over>=dx) {
over-=dx;
m2.onestep(diry);
}
pause(step_delay); // step_delay is a global connected to feed rate.
// test limits and/or e-stop here
}
} else {
for(i=0;i < dy;++i) { m2.onestep(diry); over+=dx; if(over>=dy) { over-=dy; m1.onestep(dirx); } pause(step_delay); // step_delay is a global connected to feed rate. // test limits and/or e-stop here } } // update the logical position. We don’t just = newx because // px + dx * dirx == newx could be false by a tiny margin and we don’t want rounding errors. px+= dxdirx; py+= dydiry; } /** * delay for the appropriate number of microseconds * @input ms how many milliseconds to wait / void pause(long ms) { delay(ms/1000); delayMicroseconds(ms%1000); // delayMicroseconds doesn’t work for values > ~16k. } /* * Set the feedrate (speed motors will move) * @input nfr the new speed in steps/second */ void set_feedrate(float nfr) { if(fr==nfr) return; // same as last time? quit now. if(nfr > MAX_FEEDRATE || nfr < MIN_FEEDRATE) { // don’t allow crazy feed rates
Serial.print(F("New feedrate must be greater than "));
Serial.print(MIN_FEEDRATE);
Serial.print(F("steps/s and less than "));
Serial.print(MAX_FEEDRATE);
Serial.println(F(“steps/s.”));
return;
}
step_delay = 1000000.0/nfr;
fr=nfr;
}

Which corrections would be helpful.Thank you.

To make it easy for people to help you please modify your post and use the code button </> so your code looks like this and is easy to copy to a text editor. See How to use the Forum

Your code is too long for me to study quickly without copying to a text editor.

Also use the AutoFormat tool to indent your code for easier reading.

Have you considered using the GRBL program ?

…R

Compiling that code produces many errors. Where did you get it from ?

Arduino: 1.8.5 (Windows 10), Board: "Arduino Nano, ATmega328P"

C:\Users\Bob\AppData\Local\Temp\arduino_modified_sketch_170471\sketch_may12a.ino: In function 'void setup()':

sketch_may12a:14: error: 'set_feedrate' was not declared in this scope

   set_feedrate(200); // set default speed

                   ^

C:\Users\Bob\AppData\Local\Temp\arduino_modified_sketch_170471\sketch_may12a.ino: In function 'void help()':

sketch_may12a:24: error: 'VERSION' was not declared in this scope

   Serial.println(VERSION);

                  ^

C:\Users\Bob\AppData\Local\Temp\arduino_modified_sketch_170471\sketch_may12a.ino: In function 'void processCommand()':

sketch_may12a:76: error: 'parsenumber' was not declared in this scope

   int cmd = parsenumber('G', -1);

                                ^

sketch_may12a:81: error: 'fr' was not declared in this scope

       set_feedrate(parsenumber('F', fr));

                                     ^

sketch_may12a:81: error: 'set_feedrate' was not declared in this scope

       set_feedrate(parsenumber('F', fr));

                                        ^

sketch_may12a:82: error: 'mode_abs' was not declared in this scope

       line( parsenumber('X', (mode_abs ? px : 0)) + (mode_abs ? 0 : px),

                               ^

sketch_may12a:82: error: 'px' was not declared in this scope

       line( parsenumber('X', (mode_abs ? px : 0)) + (mode_abs ? 0 : px),

                                          ^

sketch_may12a:83: error: 'py' was not declared in this scope

             parsenumber('Y', (mode_abs ? py : 0)) + (mode_abs ? 0 : py) );

                                          ^

sketch_may12a:88: error: 'pause' was not declared in this scope

       pause(parsenumber('P', 0) * 1000);

                                       ^

sketch_may12a:98: error: 'position' was not declared in this scope

                 parsenumber('Y', 0) );

                                     ^

sketch_may12a:108: error: 'm1' was not declared in this scope

       m1.release();

       ^

sketch_may12a:109: error: 'm2' was not declared in this scope

       m2.release();

       ^

sketch_may12a:115: error: 'where' was not declared in this scope

       where();

             ^

C:\Users\Bob\AppData\Local\Temp\arduino_modified_sketch_170471\sketch_may12a.ino: At global scope:

sketch_may12a:122: error: expected constructor, destructor, or type conversion before '(' token

 parsenumber(key, default)

            ^

exit status 1
'set_feedrate' was not declared in this scope

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

I found it in that link :

I am new in this forum so forgive me for any mistakes.

I want this Arduino to take orders from an other by a text G-Code file. So i can't see how can i use GRBL program. I think that i need an Arduino code so it can execute the G-Code. If i am wrong please correct me.

pipertzisdimitris:
So i can't see how can i use GRBL program. I think that i need an Arduino code so it can execute the G-Code.

GRBL is Arduino code.

You need to give us a good description of your whole project if you are to get useful advice.

...R

After i upload the GRBL code i will be able to run G-Code .txt files?
Do i need any farther sources?(shield,drivers etc.)

Will l be able to have some comunication like Master/Slave?(using grbl code)
I want my slave to execute the G-code.

After i upload the GRBL code i will be able to run G-Code .txt files?

GRBL needs to be sent the G-code commands one at a time over a serial link and will respond when each one is complete

To quote from https://github.com/grbl/grbl/wiki/Frequently-Asked-Questions

How do I stream a complete G-code program to Grbl?
Streaming g-code programs to Grbl may be done by a simple send-and-respond method through the serial port. Every command followed by a return is responded to when Grbl is ready to receive another command.

Will l be able to have some comunication like Master/Slave?(using grbl code)
I want my slave to execute the G-code.

GRBL does not care what is sending the commands so they could come from a second (master) Arduino that reads them from a file and passes each in turn to the slave Arduino to be executed when it is ready.

Do i need any farther sources?(shield,drivers etc.)

Yes, of course you do, as an Arduino is not able to control a stepper motor directly.

pipertzisdimitris:
After i upload the GRBL code i will be able to run G-Code .txt files?
Do i need any farther sources?(shield,drivers etc.)

How long have you spent studying the GRBL documentation ?

...R

Same problem . I already flash grbl on my arduino uno but when it come on uploading gcodes the stepper motor still not moving . But when it comes on universal gcode sender when i press the controll machine it will move

darwinkarl2536:
Same problem . I already flash grbl on my arduino uno but when it come on uploading gcodes the stepper motor still not moving . But when it comes on universal gcode sender when i press the controll machine it will move

I am having the same problem as well. Have you found any solution? I do not want to use any software to upload the gcodes because I am trying to build an autonomous laser engraver machine (standalone Arduino based laser engraver machine).

UKHeliBob:
GRBL does not care what is sending the commands so they could come from a second (master) Arduino that reads them from a file and passes each in turn to the slave Arduino to be executed when it is ready.

How do we do the coding for the slave Arduino to receive and run the code? Is it through Serial.print(gcodes) or are there any specific codes to translate the gcode to the stepper movement?

From my understanding, GRBL occupies the serial monitor of the slave Arduino so there is no way to use the serial monitor.

Please help. :frowning:

XenonFred:
From my understanding, GRBL occupies the serial monitor of the slave Arduino so there is no way to use the serial monitor.

You could open a second instance of the Arduino IDE and give yourself a second separate serial monitor or you could use a different terminal program such as PuTTY or Realterm. Any program on the PC that can send data over a serial connection can talk to an Arduino.

How do we do the coding for the slave Arduino to receive and run the code? Is it through Serial.print(gcodes) or are there any specific codes to translate the gcode to the stepper movement?

I don't understand what you have in mind. Please explain further.

...R

XenonFred:
I am having the same problem as well. Have you found any solution? I do not want to use any software to upload the gcodes because I am trying to build an autonomous laser engraver machine (standalone Arduino based laser engraver machine).
How do we do the coding for the slave Arduino to receive and run the code? Is it through Serial.print(gcodes) or are there any specific codes to translate the gcode to the stepper movement?

From my understanding, GRBL occupies the serial monitor of the slave Arduino so there is no way to use the serial monitor.

Please help. :frowning:

Do you see THIS function in the code that was provided by the OP?

void ready() {
sofar=0; // clear input buffer
Serial.print(F("> ")); // signal ready to receive input
}

That is the message that is sent back to the program sending the "G" code line to tell that program to send the next line. If you do not provide a program on the other device that can read that message and send a "G" code line, then you will never get this to work!!!!

Paul

Robin2:
You could open a second instance of the Arduino IDE and give yourself a second separate serial monitor or you could use a different terminal program such as PuTTY or Realterm. Any program on the PC that can send data over a serial connection can talk to an Arduino.

...R

I am trying to build an autonomous laser engraver, which does not receive data from the PC but instead from another Arduino or an SD card. Therefore, I do not want any external software like Universal GCode Sender involved because the laser engraver will not be connected to any PC.

Robin2:
I don't understand what you have in mind. Please explain further.
...R

Initially, I was thinking on how to translate the gcode to stepper movement (for example, for G1 X100 F150, how do I know how many steps I need the stepper motor to move in the X-axis?). How do I program it in Arduino? However, I just reread the codes uploaded by the OP and I sort of have an idea on this issue. I will give it a try again and thanks for the reply!

Paul_KD7HB:
Do you see THIS function in the code that was provided by the OP?

void ready() {
sofar=0; // clear input buffer
Serial.print(F("> ")); // signal ready to receive input
}

That is the message that is sent back to the program sending the "G" code line to tell that program to send the next line. If you do not provide a program on the other device that can read that message and send a "G" code line, then you will never get this to work!!!!

Paul

Thank you very much! This will be helpful. My bad for missing this out.

Anyway, I will give it a try first and will update this post again.

I am trying to build an autonomous laser engraver, which does not receive data from the PC but instead from another Arduino or an SD card.

Don't you mean:-
I am trying to build an autonomous laser engraver, which does not receive data from the PC but instead from another Arduino or and an SD card.
If not where does the second Arduino get the Gcode from?

Therefore, I do not want any external software like Universal GCode Sender involved

You are going to have to write the equivalent of this on your second Arduino.

XenonFred:
I am trying to build an autonomous laser engraver, which does not receive data from the PC but instead from another Arduino or an SD card. Therefore, I do not want any external software like Universal GCode Sender involved because the laser engraver will not be connected to any PC.

I am even more confused now. In Reply #11 you said

From my understanding, GRBL occupies the serial monitor of the slave Arduino so there is no way to use the serial monitor.

and that would only make sense if the Arduino IS CONNECTED to the PC. The Serial Monitor is a PC program.

...R