This has been a long road, but I wanted to make a way to send G-code data to the Fanuc robot. I have limited modules installed in this robot, but it did have the base ‘SENSOR’ module installed. This lets you use the Serial port to send and receive data from the robot.
More on that in my Fanuc robot RS232 post.
Here is it working.
Here is the Program I am running on the robot. It is very simple.
2: R[9:SPEED]=1000 ;
3: ;
4: WAIT R[8:RUN]=1 ;
5: PR[5,1:HOME]=PR[1,1:PC_SERIAL] ;
6: PR[5,2:HOME]=PR[1,2:PC_SERIAL] ;
7: PR[5,3:HOME]=PR[1,3:PC_SERIAL] ;
8: R[9:SPEED]=PR[1,6:PC_SERIAL]*R[15:MULTIPLR] ;
9: ;
10:J PR[5:HOME] R[9:SPEED]msec CNT100 ACC60 ;
11: ;
12: R[8:RUN]=0 ;
13: WAIT .05(sec) ;
14: SEND R[8:RUN] ;
15: ;
16: ;
17: JMP LBL[1] ;
The PC program runs in a software called processing.
It is a free program, that lets you code like an Arduino but on the PC, and lets you talk to a serial port!
Here is the processing code:
// import serial database******************************
import processing.serial.*;
Serial myPort1; // Create object from Serial class
//GCODE inport^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
String[] gcodeLines; // Array to store all the lines from the G-code file
int currentLineIndex = 0; // Index to keep track of the current line being processed
float lastX = 0; // Variables to store the last X, Y, Z, and speed values
float lastY = 0;
float lastZ = 0;
float lastSpeed = 0;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
float gx = 100;
float gy = 100;
float gz = 100;
float gspeed = 100;
int myString1;
int COUNT = 0;
int READY = 0; // ready to send data
int STAGE = 0; // what stage of the program
int RSTAGE = 0; // what stage receive data
int GO = 0;// respknse from robot to go on
byte STARTCALL[] = {0x05};
byte GO60[] = {0x5a, 0x04, 0x05, 0x00, 0x00, 0x32, 0x33};
byte GO50[] = {0x5a, 0x04, 0x05, 0x00, 0x00, 0x3c, 0x3d};
int ENDCALL = 0x84;
byte ACK[] = {0x06}; // acnoledge
//VARS************************
int x=100;
int y=100;
int z=100;
int r=100;
int STOREX = 0; // store the last x value to compare.
int STOREY = 0; // store the last y value to compare.
int WRITE = 0;// change to a 1 once date written.
int m = millis(); // store times pasted.
int SENT = 0; // var to know if data was sent to the sensor to get a reading. 1 is yes dont talk again 0 is I got the data back.
int SEND = 0; // var used when robot sent 0x05 I want to send data.
int POS = 1; // what posision we are requesting 1:X 2:Y 3:Z 4:Rotation
// place to store position data from robot
long X1 = 0;
long Y1 = 0;
long Z1 = 0;
long R1 = 0;
int NEXT = 1; // ready for next variable request.
short VAL0 = 0x36;// TCC
short VAL1 = 0x0C;//Count
short VAL2 = 0x01;//R[] PR Register number
short VAL3 = 0x00;//X1
short VAL4 = 0x00;//X2
short VAL5 = 0x00;//X3
short VAL6 = 0x00;//Y1
short VAL7 = 0x00;//Y2
short VAL8 = 0x00;//Y3
short VAL9 = 0x00;//Z1
short VAL10 = 0x00;//Z2
short VAL11 = 0x00;//Z3
short VAL12 = 0x00;//Rotation 1
short VAL13 = 0x64;// Rotation 2 R1 and R2 combine to send rotation in degrees devided by 100
// SETUP ************************************************************************************
void setup() {
// Load the G-code file into an array
gcodeLines = loadStrings("test.gcode");
size(400, 200);
background(255);
textAlign(LEFT, TOP);
textSize(16);
fill(0);
// Process the first line of G-code
processLine(currentLineIndex);
// Setup the serial port for FANUC sensor input. The 'O' is of odd parity.
myPort1 = new Serial(this, "COM4", 19200, 'O', 8, 1);
//Serial(parent, portName, baudRate, parity, dataBits, stopBits)
}
//*******************************************************************************************
// MAIN LOOP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void draw() {
// serial send section**********************************
if (WRITE == 0) {
if (STAGE == 0) {
//x = x - 70;
//STORE = x;
//print("STAGE=");
//println(STAGE);
VAL0 = 0x36;// TCC
VAL1 = 0x0C;//Count
VAL2 = 0x01;//R[] PR Register number
VAL3 = 0x00;//X1
VAL4 = 0x00;//X2
VAL5 = 0x00;//X3
VAL6 = 0x00;//Y1
VAL7 = 0x00;//Y2
VAL8 = 0x00;//Y3
VAL9 = 0x00;//Z1
VAL10 = 0x00;//Z2
VAL11 = 0x00;//Z3
VAL12 = 0x00;//Rotation 1
VAL13 = 0x64;// Rotation 2 R1 and R2 combine to send rotation in degrees devided by 100
// take the gcode and send it through to robot ( make any adjustments here )
//x = Float.floatToIntBits(gx);
//y = Float.floatToIntBits(gy);
//z = Float.floatToIntBits(gz);
// r = Float.floatToIntBits(gspeed);
x = int(gx * 100);
y = int(gy * 100);
z = int(gz * 100);
r = int(gspeed * 100);
x = x;
y = y;
z = z;
r = r/100; // sent to robot as 1955.8 as 19.550 because of degree limitations. 0-365. So on robot need to * 100 to go from 19.550 to 1955.0 rounds off decimal.
//r = 100 ;
if(r == 0){r = 1000;} // fix a potential error state
// if larger than 255 grab a 4 digit hex, and cut off the last two and make that the second to last slot before BCC
if (x >= 255) {
String VAL = hex(x, 4);
VAL = VAL.substring(0, VAL.length() - 2);
VAL4 = Short.parseShort(VAL, 16) ;
}
// store value of x into last byte before BCC
if (x >= 0) {
//String VAL5A =hex(x,2);
//VAL5 = convertStringToHex(VAL5A);
VAL5 = Short.parseShort(hex(x, 2), 16) ;
}
// if larger than 255 grab a 4 digit hex, and cut off the last two and make that the second to last slot before BCC
if (y >= 255) {
String VAL = hex(y, 4);
VAL = VAL.substring(0, VAL.length() - 2);
VAL7 = Short.parseShort(VAL, 16) ;
}
// store value of x into last byte before BCC
if (y >= 0) {
//String VAL5A =hex(x,2);
//VAL5 = convertStringToHex(VAL5A);
VAL8 = Short.parseShort(hex(y, 2), 16) ;
}
// if larger than 255 grab a 4 digit hex, and cut off the last two and make that the second to last slot before BCC
if (z >= 255) {
String VAL = hex(z, 4);
VAL = VAL.substring(0, VAL.length() - 2);
VAL10 = Short.parseShort(VAL, 16) ;
}
// store value of x into last byte before BCC
if (z >= 0) {
//String VAL5A =hex(x,2);
//VAL5 = convertStringToHex(VAL5A);
VAL11 = Short.parseShort(hex(z, 2), 16) ;
}
// if larger than 255 grab a 4 digit hex, and cut off the last two and make that the second to last slot before BCC
if (r >= 255) {
String VAL = hex(r, 4);
VAL = VAL.substring(0, VAL.length() - 2);
VAL12 = Short.parseShort(VAL, 16) ;
}
// store value of x into last byte before BCC
if (r >= 0) {
//String VAL5A =hex(x,2);
//VAL5 = convertStringToHex(VAL5A);
VAL13 = Short.parseShort(hex(r, 2), 16) ;
}
// temp use to fill all vars with X
//VAL7 = VAL4;
//
//VAL10 = VAL4;
//VAL11 = VAL5;f
/*
// debug print to terminal to see what is being sent.
print("Compiled data string: Decimal X:");
print(x);
print(" Y:");
print(y);
print(" Z:");
print(z);
print(" R:");
print(r);
print(" |HEX="); // decimal value for debugging
print(hex(VAL1, 2));
print("-");
print(hex(VAL2, 2));
print("-");
print(hex(VAL3, 2));
print("-");
print(hex(VAL4, 2));
print("-");
print(hex(VAL5, 2));
print("-"); // print serial string
print(hex(VAL6, 2));
print("-");
print(hex(VAL7, 2));
print("-");
print(hex(VAL8, 2));
print("-");
print(hex(VAL9, 2));
print("-");
print(hex(VAL10, 2));
print("-");
print(hex(VAL11, 2));
print("-");
print(hex(VAL12, 2));
print("-");
print(hex(VAL13, 2));
print("-");
println(hex(VAL1 ^ VAL2 ^ VAL3 ^ VAL4 ^ VAL5 ^ VAL6 ^ VAL7 ^ VAL8 ^ VAL9 ^ VAL10 ^ VAL11 ^ VAL12 ^ VAL13)); // calculate BCC
*/
}
// (X) Send to serial port, start the process.***************
// Start the call and wait for a response
if (STAGE == 0) {
myPort1.write(STARTCALL);
//delay(10);
STAGE = 1;
READY = 0;
//debug("stage = 1");
// println("* (PR) START CALL *");
}
// send out the serial data here ***************
if (STAGE == 1 && READY == 1) {
//myPort1.write(GO50);
// X AXIS ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
myPort1.write(VAL0); // TCC Sending position register to robot PR
myPort1.write(VAL1); // COUNT how many data bytes will follow ( 0x0C or 13 )
myPort1.write(VAL2); // R[] number this is what register to write to ( for this PR[1] )
myPort1.write(VAL3); // X1 First byte of the X data ( For this always 0 ) Leading zeros are used here
myPort1.write(VAL4); // X2 Second Byte of the X data ( Only used if over 255 )
myPort1.write(VAL5); // X3 Thrd Byte of X data, this is used for every number from 0-255
myPort1.write(VAL6); // Y1
myPort1.write(VAL7); // Y2
myPort1.write(VAL8); // Y3
myPort1.write(VAL9); // Z1
myPort1.write(VAL10); //Z2
myPort1.write(VAL11); //Z3
myPort1.write(VAL12); //R1
myPort1.write(VAL13); //R2
myPort1.write(VAL1 ^ VAL2 ^ VAL3 ^ VAL4 ^ VAL5 ^ VAL6 ^ VAL7 ^ VAL8 ^ VAL9 ^ VAL10 ^ VAL11 ^ VAL12 ^ VAL13); //BCC Error correcting byte done with XOR ( Exclusive or comparison '^')
//println("* (PR) DATA SENT *");
//delay(10);
READY = 0;
STAGE = 3;
}
// data sent, end the call.
if (STAGE == 3 && READY == 1) {
myPort1.write(ENDCALL);
//delay(10);
STAGE = 10;//10
//println("Waiting for 0x05 from Robot.");
// println("* (PR) END CALL *");
//88888888888888888888888888888888888888888888888888888888888888888888
/*
currentLineIndex++;
if (currentLineIndex < gcodeLines.length) {
processLine(currentLineIndex);
WRITE = 0; // send new data to robot
} else {
println("End of file reached.");
exit(); // Exit the program when all lines have been processed
} // if robot sends data, it is ready for updated coordinates.
// myPort1.write(ACK);
//delay(100);
*/
//STAGE = 0;
READY = 0;
//delay(1);
//88888888888888888888888888888888888888888888888888888888888888888888
}
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
// wait for a response from the robot of 0x05, to say it is ready for the next line.
if(STAGE == 100){
//println("Waiting for 0x05 from Robot.");
if(GO == 1){
STAGE = 10;
GO = 0;
}
//STAGE = 10; //temp use
}
//(Y) Send to serial port, start the process.***************
// Start the call and wait for a response
if (STAGE == 10) {
//delay(50);
myPort1.write(STARTCALL);
//delay(10);
STAGE = 11;
READY = 0;
//debug("stage = 1");
//println("* (RUN) START CALL *");
}
// send out the serial data here ***************
if (STAGE == 11 && READY == 1) {
// RUN command send to register ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
VAL0 = 0x5a;
VAL1 = 0x04;
//VAL2 = 0x05;
VAL3 = 0x00;
//VAL4 = 0x00;
//VAL5 = 0x3C;
VAL2 = 0x08; // #8 (RUN)
VAL4 = 0x00; // leading zeros
VAL5 = 0x01; // #1 = All data sent, run command. #0 is robot ran and is now waiting.
myPort1.write(VAL0); // TCC what it is trying to send ( Register info )
myPort1.write(VAL1); // COUNT how many data bytes will follow ( for this always 4 )
myPort1.write(VAL2); // R[] number this is what register to write to ( for this always #5 )
myPort1.write(VAL3); // D1 First byte of the data ( For this always 0 ) Leading zeros are used here
myPort1.write(VAL4); // D2 Second Byte of the data ( Only used if over 255 )
myPort1.write(VAL5); // D3 Trd Byte of data, this is used for every number from 0-255
myPort1.write(VAL1 ^ VAL2 ^ VAL3 ^ VAL4 ^ VAL5); //BCC Error correcting byte done with XOR ( Exclusive or comparison '^')
//println("* (RUN) DATA SENT *");
//delay(10);
READY = 0;
STAGE = 13;
}
// data sent, end the call.
if (STAGE == 13 && READY == 1) {
myPort1.write(ENDCALL);
//delay(10);
STAGE = 101;//0
READY = 0;
//STOREX = x;
//STOREY = y;
//println("* (RUN) END CALL *");
WRITE = 1; // all data has been sent stop.
// delay(500);// slows time commands are send out
}
}// end WRITE = 0;
// receive Register of RUN from robot &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
if (WRITE == 1) {
//println("Waiting for 0x05 from robot ......");
//if (SEND == 1 || READY == 1 || GO == 1) {
// WRITE = 0;
// SEND = 0;
GO = 0;
// } // if robot sends data, it is ready for updated coordinates.
myPort1.write(ACK);
// myPort1.write(ACK);
//GO = 1;
//delay(10);
WRITE = 2;
}
// receive Register of RUN from robot &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
if (WRITE == 2) {
// myPort1.write(ENDCALL);
if (GO == 1) {
WRITE = 0;
//SEND = 0;
GO = 0;
//println("recived 0x05 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> moving on to next gcode line");
STAGE = 0;
currentLineIndex++;
println(currentLineIndex);
if (currentLineIndex < gcodeLines.length) {
processLine(currentLineIndex);
WRITE = 0; // send new data to robot
} else {
println("End of file reached.");
exit(); // Exit the program when all lines have been processed
} // if robot sends data, it is ready for updated coordinates.
// myPort1.write(ACK);
//delay(3000);
}
}
// Check the FANUC serial port for data *********************************************
if ( myPort1.available() > 0) { // If data is available,
byte[] inBuffer = new byte[7];
inBuffer = myPort1.readBytes();
myPort1.readBytes(inBuffer);
if (inBuffer != null) {
//String myString = new String(inBuffer);
//}
// println(inBuffer);//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
if (inBuffer[0] == 6) {
// println("Acknoledge 0x06");
READY = 1;
}
if (inBuffer[0] == 5 ) {
// println("Robot Request to send 0x05 >>>>>>>>>>>>>>>>>>>>>>>>");
//SEND = 1;
GO = 1;
myPort1.write(ACK);
println("Recived 0x05 G0 = 1");
}
if (inBuffer[0] == 132) {
// println("Robot ended coms 0x84");
NEXT = 1;
//GO = 1;
}
if (inBuffer[0] == -124) {
//println("Robot ended coms 0x84");
NEXT = 1;
SEND = 1;
//GO = 1;
}
if (inBuffer.length >= 2) {
if (inBuffer[1] == 5) {
// println("Robot Request to send 0x05");
//SEND = 1;
//GO = 1;
}
}
// if we get data back from robot (R[] data)
if (inBuffer[0] == 85) { // == 85
//println(inBuffer);
//inBuffer[0] is TCC or 85
//inBuffer[1] is Length or 3
//inBuffer[2,3,4] ae the data bits or the number for R[] in robot
//inBuffer[5] is the BCC, ignoring for now.
//if(inBuffer[2] == -1){ } //inBuffer[2] = 0;
//if(inBuffer[3] == -1){ inBuffer[3] = 0;}
long VALUE = 0;
// conversion logic
if (inBuffer[2] != -1) {
VALUE = inBuffer[3] * 256 + inBuffer[4];
}
if (inBuffer[2] == -1) {
int MULT = 1;
//if(inBuffer[3] <= -1){MULT = int(inBuffer[3]); MULT = MULT - 1; VALUE = MULT * -128 + inBuffer[4];}
if (inBuffer[3] <= -1) {
VALUE = (int(inBuffer[3]) * -256) + inBuffer[4];
}
//if(inBuffer[3] <= -2){VALUE = abs(inBuffer[3]) * -256 + inBuffer[4];}
}
int r = 0;
byte b0 = 127;
if ((inBuffer[2] & 0x80) != 0) {
r |= b0 << 24;
}
r |= inBuffer[2] << 16;
r |= inBuffer[3] << 8;
r |= inBuffer[4];
// print("RESULT OF CONVERSION TO INT: ");
GO = 1;
//println(r);
//if(VALUE < 0){VALUE = VALUE + 256;}
//NEXT = 1;
if (POS == 4) {
POS = 5; // Stop for now
//print("R-POS:");
//println(VALUE);
R1 = VALUE;
}
if (POS == 3) {
POS = 4; // move on to R
//print("Z-POS:");
//println(VALUE);
Z1 = VALUE;
}
if (POS == 2) {
POS = 3; // move on to Z
//print("Y-POS:");
//println(VALUE);
Y1 = VALUE;
}
if (POS == 1) {
POS = 1; // move on to Y was 2
//print("X-POS:");
//println(VALUE);
X1 = VALUE;
}
//RSTAGE = 2;
}
}
}
}// void draw
void keyPressed() {
// When a key is pressed, process the next line of G-code
currentLineIndex++;
println("key advance next line");
if (currentLineIndex < gcodeLines.length) {
processLine(currentLineIndex);
WRITE = 0; // send new data to robot
} else {
println("End of file reached.");
exit(); // Exit the program when all lines have been processed
}
}
void processLine(int index) {
// Extract X, Y, Z coordinates, and speed from the current line
String[] tokens = splitTokens(gcodeLines[index], " ");
gx = getValue(tokens, 'X');
gy = getValue(tokens, 'Y');
gz = getValue(tokens, 'Z');
gspeed = getValue(tokens, 'F');
if(gspeed == 0){gspeed = 1000;} // fix a potential error state
// Keep the last value if the current value is 9999
if (gx == 9999) {
gx = lastX;
} else {
lastX = gx;
}
if (gy == 9999) {
gy = lastY;
} else {
lastY = gy;
}
if (gz == 9999) {
gz = lastZ;
} else {
lastZ = gz;
}
if (gspeed == 9999) {
gspeed = lastSpeed;
} else {
lastSpeed = gspeed;
}
// Display the extracted values on the screen
background(255);
text("X: " + gx + "\nY: " + gy + "\nZ: " + gz + "\nSpeed: " + gspeed, 20, 20);
}
float getValue(String[] tokens, char identifier) {
// Helper function to extract a value from the tokens based on the identifier (X, Y, Z, F)
for (String token : tokens) {
if (token.charAt(0) == identifier) {
return float(token.substring(1));
}
}
return 9999; // Return 0 if the identifier is not found
}
Take note of the Serial port (Com) number, I am using a USB to serial adapter for this.
You will need to have a gcode file that is X,Y,Z coordinates only, no arcs. Also F values for feed rate or speed.
Also, no negative numbers, It is best to set a user frame to 0,0,0 of where you plan to work, and have all work offset from there.
As I add more features and figure out arcs, I will update the code.
NOTE: This is an active project, so check back often as code and this page update.
Any questions post them in the comments bellow.