# Macro Gcode question

**URL:** <https://forum.sienci.com/t/macro-gcode-question/21399>\
**Category:** ❓ Question\
**Created:** [August 5, 2025, 8:27pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399 "2025-08-05T20:27:07Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jens](https://forum.sienci.com/letter_avatar_proxy/v4/letter/j/d2c977/32.png) [@Jens](https://forum.sienci.com/u/Jens)\
**Post date:** [August 5, 2025, 8:27pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399/1 "2025-08-05T20:27:08Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![Jens](https://forum.sienci.com/letter_avatar_proxy/v4/letter/j/d2c977/32.png) [@Jens](https://forum.sienci.com/u/Jens)\
**Post date:** [August 6, 2025, 1:40am UTC](https://forum.sienci.com/t/macro-gcode-question/21399/2 "2025-08-06T01:40:33Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![cjm](https://forum.sienci.com/user_avatar/forum.sienci.com/cjm/32/8862_2.png) [@cjm](https://forum.sienci.com/u/cjm)\
**Post date:** [August 6, 2025, 6:33am UTC](https://forum.sienci.com/t/macro-gcode-question/21399/3 "2025-08-06T06:33:33Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Jens](https://forum.sienci.com/letter_avatar_proxy/v4/letter/j/d2c977/32.png) [@Jens](https://forum.sienci.com/u/Jens)\
**Post date:** [August 6, 2025, 7:15am UTC](https://forum.sienci.com/t/macro-gcode-question/21399/4 "2025-08-06T07:15:08Z")

</div>

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 ?

---

<div class="post-metadata">

**Author:** ![Jens](https://forum.sienci.com/letter_avatar_proxy/v4/letter/j/d2c977/32.png) [@Jens](https://forum.sienci.com/u/Jens)\
**Post date:** [August 6, 2025, 7:45am UTC](https://forum.sienci.com/t/macro-gcode-question/21399/5 "2025-08-06T07:45:12Z")

</div>

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]?

---

<div class="post-metadata">

**Author:** ![JPlocher](https://forum.sienci.com/user_avatar/forum.sienci.com/jplocher/32/9807_2.png) [@JPlocher](https://forum.sienci.com/u/JPlocher)\
**Post date:** [August 6, 2025, 3:07pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399/6 "2025-08-06T15:07:58Z")

</div>

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)

---

<div class="post-metadata">

**Author:** ![Jens](https://forum.sienci.com/letter_avatar_proxy/v4/letter/j/d2c977/32.png) [@Jens](https://forum.sienci.com/u/Jens)\
**Post date:** [August 6, 2025, 3:24pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399/7 "2025-08-06T15:24:20Z")

</div>

It works !!!😃 Very cool!

---

<div class="post-metadata">

**Author:** ![Jens](https://forum.sienci.com/letter_avatar_proxy/v4/letter/j/d2c977/32.png) [@Jens](https://forum.sienci.com/u/Jens)\
**Post date:** [August 6, 2025, 3:27pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399/8 "2025-08-06T15:27:31Z")

</div>

> [@JPlocher](#):
>
> As for documentation for gsender and grbl’s macro usage, I have not found a good comprehensive source - let us know how it goes!

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.

---

<div class="post-metadata">

**Author:** ![KGN](https://forum.sienci.com/letter_avatar_proxy/v4/letter/k/c77e96/32.png) [@KGN](https://forum.sienci.com/u/KGN)\
**Post date:** [August 6, 2025, 4:11pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399/9 "2025-08-06T16:11:47Z")

</div>

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.

> [@Jens](#):
>
> 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?

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.

> **[Additional Features - gSender Docs](https://resources.sienci.com/view/gs-additional-features/#advanced-macros)**
>
> Learn the advanced features of gSender such as shortcuts, macros, workspaces, calibration tools, controlling spindles, lasers, coolant, and more.

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)

---

<div class="post-metadata">

**Author:** ![Jens](https://forum.sienci.com/letter_avatar_proxy/v4/letter/j/d2c977/32.png) [@Jens](https://forum.sienci.com/u/Jens)\
**Post date:** [August 6, 2025, 4:39pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399/10 "2025-08-06T16:39:07Z")

</div>

I was aware of the non-gcode expressions - it took me quite a while to find documentation ☹ 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?

---

<div class="post-metadata">

**Author:** ![Jens](https://forum.sienci.com/letter_avatar_proxy/v4/letter/j/d2c977/32.png) [@Jens](https://forum.sienci.com/u/Jens)\
**Post date:** [August 6, 2025, 4:48pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399/11 "2025-08-06T16:48:57Z")

</div>

> [@KGN](#):
>
> 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.

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.

---

<div class="post-metadata">

**Author:** ![KGN](https://forum.sienci.com/letter_avatar_proxy/v4/letter/k/c77e96/32.png) [@KGN](https://forum.sienci.com/u/KGN)\
**Post date:** [August 6, 2025, 5:50pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399/12 "2025-08-06T17:50:27Z")

</div>

> [@Jens](#):
>
> 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?

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](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.

> [@Jens](#):
>
> 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

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?

---

<div class="post-metadata">

**Author:** ![Jens](https://forum.sienci.com/letter_avatar_proxy/v4/letter/j/d2c977/32.png) [@Jens](https://forum.sienci.com/u/Jens)\
**Post date:** [August 6, 2025, 6:11pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399/13 "2025-08-06T18:11:18Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![JPlocher](https://forum.sienci.com/user_avatar/forum.sienci.com/jplocher/32/9807_2.png) [@JPlocher](https://forum.sienci.com/u/JPlocher)\
**Post date:** [September 12, 2025, 3:42am UTC](https://forum.sienci.com/t/macro-gcode-question/21399/14 "2025-09-12T03:42:36Z")

</div>

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

[grblHAL](https://www.grbl.org/what-is-grblhal) shares some [G-code macro concepts](http://linuxcnc.org/docs/2.8/html/gcode/overview.html) with LinuxCNC  
LinuxCNC has [a good G-code overview](http://linuxcnc.org/docs/2.8/html/gcode/overview.html)  
LinuxCNC has [a good M-code overview](https://linuxcnc.org/docs/html/gcode/m-code.html)  
Marlin’s docs have a [useful list of G-code commands](https://marlinfw.org/meta/gcode/)

[Vectric’s docs on postprocessors](https://docs.vectric.com/docs/V12.0/Aspire/ENU/Help/form/post-processor-editing/index.html)

---

<div class="post-metadata">

**Author:** ![chrismakesstuff](https://forum.sienci.com/user_avatar/forum.sienci.com/chrismakesstuff/32/10759_2.png) [@chrismakesstuff](https://forum.sienci.com/u/chrismakesstuff)\
**Post date:** [March 20, 2026, 7:36pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399/15 "2026-03-20T19:36:13Z")

</div>

Closed on March 20, 2026, 7:36pm UTC



---

<div class="post-metadata">

**Author:** ![chrismakesstuff](https://forum.sienci.com/user_avatar/forum.sienci.com/chrismakesstuff/32/10759_2.png) [@chrismakesstuff](https://forum.sienci.com/u/chrismakesstuff)\
**Post date:** [March 20, 2026, 7:38pm UTC](https://forum.sienci.com/t/macro-gcode-question/21399/16 "2026-03-20T19:38:23Z")

</div>

I added a new example to the docs to help with this circumstance based on this conversation (#7 on the list), thanks for bringing it up @Jens!

> **[Additional Features - gSender Docs](https://resources.sienci.com/view/gs-additional-features/#advanced-macros)**
>
> This page covers all the advanced features of gSender such as shortcuts, macros, workspaces, calibration tools, controlling spindles, rotary axes, lasers, coolant, and more. Remember, you can always quickly navigate the page by clicking the headings...
