• Scam Alert. Members are reminded to NOT send money to buy anything. Don't buy things remote and have it shipped - go get it yourself, pay in person, and take your equipment with you. Scammers have burned people on this forum. Urgency, secrecy, excuses, selling for friend, newish members, FUD, are RED FLAGS. A video conference call is not adequate assurance. Face to face interactions are required. Please report suspicions to the forum admins. Stay Safe - anyone can get scammed.

GCode alternatives

My understanding is M-codes are Macros, which in a lot of cases can become machine application specific. While there are standards, the more I see both G and M codes vary with machine and application.

If you note Fusion, SW, Mastercam and others have options to specify the machine to tweak the conversational language to write machine specific code. Generic is a good starting point, but machine specific is what is required.
I hesitate to use the word MACRO since my background is computer science although I can see how it can be thought of as that.

If it were a MACRO from the programming perspective then the M6 instruction would be expanded into a number of other G-Code instructions. But in many ways the enhancement of an Mx command is more like a function or subroutine call that exists in another file rather than the current one. The M98 and M99 branch and return from a different section of the existing G-Code program so the G-Code interpreter has to locate the O4000 statement when it sees the M98 P4000 line. It returns to the next line when it encounters the M99.

That makes the M98 more like an assembly language subtroutine CALL and the M99 the RET instruction. Or in BASIC GOSUB and RETURN.

If it were a true MACRO for a sequence of G-Codes then a new file would first be created from the source file and at each location of the MACRO there might be an extra 100 lines of G-Code representing the MACRO expansion. I don't think G-Code interpreters do it that way.

But I'm new to this.
 
I don't think anyone would throw away their power feed for their X axis (or Y for that matter) in favour of using the handles. And even just with an old windshield washer motor, toothed belts and pulleys along with a battery charger people have created a power feed for their Z Knee because cranking gets old really fast.

So, if the power feed instead of a knob and a switch was a button on the screen or keypad or MPG pendant I think we'd still like it better than manual turning of handles. And if you have a chunk of aluminum you need to face with your 2" 4 insert carbide face mill it's still kind of a pain to wind it back and forth, even with power feed, a number of times to bring it down the amount you want.

That's were the wizards in MACH3 come in handy. This 3.5" x 8" block needs to be 0.4" thinner. At 0.1" per cut it's 4 passes. Very tedious.
1688249520721.webp


But click on the Post G Code button and you get this that can be saved as file or just run from the main window.
No fancy macros. You're responsible for turning on the spindle and setting the tool zero point along with XY. These become second nature with a bit of practice or various edge finding tools; mechanical or electronic. I've added the comments.
F20 (20 IPM)
G00 Z2 (Go to the safe Z position)
G00 X-5 Y-1 (then to the starting point.
G00 Z-0.1 (bring the tool down. We could change to G1 Z-0.1 F5 if we wanted to do that more slowly)
F20 (Back to 20 IPM)
G01 Y-1 (and now start milling the surface)
G01 X9
G01 Y0.5
G01 X-1
F20
G01 Y2
G01 X9
G01 Y3.5
G01 X-1
G01 Y4.5
G01 X9
G00 Z2 (Go up)
G00 X-5 Y-1 (Back to starting point)
G00 Z-0.2 (next level and another 0.1" pass)
F20
...
This does become way easier than manual. Just the learning curve can be steep.
 
I'm somewhat conversant with Gcode. In fact I've written a new post (the software that converts CAD stuff to Gcode) for Vectric products, handcoded stuff for converting a point cloud to X/Y/Z movements, written probing routines, etc.

I see Gcode as an ugly, cryptic language and generally not desirable. However, what specific problems would a replacement solve? Rather few machinists (at least the younger ones) write Gcode programs and it is almost always quick to go back to the CAD, make changes and re-post plus updating the CAD ensures that changes are tracked. We no longer have to punch reels of paper tape! There are numerous software packages than manage to generate Gcode. What is the impetus to adopt a replacement?
 
But facing is still easy to do with a manual operating. A 3.5" circular pocket 0.9" deep on a piece that is too large to to clamp to the lathe faceplate. Tedious with first a hole, then boring bar gradually getting it large enough to make that size pocket. Again MACH3 wizard to set up all the parameters.

1688250918265.webp


This code generates spindle control etc. Here's a little bit of it. I won't go through the details but the key info is the R0.1 etc for the radial cuts. Very hard to do with two handles or one handle and power feed on the other.

G0 G49 G40 G17 G80 G50 G90
M6 T4(TOOL DIA.0.5)
G64
G20 (Inch)
M03 S1000
M08
G00 G43 H4 Z0.1
X0 Y0
G01 Z-0.25 F1
G2 Y0 X0.1 R0.05 F30
Y0 X-0.1 R0.1
Y0 X0.2 R0.15
Y0 X-0.2 R0.2
Y0 X0.3 R0.25
Y0 X-0.3 R0.3
Y0 X0.4 R0.35

And BTW, LinuxCNC is far worse. It doesn't really have the graphical input unless you are running a TORMACH which has added this to their LinuxCNC user interface screen.

Jon Elson, who sells servo motor drives for Linux has a series of stand alone C programs to do much of this. you enter all the commands in on the command line in a command window and then save the results. Perfectly describes what I dislike about Linux in general.

So I started converting his programs over to Lazarus which is like Turbo Object Pascal 5.0. Runs on MACs, Windows, Linux.

My program still needs some work but it can do it with R or IJ commands for tool path creation. Again the credit for the code goes to Jon Elson.
1688251698056.webp


( Bore Hole using R commands, G-Code in "P:\Milling Machine\linuxcnc\MakeBore_G-Code\MakeBore.ngc")
N10 G01 F30.000 X0.0000 Y0.0000
N20 F5.000 Z-0.1000
N30 F30.000 X0.0625
N40 G03 X0.0000 Y0.0625 R0.0625
N50 X-0.1250 Y0.0000 R0.0781
N60 X0.0000 Y-0.1875 R0.1354

Suddenly making a hole is easy.
 
I'm somewhat conversant with Gcode. In fact I've written a new post (the software that converts CAD stuff to Gcode) for Vectric products, handcoded stuff for converting a point cloud to X/Y/Z movements, written probing routines, etc.

I see Gcode as an ugly, cryptic language and generally not desirable. However, what specific problems would a replacement solve? Rather few machinists (at least the younger ones) write Gcode programs and it is almost always quick to go back to the CAD, make changes and re-post plus updating the CAD ensures that changes are tracked. We no longer have to punch reels of paper tape! There are numerous software packages than manage to generate Gcode. What is the impetus to adopt a replacement?
One can say the same thing about programming micro-controllers. Assembler hand coding each instruction with switches is pretty raw. Hand assemble the code from the processor data sheet, enter the address, the data byte, toggle to write it. Rinse and repeat.
1688251908248.webp

Eventually we had an OS and could write in Assembler mnemonics and labels and some people do still write assembler code. Here's some for an ATMEL which is just about as cryptic as G-Code.

Code:
    .include "m328pdef.inc"

    .def    mask     = r16        ; mask register
    .def    ledR     = r17        ; led register
    .def    oLoopR     = r18        ; outer loop register
    .def    iLoopRl = r24        ; inner loop register low
    .def    iLoopRh = r25        ; inner loop register high

    .equ    oVal     = 71        ; outer loop value
    .equ    iVal     = 28168        ; inner loop value

    .cseg
    .org    0x00
    clr    ledR            ; clear led register
    ldi    mask,(1<<PINB0)        ; load 00000001 into mask register
    out    DDRB,mask        ; set PINB0 to output

start:    eor    ledR,mask        ; toggle PINB0 in led register
    out    PORTB,ledR        ; write led register to PORTB

    ldi    oLoopR,oVal        ; initialize outer loop count

oLoop:    ldi    iLoopRl,LOW(iVal)    ; intialize inner loop count in inner
    ldi    iLoopRh,HIGH(iVal)    ; loop high and low registers

iLoop:    sbiw    iLoopRl,1        ; decrement inner loop registers
    brne    iLoop            ; branch to iLoop if iLoop registers != 0

    dec    oLoopR            ; decrement outer loop register
    brne    oLoop            ; branch to oLoop if outer loop register != 0

    rjmp    start            ; jump back to start
.
All just to blink an LED. Or we can now use the modern Arduino environment and blink the LED this way.
C-like:
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  delay(1000);                      // wait for a second
  digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  delay(1000);                      // wait for a second
}

Again more readable and we don't care what the bits and bytes look like. All handled under the covers.

I agree with @kstrauss that what would you change G-Code into? A graphical interface already exists in a wider variety of forms for CNC control and can literally be used like automated power feed.
 
This does become way easier than manual. Just the learning curve can be steep.

Don't have a power feed on any axis yet. Not sure I ever will. Too much coin I'd rather spend elsewhere.

Don't mind taking multiple passes by hand.

Main reason for power x/y axis for me would be travelling a long distance a bit quicker, not milling a part.

Definitely want Power Z though. My 20V Dewalt Drill has better things to do than sit there waiting to lift or drop the knee on my mill.
 
Code:
tools {
 drillTool {size = 21/64, type = DRILL, length = 4.01, steel = 500 rpm, aluminium = 800 rpm}
 spotDrill { size = 6mm, type = SPOTDRILL, length = 2.05, steel = 500, aluminium 1250}
 threadTool {size = 1/4, type = TAP, length = 3.04, steel = 150, aluminium = 300}
};

toolPositions { T1=drillTool, T2=spotDrill, T3=threadTool};

program {
   drillTable { 1 = {0.5,-0.5,-0.5} 2= {1.0,-0.5,-0.5} 3={1.5,-0.5,-0.5} }

   material=ALUMINIUM;
   coolantOn()

   moveTo( 1.0, 1.0, 0.1)

   spotDrill.spotDrill( 0.25, drillTable);
   drillTool.peckDrill( 0.1 pecks, drillTable);
   theadTool.threadHoles( drillTable);

}
 
Last edited:
Don't have a power feed on any axis yet. Not sure I ever will. Too much coin I'd rather spend elsewhere.

Don't mind taking multiple passes by hand.

Main reason for power x/y axis for me would be travelling a long distance a bit quicker, not milling a part.

Definitely want Power Z though. My 20V Dewalt Drill has better things to do than sit there waiting to lift or drop the knee on my mill.
My mill came with an X power feed. After having that I'd never let it go.
I did put a stepper motor on the knee. Then upgraded it because it was slower than by hand and would lock up. The final motor was larger and gave me 25 ipm. So to move the full 12" or so took roughly 30 seconds. Now it's at 150 IPM or 2.5" per second at full speed. Love it!

What I wanted to do with my mill, and may still do is create the equivalent of a pendant with BEGIN/END position buttons like my ELS.

Think of it this way. You have two movable switches on your X axis that control the X axis power feed depending on the direction. So hit the logical right most switch moving to the right and it stops. But you can go left away from that activated switch.

The left switch is tripped with the opposite direction motion but you can move off it back to the right. Loosen a knob to slide the switches on a track to where you want them. Dial in the feed speed you want. Set the Quill or Knee height for say a 0.1" depth of cut. Engage power feed at some dial setting and go have a coffee. When you get back it's done a pass and stopped on the switch. Raise the quill (lower the knee) and fast speed back to the other switch. Lower the quill for now 0.2" and engage to cut another pass. Go grab a doughnut to go with that coffee.

That's the mechanical approach all very logical and simple wiring with a relay and regular power feed.

From the software perspective on a machine that has CNC it's also easy. Set the BEGIN position to X=1.5" and the END position to X=5.5".
Move the Z axis up away from the work. Bring the tool over the work where you want to cut a pass and lower it until the tool bit just barely scratches the surface. Zero that axis just like you would on a DRO. Now move to the BEGIN position and lower the tool to -0.1"

Press START and the system moves from BEGIN to END. In effect the switches are software rather than hardware. But it's not different really.
When it's done move the Z to 0.0. Then Move at high speed from END to BEGIN position. Lower Z to 0.2" Press START to move from BEGIN to END.

The only real difference is you're not standing over the machine waiting for the power feed to bring it to the end position or spending 2 minutes slowly turning the hand crank to move the table 4".

And with the MDI input line in the CNC program you type in this to move at 2 IPM so 2 minutes to move 4"
G0 Z0
G0 X1.5
G1 Z-0.1
G01 X5.5 F2
G0 Z0.0
G0 X1.5
G01 Z0.2
G01 X5.5 F2

And so on. Write that into a text program and load it as a GCode and just press start instead. A lot of extra steps and typing. Setting up a few fields like feed rate, spindle speed cutting speed and begin/end positions and then pressing start is much easier.
 
tools {
drillTool {size = 21/32, type = DRILL, length = 4.01, steel = 500 rpm, aluminium = 800 rpm}
spotDrill { size = 6mm, type = SPOTDRILL, length = 2.05, steel = 500, aluminium 1250}
threadTool {size = 1/4, type = TAP, length = 3.04, steel = 150, aluminium = 300}
};

toolPositions { T1=drillTool, T2=spotDrill, T3=threadTool};

program {
drillTable { 1 = {0.5,-0.5,-0.5} 2= {1.0,-0.5,-0.5} 3={1.5,-0.5,-0.5} }

material=ALUMINIUM;
coolantOn()

moveTo( 1.0, 1.0, 0.1)

spotDrill.spotDrill( 0.25, drillTable);
drillTool.peckDrill( 0.1 pecks, drillTable);
theadTool.threadHoles( drillTable);

}
Exactly. Easier than G-Code but a lot to learn too. But then so is the CAM program.
 
I agree that most people find the Arduino environment more intuitive than the magically generated assembler. I suspect that most Arduino programmers have never even looked at the generated assembler code. Would any benefit if the C-compiler generated Pascal code or whatever that is more readable and more intuitive than assembler?

Today virtually everything is designed in some flavour of CAD and magically converted into cryptic Gcode with CAM software. Most machinists never look at the Gcode. Rather like the situation with the Arduino environment producing assembler as an intermediate to actual machine instructions.
 
Other than the list of points to tap here's the G-Code for a similar type of operation. Once you've learned the basic G-Code it's not that tough to understand. And the program @Janger posted would likely compile to G-Code like this.

g17 g20 g40 g49 g54 g64 g80 g90 g94
(Spot Drill )
t1m6g43
F20
G0 Z1.0
X0.5 y0.0
S1000 M3
G01 Z0.25 F20
G81 x0.5 y0 z-0.25 R0.25
M5
(Peck Drilling #21 0.75 deep)
t7m6g43
S1000 M3
G0 Z1.0
X0.5 y0.0
g01 Z0.0 F20
g83 x0.5 y0 z-0.75 r0.1 q0.05 F5
M5
(Tapping 1/4-20 0.7" deep)
t8m6g43
s200 m3
G0 X0.5 Y0 z1
G1 Z0.1 F20
G33.1 Z-0.7 K0.05
M5
G0 Z1
G0 X1.25 Y2.25
M2
%
 
I agree that most people find the Arduino environment more intuitive than the magically generated assembler. I suspect that most Arduino programmers have never even looked at the generated assembler code. Would any benefit if the C-compiler generated Pascal code or whatever that is more readable and more intuitive than assembler?

Today virtually everything is designed in some flavour of CAD and magically converted into cryptic Gcode with CAM software. Most machinists never look at the Gcode. Rather like the situation with the Arduino environment producing assembler as an intermediate to actual machine instructions.
It's actually really hard to find the assembler or listing file in the Arduino world. It's created as a temp file and then promptly erased so very hard to even look to see how inefficient it might be.

I find Object C more difficult than Object Pascal but that's just me. I have a few complaints about Pascal too. At least you can look at the G-Code generated by the CAM program.
 
I agree that most people find the Arduino environment more intuitive than the magically generated assembler. I suspect that most Arduino programmers have never even looked at the generated assembler code. Would any benefit if the C-compiler generated Pascal code or whatever that is more readable and more intuitive than assembler?

Today virtually everything is designed in some flavour of CAD and magically converted into cryptic Gcode with CAM software. Most machinists never look at the Gcode. Rather like the situation with the Arduino environment producing assembler as an intermediate to actual machine instructions.

I know that assembler and machine language correlate 1 to 1. But processors don't really understand assembler. They understand machine language. So is that what you meant here or does the Arduino (and others) actually generate assembler which then gets converted to machine language?

On a side note - I actually miss the raw power and speed of programs written directly in assembler.
 
Machine language and assembler tend to be used interchangeably.
No one would look up op codes and addresses and program in bytes unless they are using a bare bones monitor etc. Think original imsai or pdp8.
 
I hesitate to use the word MACRO since my background is computer science although I can see how it can be thought of as that.

If it were a MACRO from the programming perspective then the M6 instruction would be expanded into a number of other G-Code instructions. But in many ways the enhancement of an Mx command is more like a function or subroutine call that exists in another file rather than the current one. The M98 and M99 branch and return from a different section of the existing G-Code program so the G-Code interpreter has to locate the O4000 statement when it sees the M98 P4000 line. It returns to the next line when it encounters the M99.

That makes the M98 more like an assembly language subtroutine CALL and the M99 the RET instruction. Or in BASIC GOSUB and RETURN.

If it were a true MACRO for a sequence of G-Codes then a new file would first be created from the source file and at each location of the MACRO there might be an extra 100 lines of G-Code representing the MACRO expansion. I don't think G-Code interpreters do it that way.

But I'm new to this.
In Centriods language they do
call it Macro's to and it does mean exactly what you think it means. By calling up these functions one line in code does many things and they must be added as a sub routine.
 
In Centriods language they do
call it Macro's to and it does mean exactly what you think it means. By calling up these functions one line in code does many things and they must be added as a sub routine.
I'm not sure I understand that.
 
Sorry miss typed, the M-code calls a series of steps that must be followed:

ie a tapping path with a mill, enter perimeters in the conversational language, with the M code and wil say follow a 1/2 UNC path for a given depth with a given series of cut depths.

In short a macro (sorry I started programming many years ago when they where still called subroutines).

Basically it allows you to design.

From what I understand if you dive deep enough you can modify individual G-codes to behave differently even though it falls within the basic layout. Machine or application specific.

I also am lead to understand that the language works as follows:

Conversational - very simple instructions that allow software to write your G-Code (what I use, example, clean out within this set of line to a depth of...and it creates the series of G-codes that do this).

G-M codes are the steps, start here, move this far, this fast, on this arc and so on. Part of makes this difficult to grasp is you are not define points only how to get there.

In the machine each code has macros that define a series of actions, some simple some complex.

The more I get into it, the more I understand why industry has not gotten away from G/M codes, simply because of the flexibility it allows.
 
As I dive into the combination of G-Codes and Python for modifying things like Tool Change and Tool Changers I am amazed at how well it works.

At the CAD level it's quite a bit simpler. At least with the MecSoft VisualCAM. For example: Same 3.5" hole. Same 0.9" depth. Same stepover. Paused this into the first 0.1" depth cut to show the circular path.
1688269154288.webp


Which turns out to actually be a series of linear moves. Here's a fragment of the first layer just before it moves back to the center and goes down to 0.2" depth. Notice it's all straight lines and it's not even all of them on this circle. This CAM package doesn't appear to let the machine trajectory planner handle the arc but uses G01 linear moves.

N222 X-0.1778
N223 X-0.523 Y1.3791
N224 X-0.8379 Y1.2139
N225 X-1.1041 Y0.9781
N226 X-1.306 Y0.6855
N227 X-1.4321 Y0.353
N228 X-1.475 Y0.
N229 X-1.4321 Y-0.353
N230 X-1.306 Y-0.6855
N231 X-1.1041 Y-0.9781
N232 X-0.8379 Y-1.2139
N233 X-0.523 Y-1.3791
N234 X-0.1778 Y-1.4642
N235 X0.1778
N236 X0.523 Y-1.3791
N237 X0.8379 Y-1.2139
N238 X1.1041 Y-0.9781
N239 X1.306 Y-0.6855
N240 X1.4321 Y-0.353
N241 X1.475 Y0. ( Last part of circle )
N242 G0 Z0.25 ( Move up )
N243 X0.1 ( Back to start position in middle )
N244 G1 Z-0.2 F29.3 ( Down to next level )

Compare that to the previous example of the C code ported to Lazarus Pascal which used G03 for ARC moves. So if all you have is a CAM package that does linear moves to simulate an arc then perhaps learning G-Code programming to create a much shorter program with G03 moves.

ie: Operating in G03 mode.
N320 X0.0000 Y1.4900 R1.4900 (last circle)
N330 G01 F30.000 X0.0000 Y0.0000 (Move back to center in G01 Linear motion)
N340 F5.000 Z-0.2000 (Next Level)

This is an example of why I like to look at what the C compiler makes and why I don't like that the Arduino hides it. Even now, when I write code I find with a new processor/compiler combination that writing the code one way rather than a different way to obtain the result can often generate wildly different code and processing speed.

For the older architecture paging processors I've had to tweak a function with assembler to access the correct memory location because the compiler didn't do it right. But then I'm old school.
 
Machine language and assembler tend to be used interchangeably.
No one would look up op codes and addresses and program in bytes unless they are using a bare bones monitor etc. Think original imsai or pdp8.

Yes, I understand this. My first microprocessor programming adventure started before assemblers were generally available. So I actually did program in machine language.

But perhaps that's why finding the Arduino assembler output is so difficult. Perhaps it doesn't do that. Perhaps it skips straight to outputting machine language.
 
Back
Top