Notes from a Machinist

I'm late to the party. Again.

Using Awk to Bore Deep Holes

2022-12-17

Table of Contents


Introduction

I’ve been making stator housings for underwater thrusters, in 316 stainless steel. I use Fusion 360 to create tool paths, and am generally happy with it, but needed a bit of extra software this time.

You can see an some of the interiors after the first operation in the photo above. They are fairly deep and I wanted a fairly rigid (i.e. thick) boring bar after drilling it out to two inches wide.

The problem I needed help with was clearing chips. I tried boring horizontally and vertically. I tried adding a very aggressive peck. But still, I found myself hovering around the machine, waiting for a nest of chips to get big, and then manually waiting for the next time the tool retracted to pause things and clear the chips. Finally I figured out a way to make the machine automatically pause and wait for me.

I’m writing this article for an audience of machinists who understand g code but may not be familiar with awk.

Awk Script

I ended up writing my first awk script as it seemed like a reasonble match for this problem with its ability to specify patterns and actions.

I’ve broken the script into pieces here with explanations and the full script is further down.

#!/usr/bin/env gawk

BEGIN { in_zone = 0 found_zone = 0 }

In the snippet above, BEGIN is a special pattern, run at the start of the script and { in_zone = 0 found_zone = 0 } is an action associated in with the pattern. The action sets two variables to 0 (false). It isn’t strictly necessary in awk; I believe that undeclared variables are considered to be 0/false but I find it is often more clear to be explicit about things like this.

in_zone is a flag, set to true when we are processing lines from the tool path that I want to modify.

found_zone is a flag that is used to track if we ever found the zone and is meant to help guard against the situation where something changed and the script silently fails. The script is fragile as it depends heavily on things that can change inside Fusion and I tried to add guards like this to notify me when things are going wrong.

1

In awk, each time a line is processed (in our case, from the g code output by the Fusion post-processor), every pattern is evaluated in order and if it matches, the associated action is run.

1 is a pattern that always evaluates to true and because I did not specify an action, awk defaults to writing the current line out unmodified.

/N17 T909$/ {
  if (in_zone != 0) {
    print "already in zone and found N17 T909$" > "/dev/stderr"
    err = 1
    exit 1
  }
  in_zone = 1
  found_zone = 1
  z_cnt = 1
}

/N17 T909$/ is a regular expression pattern which matches if a line ends with N17 T909 (specifying it this way means it will work whether or not a block delete character precedes it). The N17 and T909 are part of the fragility of this script and the script needs to be modified if things change. In retrospect it might have been useful to key off of the comment at the beginning of the tool path, rather than the line number.

The if block is some error checking.

The rest of it is keeping track of the fact that we have entered the zone and setting z_cnt to 1. The idea is that the script notices every time the boring bar retracts, and increments z_cnt and uses that to decide when to insert M0. More about this below.

/N18 T909/ {
  if (in_zone == 0) {
    print "not in zone and found N18 T909" > "/dev/stderr"
    err = 1
    exit 1
  }
  in_zone = 0
}

This pattern notices that we are now past the tool path we want to modify. There is some error checking and we set the in_zone variable to false.

/^G0 Z0.19$/ {
  if (in_zone != 0) {
    z_cnt = z_cnt + 1
    if (z_cnt%2 == 0 && wrote <= 5) {
      print "M0"
      print "M08"
      print "M03"
      wrote = wrote + 1
    }
  }
}

This is the main part of the script. Every time we retract to Z0.19 (more fragility, I know!), we increment z_cnt and then if it is an even number (z_cnt%2 == 0) and we have written less than 6 M0 blocks (wrote <= 5), then stop everything, and when the cycle start button is pressed, restart the coolant and spindle.

I arrived at this logic by observation. I found I could get two passes with the nest chips still being manageable enough. It helps that I am using pecking in that it makes it easier to remove them from the boring bar. Also, I found that after 5 stops, there was enough room in the hole for the coolant to clear the chips without my help.

END {
  if (err == 1) {
    exit 1
  }
  if (found_zone == 0) {
    print "never found N17 T909$" > "/dev/stderr"
    exit 1
  }
  if (in_zone != 0) {
    print "never found N18 T909" > "/dev/stderr"
    exit 1
  }

  printf "successfully inserted %d stops\n", wrote > "/dev/stderr"
}

This final block runs at the end of the script and is mostly about handling errors.

Full Script

Here is the full script

#!/usr/bin/env gawk

BEGIN { in_zone = 0 found_zone = 0 }

1

/N17 T909$/ {
  if (in_zone != 0) {
    print "already in zone and found N17 T909$" > "/dev/stderr"
    err = 1
    exit 1
  }
  in_zone = 1
  found_zone = 1
  z_cnt = 1
}

/N18 T909/ {
  if (in_zone == 0) {
    print "not in zone and found N18 T909" > "/dev/stderr"
    err = 1
    exit 1
  }
  in_zone = 0
}

/^G0 Z0.19$/ {
  if (in_zone != 0) {
    z_cnt = z_cnt + 1
    if (z_cnt%2 == 0 && wrote <= 5) {
      print "M0"
      print "M08"
      print "M03"
      wrote = wrote + 1
    }
  }
}

END {
  if (err == 1) {
    exit 1
  }
  if (found_zone == 0) {
    print "never found N17 T909$" > "/dev/stderr"
    exit 1
  }
  if (in_zone != 0) {
    print "never found N18 T909" > "/dev/stderr"
    exit 1
  }

  printf "successfully inserted %d stops\n", wrote > "/dev/stderr"
}

Other Ways I Could Have Approached This

I could have broken the tool path into 7 tool paths in Fusion, with different radii settings for each. An advantage of that is that there is no separate script to maintain and run. A disadvantage is that tweaks to the tool path become a lot more painful as I have to repeat them carefully 7 times. I understand that Mastercam has a feature meant specifically for this case, but don’t have any familiarity with it.

I could have modified the post processor. While I have modified post processors in the past successfully, I generally dislike doing that as it creates a burden to track future changes from autodesk and to merge them into my modified version.


Discuss here