Macro Gcode question

I am trying to make some sense out of a macro found on the net. It is a probing routine. Most of it works except one line:

Given that PROBE_X1 and PROBE_X2 are valid numbers in the form of xxx.xxx

%newX=([PROBE_X1]+[PROBE_X2])/2

G10 L2 P0 X[newX]

The G10 line fails

When I add a printout of [newX] above the G10 line it comes back as NaN (not a number)

Why is newX not computed correctly?

Ok, maybe the question was too hard … let me try something that is theoretically easier:

Given the following macro:

%PROBE_X1=7
%PROBE_X2=3.5
%newX=([PROBE_X1] + [PROBE_X2] + 4) / 2
([newX] [PROBE_X1] [PROBE_X2])

Looking at the console I see (36.77 7 3.5) WTH???

It obviously recognized PROBE_X1 as being 7 and PROBE_X2 as being 3.5

(7+3.5+4)/2 is definitely not 36.77 so what (probably stupidly simple) thing am I missing here?

Hi @Jens,

The brackets “[ ]” in the formula need to be removed, or Number( ) needs to be added to convert to a value.

%newX=(PROBE_X1 + PROBE_X2 + 4) / 2
%newX=(Number([PROBE_X1]) + Number([PROBE_X2]) + 4) / 2

What you’re getting is 73.54/2 = 36.77 and not the (7+3.5+4)/2 = 14.5/2 = 7.25.

1 Like

Crap, I knew it was something stupid but I just couldn’t figure it out.

I will give that a try tomorrow, thanks!

PS.: Is there a rule for when brackets are used? I was under the impression that [variable] always means that the ‘variable’ name is replaced by it’s value.

Why does this work:

([variable1] [variable2] etc etc)

the result being that the content of variable1 and variable2 is printed to the console.

I would like to understand the thinking behind this so it makes more sense to me.

Just had a thought … maybe bracketed variables are not numbers but text … could that be the case?

If that is the case though, why would two concatenated texts be divisible by 2 ?

This is actually starting to make some sense. Square brackets replace the variable content but the default is text and you need to cast it to a number with the ‘Number’ operator. The only puzzle now is why, when you concatenate two text variables do you get something that you can treat as a number (ie you can divide it by 2). Is there some sort of automatic conversion if there is a text variable that looks like a number and is followed by a numeric operator?

Macro’s are quickly getting to the ‘rocket science’ territory. I wouldn’t have figured this out by myself in a million years especially with the sample code on the internet having that same error.

One last question if I may … suppose you want to do the following:

G10 L2 P0 X[newX] (with newX being the new X coordinate being written to the G54 coordinate system)

Are the square brackets needed or should you say G10 L2 P0 X newX (do we need a space between X and newX or should this in fact be G10 L2 P0 XNumber[newX]?

This is a common software issue - the difference between “token concatenation” and “expression evaluation” can be confusing.

Your first version simply pasted the literal content of the PROBE_X1 and _X2 named values together, and gave you the sequence

“7””3.5””4””/””2” = 73.54/2

Using Number() changed the intent from concatenation (aka text pasting…) to evaluating, giving

(7 + 3.5 + 4) / 2

As for documentation for gsender and –-grbl’s-- grblHAL’s macro usage, I have not found a good comprehensive source - let us know how it goes!

(edit - should have been more precise, grbl != grblHAL != g-code)

It works !!!:smiley: Very cool!

It is too bad that comprehensive documentation is not available. As it is, I had to piece tidbits of information together from various sources to get as far as I have. Well at least this particular puzzle has been solved and I will keep all this in mind in the future if weird stuff happens.

To clarify, there’s no such thing as grbl macros - all the logic/replacement is done on the sender side. grblHAL does support linuxCNC like macros on the firmware side which are more complex but you’d have to be comfortable on the SD card side of things.

On the backend, we evaluate non-gcode expressions indicated by % or […] using Esprima which parses it into Javascript expressions that we can run to evaluate more complex operations.

Yes

We do have some documentation that covers the basics (specifically it covers variables, expressions, logic and stored functions) , but if you think there’s room for improvement let us know.

I think gSender macros are pretty flexible and a lot more powerful than people realize. We use them in gSender frequently (for example, probing off different corners - we use the same routine code and can swap directions of travel using %variables that are populated beforehand)

2 Likes

I was aware of the non-gcode expressions - it took me quite a while to find documentation :frowning: There is no mention anywhere (that I could find) that says ‘we use a mix of gcodes and our own codes’ so if you can’t find something in the plentiful gcode documentation on the web, look at this link to see what these other codes mean.

Maybe you can comment on the following:

In the linked documentation of additional features, it says:

Use your variable in g-code, like G21 G91 G0 X[variable] (moves the X-axis by the amount set in the variable)

This to me implies that that the square bracket annotation replaces the content of the variable in the expression. This was my interpretation until I hit the big stumbling block of this thread. In the example line [variable] the expression is replaced with a numeric value of the variable. Why, in the expression %newX=([PROBE_X1] + [PROBE_X2] + 4) / 2 is the value of [PROBE_X1] not substituted with the number ‘7’. It is inconsistent and confusing. Why do I need to leave out the brackets in my expression for the variables to be interpreted as numbers instead of text?

Yes, there is plenty of room for improvement in the form of a comprehensive (not just the commonly used features) guide of all the features of the macro interpreter. If you don’t have the resources for a comprehensive guide then please include links for all the features so that the user can piece things together themselves. Maybe I overlooked details or links on the non-gcode based features … that is quite possible.

You are mixing two different ways we use to escape a macro line into the expression interpreter by having both % and […].

% at the start already means the line will be interpreted as a Javascript expression and so the […] are treated as arrays by Javascript.

Inside the interpreter, if the tree node sees an identifier (SYMBOL = VALUE, like PROBE_X1 or PROBE_X2) and the value looks like a number we explicitly convert it to a number. This is just a general nice thing we do because most macros deal with modifying numbers in some form.

Since you added extra […] the node.type is no longer a identifier, it’s an ArrayExpression, and the conversion doesn’t happen because an array value can be anything. JS already has it’s own way of dealing with addition when it comes to array/other non-primitive types and the result is effectively concatenating a string representation of the array. So [PROBE_X1] + [PROBE_X2] + 4 becomes 73.54 because [PROBE_X1] and [PROBE_X2] are just two arrays, [7] and [3.5].

Once again, this is just how the JS language works when it comes to handling addition on non-primitive types - here’s a Codepen showing the equivalent to what you’re doing in that adding two arrays together just concatenates the values. Under the hood, JS calls toPrimitive on complex types and for arrays the primitive is a string. String + String in JS just concatenates.

https://codepen.io/kglovern/pen/MYaoJQM

Hopefully the above clears up why you had the behaviour you did - it’s in line with ECMAscript standards.

This is effectively the Javascript library and is documented elsewhere unless you have specific things you want us to mention. Realistically, the provided examples cover the most common use cases for what someone is going to do in a g-code macro (basic maths, storing values, storing strings like modals, etc.). We could probably expand on some useful JS native libraries (like Math, etc.).

Is it just more examples or something else you’d like to see?

Ahhhhh, I seeeeee …… Now that makes more sense. Everything I have ever worked with was one single interpreter/language. The concept that we are dealing with two different interpreters never occurred to me.

Yes, this explanation helped a tremendous amount in clarifying what is happening here.

Maybe a version of that could be included in the macro documentation …. ie a specific mention that there are two different ways of how things are interpreted. Also, a more direct statement (and a link) to the aspects that are not found in gcode documentation (% and )

Anyway, thank you very much for clearing that up for me.

2 Likes

better late than never… here are several docs that may be useful

grblHAL shares some G-code macro concepts with LinuxCNC
LinuxCNC has a good G-code overview
LinuxCNC has a good M-code overview
Marlin’s docs have a useful list of G-code commands

Vectric’s docs on postprocessors