Sunday 29 September 2019

Variables vs arguments for passing data

Passing data between macros:
I've struggled a bit with the issue of passing values when calling macros from within other macros. As there are quite a few levels of nesting in a typical probing operation, it's necessary to pass parameter values when you call one from another.

Some of the higher level macros seem to be perfectly happy to be passed parameters when you make a "command line" type call. In my relatively limited programming experience, these passed values are often called "arguments". In Centroid syntax, this will typically look something like this:

G65 "c:\cncm\probing\f360_probing-x.cnc" X[-8.] Y[20.] Z[50.] M[6.] F[1000.] D[56.] A[1] C[5.] H[3.] R[50.] W[01.]

Once inside the macro, you pick the parameters up and name them locally. From what I can see from existing examples, this requires something like the following:

DEFINE <x> #x
DEFINE <y> #y
DEFINE <z> #z
DEFINE <nominaldiameter> #m
DEFINE <feed> #f
DEFINE <depth> #d
DEFINE <approach> #a
DEFINE <clearance> #c
DEFINE <overtravel> #h
DEFINE <retract> #r
DEFINE <targetwcs> #w 

You can then use the named variables (rather than the short parameters) within expressions, such as this:

G65 "c:\cncm\probing\f360_probe_x.cnc" A[<approach>] C[<clearance> + <overtravel>]

and 

#100 = [#34006 + <approach> * #34009] ; (where did the hit occur)
However, that leaves the question of how to deal with "new" variables, which will either have to be created as named variables ("aliases") or as new (and therefore hopefully unallocated) numbered variables.

Defining aliases:
I tried to create my own new named variables ("aliases") using the DEFINE statement. This appears to be accepted by the interpreter ie it doesn't create any obvious error. However, it fails when I subsequently try to use said new variables in statements or expressions and may or may not be due to me also trying to include an equation in the definition. Needless to say, there is almost no coverage of this feature in the Centroid documentation and very few examples to go on. 

This works:

#100 = [#34006 + <approach> * #34009] ; (where did the hit occur)
But this doesn't:


<expected> = [<x> + <approach> * [<clearance> + <nominaldiameter>/2.0]], whether or not there was a DEFINE at the front, or a "=" sign.

This whole DEFINE / alias business turned into a bit of an unprofitable shit storm and I finally concluded that aliases were not the way to go. I will stick to using numbered variables inside macros.

This macro call works:

G65 "c:\cncm\probing\f360_update_x.cnc" W[<targetwcs>] H[#34006 + <approach> * #34009] E[[<x> + <approach> * [<clearance> + <nominaldiameter>/2.0]]]

Inside the macro, we have:
DEFINE <wcs> #w
DEFINE <hitfound> #h

DEFINE <expected> #e
...
etc
...
#[#34831] = #[#34831] + #h - #e ; updates the WCS value.

Conventionally, local variables are numbered #100-300 if I understand correctly. However, these are local and volatile ie not for passing between macros, with values that evaporate when you leave the current macro. For higher level, more global variables that can be accessed and shared by multiple macros, you'd want to allocate a unique variable number for each new usage. 

Aha - plenty of system variables!!
It's surely no coincidence that Centroid have created a whole slew of unique system variables in the 30000-34999 range. Each appears to have a unique usage - and there are quite a few gaps which I'm guessing I could grab for my own needs. In particular, there is a fine looking gap between 34100 - 34499. I'm planning on making these my own. I reckon 400 variables should be enough for my purposes.

Most of the rest of the system variables which are already defined and in use are in the range 30000 - 34999, with a bizarre addition between 29561 - 29569 which seems to be used by the "wall following" macro. 

Existing system variables:
There's a file called "probe_user_vars.txt" in the Centroid installation that sort of lists the variables currently in use, although most of them have no useful description to speak of. I've now imported that into Excel and am updating it with vaguely useful notes as I figure out what each of them does. Might have been nice if the originators had done so, mind.

The plan:
I will stick with numbered variables between 34100-34499 for my new probing parameters. As I create them, I will add them to the spreadsheet along with descriptions of what they are used for and comments locally within the macro. 

Wednesday 25 September 2019

Bore probing - getting there...

Bore probing operation:
The Fusion post has now been hacked about to generate a bore probing operation:

  • Move to safe position above axis of bore at the X, Y coordinate position of the axis.
  • Move down to the specified height.
  • Probe both walls in X, stopping at the mid point. 
  • Probe both walls in Y, stopping at the mid point.
  • Save the current position as the corrected X, Y coordinates of the bore in the current WCS. 
In fact, the std Renishaw probing routines that are built in to the Fanuc etc posts have a more elaborate movement than simply plunging into the bore then shuttling back and forth:



(RENISHAW PROBE)
N35 G55
N40 G00 X55. Y20.
N45 G43 Z25. H10
N50 G65 P9832
N55 G65 P9810 Z15. F1000.
N60 G65 P9814 Z-6. D30. Q3. R-3. S1.
N65 G65 P9810 Z25.
N70 G65 P9833

N75 G28 G91 Z0.

As you can see, the fancy moves are clearly contained within the Renishaw macros, not generated by the post processor. The Fusion toolpaths are presumably showing what the Renishaw probing moves look like.

In my case, all I have done is use the existing "bore" macro from Centroid to locate the central axis. That won't be good enough for the "bore with island" move, where the probe must retract to avoid contact with the island. But this seemed like a fairly simple way to get started:

(Renishaw probe)
N35 G55
N45 G0 X55. Y20.
N50 G43 Z30. H10
N60 G65 "c:/cncm/system/probe_get_modals.cnc"
N65 G65 "c:/cncm/system/probe_bore.cnc"
N70 G65 "c:/cncm/system/probe_update_x.cnc"
N75 G80
; N80 X0. Y0. Z30. ; (This is redundant!)
N90 G28 G91 Z0.
N95 M30
%

The program and the macros:
probe_bore.cnc:

; store current WCS x position
#34562 = #5041
; store current WCS y position
#34563 = #5042

; find center of x
G65 "c:/cncm/system/probe_center_inside.cnc" E1
; store width 1
#34560 = #34506

; find center of y
G65 "c:/cncm/system/probe_center_inside.cnc" E2
; store width 2
#34561 = #34506

probe_update_xy.cnc:

#34831 = 2501 + #4014 - 54                   ; x - so 2501 is G54, 2502 is G55 etc
#34832 = 2601 + #4014 - 54                   ; y - so 2601 is G54, 2602 is G55 etc

; Update the current WCS with the difference between initial and final positions
#[#34831] = #[#34831] + #5041 - #34562       ; Update current WCS X variable
#[#34832] = #[#34832] + #5042 - #34563       ; Update current WCS Y variable

The variables:
It took me a while to figure them out. There's nothing particularly special about them but it's easy to confuse "the current WCS coordinate position" with "the coordinates of the current WCS origin" and you have to bear in mind that some of the variables are read only.
#2501     this is the X machine coordinate of the origin of the current WCS
#2601     this is the Y machine coordinate of the origin of the current WCS
#5041     this is the current X coordinate of the tool in the current WCS
#5042     this is the current Y coordinate of the tool in the current WCS
#34562   this was  the X coord of the tool in the current WCS, saved before the last probing move
#34563   this was  the Y coord of the tool in the current WCS, saved before the last probing move
#34831   variable to hold X coord in current WCS system: 2501 means G54, 2502 means G55 etc
#34832   variable to hold Y coord in current WCS system: 2601 means G54, 2602 means G55 etc

So this expression:
#[#34831] = #[#34831] + #5041 - #34562
simply adds the difference between the initial X coordinate and the final X coordinate to the current X coordinate, all in the current WCS. It works for G54, G55 etc. 

The proof:
It works:

Must admit, the approach rapids seem a bit excessive but hey, I got away with it. For safety and simplicity, I set my G40P4 (vise) parking position in the centre of the workpiece. This meant the probe position would be X0 Y0 Z-60. Setting it else where works fine but there's the danger I might forget to zero the axes or somesuch. Although I have several spare probe tips, they are £30 a pop, so best taken care of.


N35 G54
N45 G0 X0. Y0.
N50 G43 Z-60. H10
N60 G65 "c:/cncm/system/probe_get_modals.cnc"
N65 G65 "c:/cncm/system/probe_bore.cnc"
N70 G65 "c:/cncm/system/probe_update_xy.cnc"
N75 G80
; N80 X0. Y0. Z-30.
N90 G28 G91 Z0.
N95 M30

This is the first of the probing operations I have implemented. It's probably the easiest and isn't in a final state by any means. But it's getting there and I'm learning a lot along the way....

Wednesday 11 September 2019

Fusion 360 probing - first working postlet!

Where are we?
Having got a simple probing macro working (see previous post), the next step is to knife and fork the embryonic "Centroid post with probing" to cause Fusion 360 generate the correct g-code to run some sort of probing event. I managed this - almost - previously, albeit with some manual edits required to weed out troublesome code that the Centroid controller disagreed with. In particular, it generated an M3 (spindle ON) command. Although the set speed was 0rpm for the Renishaw probe, it was right to question (override) the M3 request. I also had problems with the retract height which was somewhat excessively high (60mm). Of course, that's really down to the settings in the CAM that generated the operations rather than the post itself.

So, having managed to butcher the probing_bore.cnc macro to the point of functioning, along with the probing_update_x.cnc to make the results stick, let's try to implement that in my evolving post processor.

Probing post additions / changes to enable the "Bore" probing moves:
I made the following changes / additions to the post code:


    case "probing-xy-circular-hole":
      forceXYZ();
      // move slowly always from clearance not retract
      writeBlock(
        gFormat.format(65), '"c:/cncm/system/probe_get_modals.cnc"'
      );
      writeBlock(
        gFormat.format(65), '"c:/cncm/system/probe_bore.cnc"'
      );
      writeBlock(
        gFormat.format(65), '"c:/cncm/system/probe_update_x.cnc"'
      );
       break;


and this last bit ("if (spindleSpeed != 0)..." etc to prevent outputting M3 when the set speed is 0 (ie probe tool etc):

if (insertToolCall ||
      isFirstSection() ||
      (rpmFormat.areDifferent(spindleSpeed, sOutput.getCurrent())) ||
      (tool.clockwise != getPreviousSection().getTool().clockwise)) {
    // changed spindleSpeed < 1 to "< 0"
        if (spindleSpeed < 0) {
      error(localize("Spindle speed out of range."));
    }
    if (spindleSpeed > 99999) {
      warning(localize("Spindle speed exceeds maximum value."));
    }
    if (spindleSpeed != 0) {
    writeBlock(
      sOutput.format(spindleSpeed), mFormat.format(tool.clockwise ? 3 : 4))
    }
  }

This is what it generates. Looks good to my semi-trained eye.
%
O00010 (Test Fusion probing functions)
(T10  D=6. CR=3. - ZMIN=-6. - probe)
N10 G90 G94 G17
N15 G21
N20 G28 G91 Z0.
N25 G90
(Circ hole)
N30 T10 M6
(Renishaw probe)
N35 G54
N45 G0 X55. Y20.
N50 G43 Z30. H10
N60 G65 "c:/cncm/system/probe_get_modals.cnc"
N65 G65 "c:/cncm/system/probe_bore.cnc"
N70 G65 "c:/cncm/system/probe_update_x.cnc"
N75 G80
N80 X0. Y0. Z30.
N90 G28 G91 Z0.
N95 M30
%

And yes, it works - sort of. The output is still full of my debug messages but the functionality is there. It's only proof of function at this stage and there are a few logical errors, such as line N80 which originally told the machine to go to X55 Y20 again after probing. Having reset the G54 origin to ~X55 Y20 at line N45 before probing, this would end up taking the tool to ~X110 Y40. I need to save the original coordinates somewhere and use those to set the corrected offsets so that the WCS tool position is "X55 Y20" in the current WCS at the end of the sequence. It should be close to the original X55 Y20, with only a slight movement due to the probing correction.

Thursday 5 September 2019

Fusion 360 probing - updating the current WCS

Updating the current WCS after probing:
I will attempt to get the current WCS updated (corrected) after probing, as a first step. From what I can see, this should be something like:

       #2501 = #5021 - for the x coordinate

       #2601 = #5022 - for the y coordinate

where #2501 is the (read write) current WCS x coordinate (read / write) and #5021 is the (read-only) current x coordinate. 


This seems to work:
It's full of debugging messages, created using the G10 command. Without that I'd have had a royal time of trying to figure out WTF was going on. They can come out later on if I can be bothered.

Here's the macro I've been using in MDI (by typing "M72") to do the probing and updating - it initialises the probing parameters, calls the bore probing macro, then runs the update macro:




It may seem like great progress - and I suppose it's a lot better than what I had a week ago - but I'm still a LONG way off having anything ready to go, even if we overlook the post processor bit (which will need to generate the g code to actually run these probing macros).
  • It doesn't check to see if there is actually a probe fitted, which could be a problem for the probe tip if you start probing with the tool inserted but forgot to plug the probe in. There's a loop back circuit for just that purpose, so that safety function needs to be added.
  • You don't necessarily want to set the WCS origin to the final probe position. In many cases, you want to preserve the existing origin location.
  • ....

Wednesday 4 September 2019

Centroid post processor for Fusion 360 probing - update

Gnnng, oooph. Yes, this is truning into quite the workout. Figuring this out - and indeed implementing it - requires a lot of work on several fronts:

Javascript:
Various textbook sources for this, such as Peter-Paul Koch on Javascript and A Beginners Guide to Javascript by John Pollock.

Also a video tutorial on Javascript by Mosh Hamedani - "Coding with Mosh" which is pretty good for $15. There's a taster on YT for free, which in itself is useful stuff:

Javascript tends to be used by website designers but it's what Autodesk chose to use for their postprocessors. To be fair, it's not too bad but much of the JS content out there is focused on stuff like CSS and HTML which is of no relevance here.

Post processor development:
As mentioned previously, Visual Studio Code is pretty neat, being more like an IDE than a simple editor, although I've been held back on using this in anger by the need to focus on learning enough Javascript to get by. In the meantime, I've been trying to digest the various Fusion probing posts, so I can get a feel for what is involved. These are the probing posts from Fanuc and the Path Pilot (aka LinuxCNC) post that seems to have been created by David Loomes up in Jockland, the land of my forefathers.

The Fanuc posts make use of special Renishaw probing macros. Obviously these are no use to me, as the Centroid probing system is quite different in operation. Also, the Fanuc Macro B syntax is (naturally) different to Centroid's own macro dielect.

The Path Pilot / LinuxCNC post is written for LinuxCNC, so the macro calls are quite different from both Centroid and Fanuc.

Probing macros structure:
At first thought, you might believe that probing is a pretty simple matter of running the probe into a surface (at controlled speed!) and noting the coordinates where the probe input changes state. But you'd be underestimating the work required. Generally, the work is broken down into a series of common macros that are in turn called by the various top level macros. So there's a sort of hierarchy of macros at play here.
These are the 6 main operations supported by the in-built probing functions within Centroid CNC12:
  • Bore (4 way probing a hole to find the mid point)
  • Boss (4 way probing a boss to find the mid point)
  • Slot (2 way probing a slot to find the mid point)
  • Web (2 way probing a web to find the mid point)
  • Inside corner (2 way probing a corner to find the apex)
  • Axis (1 way probing to find a surface)

I've plotted them out and listed the macros they call in turn. There can be as many as 10 nested macros called by the first. Some are high level macros ("Level 1" in my terminology), which call lower level macros, most are lower level macros and some are both.



They usually require to be passed parameters such as the feedrate, direction of feed, target coordinates etc. And will generally output information in the form of system variables in the range 34000 onwards.

Thus, probe_boss.cnc macro requires parameters for clearance distance and height, feed rates for horizontal and vertical moves, axis number and initial direction (X = clearance dist in X or y; Z = clearance height; E = axis number; D = initial direction; F = traverse rate; B = plunge rate), in the following format:

                probe_boss.cnc X[x]  Z[z] E[e] D[d] F[f] B[b]


It returns the measurements in system variables #34574  =#5041 (current x position); #34575  =#5042 (current y position); #34576  =#5043 (current z position); #34578  =#34562 (width 1 from boss macro); #34579  =#34563 (width 2 from boss macro).

That's all very well, but while I don't want to reinvent the wheel that Centroid has honed over many years, the existing Centroid probing macros don't do exactly what is required by the Fusion probing functions. So what have we got and what do we need to come up with?

Here's the list of Fusion probing moves and the closest available in the Centroid macro ("system") folder:


It actually looks as if most of them are sort of covered. The angle probing may well be doable, judging by the Centroid macros such as probe_angle.cnc but I can come to them later. I seem to recall that Centroid have implemented angular correction in their probing functions.

The main missing feature is the requirement to update the WCS reference point / origin with the probed coordinates. This is where I got a bit misled....

Centroid have their own system variable numbering scheme. In places, it's the same as used in Fanuc Macro B - and in other places it has its own numbering. Here's a link to a listing for the Fanuc variables.

Centroid's table:

As you can see, Fanuc variables #5221 etc are numbered as #2401 etc in Centroid, yet #5021 (MCS) and #5041 (WCS) are the same in both. The #5221 vs #2401 thing threw me for a while. I was getting an "undeclared variable" message when I tried to reference #5221 but hadn't seen the #2401 hiding in plain daylight. Even more confusing is the way the WCS variable numbering differs between Centroid and Fanuc - for instance, x coordinates increment by 1 as the WCS increments from G54 to G55 etc, yet Fanuc correspondingly increments by 100. Similar but different...

The probed value needs to be written back to the WCS variables in order to correct the offset as a result of the probing measurement. As an example, I think this is how you would place the current X WCS number in variable #34831, which I will use to update the current WCS X coordinate offset:

       #34831 = 2501 + #4014 - 54

The X coordinate for WCS G54 is held in variable #2501. For G55, it is held in #2502 and for G56 it's held in #2503 etc. Similarly, the number of the current WCS is held in variable #4014, starting at 54 for G54. So subtracting 54 from that variable gives 0 for G54, 1 for G55 etc etc.

The corresponding expression for the current WCS Y variable number would be:

       #34832 = 2601 + #4014 -54

Of course, Fusion actually increments the WCS before updating the offset when doing in-program probing, leaving the initial WCS offset unchanged. For example, probing in G54 will create a G55 origin where the corrected G54 origin should be. I must figure out how that is handled at some point...

Final assembly and test of the spindle nose adaptor - RESULT!!

After the recent distraction caused by the 3D scanner, resurrecting the 3D printer and buggering about with the throttle bodies for my Honda...