G83 canned cycle, applicable to other canned cycles.

Home Forums TinyG TinyG Feature Requests G83 canned cycle, applicable to other canned cycles.

This topic contains 9 replies, has 4 voices, and was last updated by  arararar 3 years, 8 months ago.

Viewing 10 posts - 1 through 10 (of 10 total)
  • Author
  • #3444


    I’ve been thinking about how to program canned cycles, apparently while I was sleeping.  I thought I would get this out there  before I lost it.  I’ve gone ahead and started a new thread for the canned cycles.  I hope to add to this to this if anyone is interested.  I’ve not began looking at the TinyG code yet, but maybe this weekend, or if I get enough cycle time tonight.  (Running a big 2 pallet horizontal mill with Fanuc control, 80x65x47 inches working envelope)

    Generic G83 peck drill cycle:

    N10 G0 G90 G54 X1.0 Y1.0 Z1.0 ;
    N50 X1.0 ;
    N60 G80 ;

    This drills a 2.0 bolt square about G54 X0 Y0.
    (Yah, those are inches I’m using, you’ll pry my inches from my cold dead hands) 😛

    I’ve written some pseudo code for this, please excuse irregularities, general ugliness, syntax/grammar foulness.  I’m not very good at programming and use the lots of monkeys with typewriters method.  Also the sledgehammer method. 🙂  Probably about clear as mud.
    Pseudo code:

    Canned cycle sub called passing vars from call //G83 X1.0 Y1.0 Z-0.25 R0.1 Q0.1 F5.0//

    While Line != G80 //quit when G80 is reached//
      If Line has X
        Then store X in canned_X
        store current_X in canned_X
      End If

      If Line has Y
       Then store Y in canned_Y
        store current_Y in canned_Y
      End If                              //More of these type statements could be added for ABC axii//

      Output “G0 X(canned_X) Y(canned_Y) ;” //moves to first hole location or goes to where it already is//

      G83 sub called and passes (R Q z F) //G83 sub peck drills the hole//

           store current_Z in traverse_Z  //this is where it could be changed for G98,G99 function//
           Output “G0 Z(R) ;” //moves to rapid plane//
           drilled_distance = R  //we start drilling here//

          While Z != drilled_distance  //when drilled_distance is the same as Z we are done//

             drilled_distance = drilled_distance – Q  //start subtracting pecks from drilled_distance//

             If drilled_distance < Z  //We don’t want to drill deeper than Z so reset number to max Z depth//
                Then drilled_distance = Z
             End If

             Output “G1 Z(drilled_distance) F(F) ;” //drill a peck//
             Output “G0 Z(R) ;” //peck back out to Z0.1 in this example//

             If drilled distance != Z  // We don’t want to go back into hole if already gone to depth //
                Then Output “G0 Z(drilled_distance + .01) ;” //rapid back into hole .01 above last drilled depth//
             End If                                                                   //the .01 would generally be a peck return parameter set elsewhere like EEPROM//
        Loop While //Get ready for the next peck or quit//

      Output “G0 Z(traverse_Z) ;”  //move back up to our intial Z, Z1.0 in this case//
     End G83 sub

     Grab next line of program  //get ready to drill the next hole or quit//
    Loop While

    End canned

    Basically this takes the parameters from the G83 line and following lines until the G80.  It converts this into G0’s and G1’s.  G17 is assumed, and does not take into account G18 and G19.  This also does not provide for G98 and G99.  Bad things would happen if in G91 mode and not G90.

    Probably be best to convert all this to machine co-ords but not sure if that function is present, think I read that it wasn’t yet.

    Output would look like this for the first hole:

    G0 X1.0 Y1.0
    G0 Z0.1
    G1 Z0.0 F5.0
    G0 Z0.1
    G0 z0.01
    G1 Z-0.1 F5.0
    G0 z0.1
    G0 z-0.09
    G1 z-0.2 F5.0
    G0 z0.1
    G0 z-0.19
    G1 z-0.25 F5.0
    G0 z0.1
    G0 z1.0

    On to next hole.

    Again, this is just a rough idea but I would appreciate any input. Or tell me to get off your lawn. 🙂



    Some thoughts. Also, I’m going to move this to the github as an issue so it’s tracked better. See https://github.com/synthetos/TinyG/issues/25

    I think you can get to this w/o a login, but you may need a github login to comment. Best to continue this discussion over there if you do that. Sorry, this forum and the github serve somewhat different purposes but do overlap.

    First, machine (absolute) coordinates are implemented (G53), as are 6 work coordinate systems, G54, G55, G56, G57, G58 and G59. G92 offsets are also implemented as proper G92, G92.1, G92.2 and G92.3 as per Kramer (NIST RS274NGC-V3) If you remember where you read that machine coordinates are not available I’d appreciate a pointer. Sounds like the wiki has inconsistent data and I’d like to fix that. Otherwise I’ll just hunt for it. Time for a revision pass anyway.

    You are actually calling for 2 things in your code: canned cycles (like G83), and subroutines, or O codes in LinuxCNC (EMC2) speak. See: http://linuxcnc.org/docs/html/gcode/o-code.html

    Canned cycles (G81-G89 + G38.2 probes) are anticipated but to date the only thing that resembles a canned cycle is the homing cycle. Here’s what would have to happen in the code to add a new canned cycle (for when you get to looking at the code)

    – Add the G code and its parameters in gcode_parser.c. In the case of G83 Q word would also have to be added – this is not already in the Gcode model. That would need to be added to the GcodeModel and GcodeInput structures in canonical_machine.h

    – Next a canned cycle should be added as a canonical machining function in canonical_machine.c/.h.  This should call the actual cycle that would probably be in its own file, something like cycle_g83peck_drill.c. You can look at cycle_homing.c for an example of how this might work.

    – The controller in controller.c handles blocking and threading using a state machine as implemented in _controller_HSM() in controller.c. Essentially it starts the main loop at the lowest level of blocking (i.e. the highest priority routine) and continues down the list until a function would block. No actual blocking is allowed, so the function returns a “busy signal” (EAGAIN code). This causes the main loop to restart. For this to work the functions that would block need to be coded as continuations. Continuations are functions that are split into 2 parts – the part that gets called initially- which runs some init code and sets up some memory variables, then the continuation “callback” that gets called from the main loop. The cycles need to go into the right part of the main loop – in this case right under the homing callback. See the following for more details:



    O codes (subroutines) are more complicated. I’ve thought about this for some time now but have not bitten the bullet on this. There are at least 3 new things that need to be added for this to work. (1) subroutines and conditionals, (2) parameters, and (3) expressions. See the EMC O code page for how they implemented this. I’ve been careful to not step on the characters needed for expressions, so they are still available for use in Gcode lines. Parameters are a challenge for an embedded system with limited memory. They are doable, but there won’e be 5999 of them – not enough memory. Some form of sparse mapping will be required.  Hopefully I’ll be able to attack this at some point, but there are a lot of other things that should probably get done first. Just having canned cycles would be a help even if there were no subroutines.


    • This reply was modified 4 years, 7 months ago by  alden.


    Thank you for the response.  It seems I have homework. 🙂

    I’ve seen Github.  I’ll continue this there if I manage to come up with anything more to contribute.  I’ll run down the statement about machine co-ords not being implemented and let you know.  I think I’ve got my wife convinced I need this controller and hope to be playing with it soon. 🙂



    Thanks for your interest



    First, machine (absolute) coordinates are implemented (G53), as are 6 work coordinate systems, G54, G55, G56, G57, G58 and G59. G92 offsets are also implemented as proper G92, G92.1, G92.2 and G92.3 as per Kramer (NIST RS274NGC-V3) If you remember where you read that machine coordinates are not available I’d appreciate a pointer. Sounds like the wiki has inconsistent data and I’d like to fix that. Otherwise I’ll just hunt for it. Time for a revision pass anyway.

    These lines in the wiki:

    Instead of the all this TinyG implements the following:
    On power up the Gcode interpreter is set to zero (X,Y,Z), which makes the machine zero the current (possibly random) position of the tool. A single coordinate system is provided. G10, G43, and G54 – G59 are not implemented.
    A reduced functionality G92 / G92.1 is available that does the following: G92 accepts axis-value pairs for all axes. The value will set that axis to the value. One or more axes must be provided. Axes that are not provided are not changed. For example, to zero a robot you can enter the below. Or just G92.1 which is a G92 with all axes being equal to zero.

    This led me to think that G54 etc. wasn’t implemented.  Even though it appeared in my example g-code out of habit.  I was understanding the control to be implementing the G92 style of offsetting like Acramatic controls.  (Possibly my least favorite control ever, at least the versions from the ’80s and ’90s ) 🙂

    also the wiki states:

    — Unsupported Commands:

    G10 Coordinate system data
    G14, G15 Spiral motion
    G28, G30 Return to home (requires parameters)
    G38.2 Straight probe
    G40, G41, G42 Cutter radius compensation
    G43, G49 Tool length offsets
    G54 – G59.3 Select coordinate system (group 12)
    G61, G61.1, G64 Set path control mode (group 13)
    G81 – G89 Canned cycles
    G92 – G92.3 Coordinate system offsets
    G98, G99 Set canned cycle return level

    M6 Tool change
    M7, M8, M9 Coolant (group8)
    M48, M49 Enable/disable feed and speed override switches (group 9)



    Here is a Python33 script I have played with for massaging CamBam files with G81 and G83 blocks. I am new to Python, so you may want to edit it to your liking 🙂

    # expands canned drill g-codes

    import re
    import sys

    def ExtractParameters(block, parms):
    """extracts drill parameters from g-code block"""
    m = re.match(".*X([-]?\d+.\d+)", block)
    if m:
    parms["x"] = float(m.group(1))
    m = re.match(".*Y([-]?\d+.\d+)", block)
    if m:
    parms["y"] = float(m.group(1))
    m = re.match(".*Z([-]?\d+.\d+)", block)
    if m:
    parms["z"] = float(m.group(1))
    m = re.match(".*Q([-]?\d+.\d+)", block)
    if m:
    parms["q"] = float(m.group(1))
    m = re.match(".*R([-]?\d+.\d+)", block)
    if m:
    parms["r"] = float(m.group(1))
    m = re.match(".*F([-]?\d+.\d+)", block)
    if m:
    parms["f"] = float(m.group(1))

    def G81(parms, outFile):
    """expands canned drill g-code G81, standard drill"""
    outFile.write("G0 X{0} y{1}\n".format(parms["x"], parms["y"]))
    outFile.write("G0 Z0.01\n")
    outFile.write("G1 Z{0} F{1}\n".format(parms["z"], parms["f"]))
    outFile.write("G0 Z{0}\n".format(parms["r"]))

    def G83(parms, outFile):
    """expands canned drill g-code G83, peck drill"""
    outFile.write("G0 X{0} Y{1}\n".format(parms["x"], parms["y"]))
    peckCount = int(abs(parms["z"]) // parms["q"])
    if peckCount < 1: # drill depth less than peck depth outFile.write("G0 Z0.01\n") outFile.write("G1 Z{0} F{1}\n".format(parms["z"], parms["f"])) outFile.write("G0 Z{0}\n".format(parms["r"])) else: peckDepth = 0.0 while (peckCount > 0):
    rapidDepth = peckDepth + 0.01
    peckDepth -= parms["q"]
    outFile.write("G0 Z{0}\n".format(round(rapidDepth, 5)))
    outFile.write("G1 Z{0} F{1}\n".format(round(peckDepth, 5), parms["f"]))
    outFile.write("G0 Z{0}\n".format(parms["r"]))
    peckCount -= 1
    finalDepth = abs(parms["z"]) % parms["q"]
    if finalDepth > 0.0:
    rapidDepth = peckDepth + 0.01;
    outFile.write("G0 Z{0}\n".format(round(rapidDepth, 5)))
    outFile.write("G1 Z{0} F{1}\n".format(parms["z"], parms["f"]))
    outFile.write("G0 Z{0}\n".format(parms["r"]))

    def ProcessFile(parms, inFile, outFile):
    for block in inFile:
    if block.find("G98") != -1:
    elif block.find("G81") != -1:
    ExtractParameters(block, parms)
    G81(parms, outFile)
    elif block.find("G83") != -1:
    G83(parms, outFile)
    elif block.find("G80") != -1:

    if sys.argv == 3:
    inFile = open(sys.argv[1], "r")
    outFile = open(sys.argv[2], "w")
    fileName = input("Enter NC input file name: ")
    inFile = open(fileName, "r")
    fileName = input("Enter NC output file name: ")
    outFile = open(fileName, "w")

    drillParms = {"x":0.0, "y":0.0, "z":0.0, "q":0.0, "r":0.0, "f":0.0}
    ProcessFile(drillParms, inFile, outFile)



    Seems the code tag didn’t keep the formatting…



    Very cool, I’m going to try and start a blog this weekend on my cnc build.  I guess you saw my thread in the project forum.  As well as the blog I hope to get python on the Raspberry Pi interpretting the Tinyg JSON output.

    I’ve been thinking about the canned cycle stuff also.  We could take your script and modify it to break canned calls to straight g-code inline to the Tinyg.  Note that the Tinyg has a pretty good line numbering scheme and this would be very useful for something like this.  Strip any Nxxxx from the program on the Rpi and substitute another Nxxxx that is being sent to the Tinyg to keep proper track of the program.  The same methods to use canned cycles would also be applicable to calling sub programs(M98, M99) and some type of macro system.

    Have you done any gui stuff with python? Maybe we could set up a git for this and start working on it together, if you would be interested.  As you can see, I’m interested in using the Rpi for the frontend as it is cheap, has good support for the gpio and low level hardware, and would be a standardized platform.  I’ve been looking at using Python 2.  But if you want 3, we can do that.

    I’m a machinist by trade and at one time was profficent with Surfcam and Mastercam, been a few years since I was a fulltime cnc programmer but feel free to ask me any general cam or machining questions.  I’ve played with microcontrollers in JAL, C, and assembly as a hobby for 5 years or so.



    Actually that was my first Python script ever after reading a book on it for several hours, so I don’t have any GUI experience and there is a bug at the end of the scrip I have since fixed. All I was trying to accomplish was to expand the drill routines from CamBam into g-code that TinyG could handle and I wanted to try something different than Pearl. I won’t likely be writing much g-code by hand since I am happy with CamBam.

    I am not much of a machinist, I have a Sherline mill and lathe and took one machining class at a junior college about ten years ago. I am actually a software engineer and this year I mentored a FIRST robotics team on electrical since they seemed to be having reliability issues with their robots the last four years. This re sparked my interest in CNC since they could really use some help in this area as well. They have an old Sharp knee mill with an Anilam controller on it that is not seeing much use.

    I haven’t purchased the TinyG card yet for my pending Sherline conversion since I am still doing my homework. The only thing holding me back is the stepper motor drivers used on the board. I read a blog (dr-iguana.com) on stepper drivers and then I have started digging into a microchip application note on driver design using a dsp processor. I am still chewing on that (very technical) and now believe I might design my own driver board using their techniques, but make it TinyG compatible.




    Hello all,

    I’ve designed a board that I am running TinyG on and using larger external motor drivers.

    I’m wondering if canned cycles have been worked on at all since this request? It would really consolidate large gcode files that involve peck drilling…


Viewing 10 posts - 1 through 10 (of 10 total)

You must be logged in to reply to this topic.