CNCJS CNC Control Software

Hey everyone. Has someone used this CNC controller software?:

It looks really cool and full of features. Very similar to UGCS but looks more polished. Any opinions?. Just did an air run of some basic GCode and it ran beautifully. Would love help with figuring out how to write GCode for tool length probing with the Nomad. Possible?. Don’t see why not. Have the X, Y coordinates of the probe but have questions how to set up the tool length based on the Nomad’s tool probe. Most macros I see online ask you for the probe thickness to calculate tool length. Trying to figure out GCode by trial and error. Help!!!


Found this macro:

; Wait until the planner queue is empty

; Set user-defined variables

; Keep a backup of current work position
%X0=posx, Y0=posy, Z0=posz

; Save modal state
; * Work Coordinate System: G54, G55, G56, G57, G58, G59
; * Plane: G17, G18, G19
; * Units: G20, G21
; * Distance Mode: G90, G91
; * Feed Rate Mode: G93, G94
; * Spindle State: M3, M4, M5
; * Coolant State: M7, M8, M9
%WCS = modal.wcs
%PLANE = modal.plane
%UNITS = modal.units
%DISTANCE = modal.distance
%FEEDRATE = modal.feedrate
%SPINDLE = modal.spindle
%COOLANT = modal.coolant

; Stop spindle
; Absolute positioning

; Raise to tool change Z
; Go to tool change X,Y
; Wait until the planner queue is empty

; Pause the program for a manual tool change

; Go to tool probe X,Y
; Lower to tool probe Z
; Wait until the planner queue is empty

; Pause the program before probing

; Cancel tool length offset

; Probe toward workpiece with a maximum probe distance
G91 ; Relative positioning
G90 ; Absolute positioning

; A dwell time of one second to make sure the planner queue is empty
G4 P1

; Update the tool length offset

; Retract from the touch plate
G91 ; Relative positioning
G90 ; Absolute positioning

; Raise to tool change Z
; Go to tool change X,Y
; Wait until the planner queue is empty

; Pause the program for cleanup (e.g. remove touch plate, wires, etc)

; Go to previous work position
G0 X[X0] Y[Y0]
G0 Z[Z0]

; Restore modal state

I change the TOOL_PROBE location to X-220 and Y-5

Run it and the carriage slams to the left side of the Nomad. Same thing happens if I use GCode to go to that position with:

G0 X[-220] Y[-5] F888

What am I doing wrong?.


Ok, I figured out that G0 position is based on my Work Position Zero and not my Machine Zero Position.

Some months ago I had loaded up CNC.js and intended to experiment a bit to figure out how to do the tool offset, but I got distracted by other projects and hadn’t thought about it until now.

Carbide Motion 3 does all of the coordinate system translation on the host and so issues the probe movement in absolute coordinates to Grbl and uses the measurement to adjust the coordinates. That is, it doesn’t tell Grbl about the offset.

Since the probe works regardless of the bed position, you don’t need to do any Y movement to measure the tool. Only X and Z.

The notes I took at the time were as follows. These aren’t machine ready, just notes at what I wanted to achieve based on observing CM3:


– Pause until user confirm –


Thanks for your response @markwal . I just discovered CNCjs and have been playing around with it for a few hours now. I really like the interface and, when I learn some GCode, how much it will allow me to really fly with my Nomad. I’ve been disillusioned with Carbide3D lately and their lack of communication and have started looking elsewhere to see what else can be done. CNCjs seems very similar to UGCS but nicer interface. Excited to have something else to explore.
I realized if I used G53 commands they used the Machine Coordinates for positioning. This allows me to rapid send the bit to the probing position no matter where my work position is. There is a Z-Probe button in CNCjs already and it mechanically does work but I have no idea if it’s offsetting the tool length appropriately. Will continue exploring. Have to leave on a trip until next Tuesday so I won’t have access to my Nomad until then.Let me know if you ever get into it and start figuring things out. Chat soon.

@patofoto I’ve been using CNCjs for quite some time and I haven’t found a reason to use anything else. I’m sometimes shocked at how active the development has been. I don’t have a nomad, but I operate a few other machines (one is a SO3) with CNCjs. I use the built in probe macro all the time. Happy to help any way I can.

1 Like

@neilferreri Thanks for your help. I know nothing about GCode. My approach has been all trial and error. I am looking for a way to probe tool length after a tool change. Also for a way to use my Triquetra touch plate to set zero. Would love to see how your macros for your SO3 work. Any chance you would be willing to share them?.

1 Like

I typically don’t probe all 3 axes because I use the center of my stock as zero quite frequently. I also haven’t yet had a need for that level of precision on my X & Y.
My typical workflow:
Secure stock
Home machine ($H)
Jog to my desired work zero
Set that point as my zero (G10 L20 P1 X0 Y0)
Jog to a desired z-probe location
Use the Z-probe tool in CNCjs to probe
Start Job

For probing, the gcode sent is:
G38.2 F50 Z-20
G38.2 is the probe command, F50 is a feedrate of 50, and Z-20 means it will lower Z 20mm before throwing an alarm.
After that it sends:
G10 L20 Z6.25
G10L20 makes the current coordinate the defined value of 6.25 and stores it in persistent memory (next time you turn on the machine, Z will still be the same)
Next it sends:
G91 to set incremental mode
G0 Z25 which just lifts your Z 25mm above your probe
G90 to get back to absolute positioning

The G38.2 probe command would work on any axis. To set up a macro for all 3 axes, you’d just have to know the thickness of your probe and your bit radius (for X&Y).

I tend to split jobs with tool changes into multiple jobs, so I don’t probe in the middle of a job. CNCjs supports this with a custom macro or hand typed commands (the way I have done it).

Happy to help more, I don’t have a 3 axis plate (I’ve used aluminum foil). Isn’t there a tool that comes with the Triquetra to give you the macro?
If not, I can help you with one.


@neilferreri Thank you so much. This is certainly a lot of information I want to sink my teeth into. I am on my way to San Antonio, TX on a hob and should be back Monday afternoon. I will start playing with your GCode to see if I can figure it out. Thank you so much for all your help. I will certainly be asking more questions.

I’m interested in setting up probing the way it works now with my Nomad if possible. I use Fusion 360 to CAD and CAM and I also send each tool path separate for the most part but on some repeat jobs, that I have everything figured out, I like to use one file for multiple paths with a tool change command in between tools. I set my X and Y zero and then set the height of stock touching the tip of the tool to the surface of the stock. Carbide Motion runs job and stops in between paths, asks for a new tool and then probes to figure out the new tool length then continues the job until a new tool is needed. I have copied the console output out of Carbide Motion when it probes and this is what I get:

(541): -> M56P0
(540): -> gc_probe


(519): -> gc_apply_reference_tool

(517): -> N0G0X-220.000Z-5.000
(516): -> gc_goto_probe_home

(514): -> gc_sync

(512): -> N0 G4P0.005
(511): -> gc_wait_for_idle

(402): -> N0G38.2Z-105.000F200.0
(401): -> gc_do_tool_probe

(399): -> N0G0Z-35.000
(398): -> gc_motion

(396): -> N0G0X-220.000Z-5.000
(395): -> gc_goto_probe_home

(391): -> $h
(390): -> gc_homing

(375): -> N0 G4P0.005
(374): -> gc_wait_for_idle

(372): -> N0G0X-20.000
(371): -> gc_motion

(369): -> M05
(368): -> gc_spindle


(187): -> M05
(186): -> gc_spindle
(185): -> gc_cancel_tool_length

(183): -> M56P0
(182): -> gc_probe

(165): -> N0G0X-120.000
(164): -> gc_motion

(159): -> $h
(158): -> gc_homing


(140): -> M56P0
(139): -> gc_probe


(61): -> M56P1
(60): -> gc_probe

(58): -> gc_sync

(56): -> N0 G4P0.005
(55): -> gc_wait_for_idle

(42): -> $#
(41): -> gc_get_offsets

(38): -> $G
(37): -> gc_parser_state

(35): -> G90
(34): -> gc_not_motion

(32): -> G49
(31): -> gc_not_motion

(29): -> G21
(28): -> gc_not_motion

(26): -> G10L2P1X0Y0Z0
(25): -> gc_not_motion

(23): -> G54
(22): -> gc_not_motion

(20): -> G92.1
(19): -> gc_not_motion

(17): -> M05
(16): -> gc_spindle

(14): -> N0 G4P0.005
(13): -> gc_wait_for_idle

(10): -> gc_wait_for_status_updates

(6): -> $X

(2): -> GRBL_RESET

I have taken out a lot of data that I think is only position data the console is reading. I’ve left info that I think will let me figure out what to do.
I also do have the code generated by the maker of the Triquetra to probe Z. The 20.65 value is the thickness of the Triquetra:

G92 Z0
G38.2 Z-25 F50.0
G92 Z20.6500
G91 G0 Z0.3.175
G91 G0 Y25 X25

Please forgive the length of the post. Wanted to get it out there before jumping on a plane.

There’s some stuff missing from the Carbide output. No big deal. You’re not really setting a tool length offset, you’re just setting Z0 for a new tool.
Looks like the triquetra code is using G92s which are temporary. The probe tool in CNCjs uses G10 L20 to set the zero which is permanent (unless you change it).
If you’re just probing Z, jog to your probe location (I usually get Z within 20mm or so) and then:
Assuming you use mm
G21 ; make sure you’re in mm
G38.2 Z-25 F75 ;probe z-axis down 25mm at feedrate of 75
G92 Z20.65 ;temp set current Z as 20.65mm
G91 ;incremental mode
G0 Z3 ;raise Z 3mm
G90 ;back to absolute mode

1 Like

@neilferreri Incredibly thankful for all your help.I will test all this next week when back home.

Just tried this macro on a piece of aluminum. At the end it goes to 0,0,0…you would not want to do that automatically with a touchplate because 0,0,0 is under the touchplate. I might have to make my own corner touch plate now!
G38.2 X12.7 F75
G92 X-3.175
G0 X-10
G91 G0 Y-20
G90 G0 X10
G38.2 Y20 F75
G92 Y-3.175
G0 Y-10
G91 G0 Z20
G90 G0 X20Y20
G38.2 Z-20 F75
G92 Z0
G0 Z10
G0 X0Y0
G1 Z0 F75


So cool!!!. Thanks for the video @neilferreri. I’m flying home today and will start playing tomorrow with all the macros you have been so kind to share. I am very excited to make CNCjs part of my workflow. Seems like i will allow me all the flexibility i want.

1 Like

Happy to share…you’ve pushed me to probe more.
Milling a piece of aluminum today. Different machine (1/8" end mill), and I wanted the XYZ zeros to be permanent. I used G10 L20 instead of G92.
Here’s the macro (again no probe plate, just metal stock…to make a probe plate!)

(start with the end mill about 10mm or less from bottom left corner. Z below surface)
G21 ;make sure we're in mm
G38.2 X12.7 F75 ;Probe W to the right 12.7mm
G10 L20 P1 X-1.5875 ;Set current X location as negative half the bit diameter
G0 X-10 ;Move left 10mm
G91 G0 Y-20 ;Move forward 20mm
G90 G0 X10 ;Move to X10 - will put you 10mm to the right of left edge
G38.2 Y20 F75 ;Probe Y
G10 L20 P1 Y-1.5875 ;Set current X location as negative half the bit diameter
G0 Y-10 ;Move to Y-10
G91 G0 Z20 ;Move Z up 20mm
G90 G0 X10Y10 ;Move to X10Y10
G38.2 Z-20 F75 ;Probe Z
G10 L20 P1 Z0.2 ;Set Current Z as 0.2mm - I was facing a piece of aluminum
G0 Z10 ;Raise to Z10
G0 X0Y0 ;Go to X0Y0


Used your last macro and it works as expected. I am starting to make a little sense of how GCode works. This, eventually, when taking into consideration a touchplate dimensions will give you WCS zero. I like this design of touchplate:

If I understood correctly, you don’t need to input bit dimensions to get the zero position with this design.

What I would love is to use a touchplate like this to get my WCS zero at the beginning of a job and then use the tool length probe in my Nomad to calculate tool length after tool changes. This would allow me to not have to reconnect my touchplate again after the initial setup. Just a matter of elegance in the workflow. I already have the tool probe so why not use it. I have the mechanics to send the machine to probe, but the stored values are all wrong. Need to understand how to store values and then use them to make calculations.

What is the difference between G54 (WCS) and G92 (Temporary offsets)?. Are G92 codes used as temporary numbers for calculations?.

All this feels like learning Chinese. I get the gist of things but still can’t make sense yet of how to make things work. I get that it’s very simple math but can’t figure out where all the calculations happen.

I’m glad that you are so generous with your knowledge. I am the same way. If there is any way I can help you with anything, please don’t hesitate to ask. Also, I like using the forum because other people might learn something from our ramblings but if you prefer we can move into private messaging.

You’d still need to account for your bit diameter. A 1/16" bit used as an XY corner probe will cause the router to be much closer to the corner of your stock than a 3/4" face mill. The distance would be the thickness of the probe + half of your bit diameter. For Z, your bit doesn’t matter…the bottom of a bit is the bottom of a bit, regardless of diameter.

Like I said, I’m not familiar with the Nomad’s probe. How does that work?

CNC worm hole here: (From a post of mine in another forum)
Basically, you have your machine coordinate system (G53), and nine available work coordinate systems, or WCS, that are a known offset from the machine coordinate system. You can set your origins for each of those WCS easily by jogging to the location you want and sending “G10 L20 P*** X0 Y0”. The *** in this case would be the number for the WCS you are setting the XY origin for. P1 for G54, P2 for G55, and so on. All of this requires homing first, so the machine knows where it is.
Let’s say I make a lot of bottle openers and I mill a lot of PCBs. I have a square mounted to my machine to set my 1x6 for the bottle opener and somewhere away from that, I have a small pocket to set in my PCB blank. I could set my G54 origin to my desired work zero for my bottle opener by jogging there and sending “G10 L20 P1 X0 Y0” (you could add a Z0 if you know you won’t need to probe). i can jog to my PCB pocket and send “G10 L20 P2 X0 Y0 Z0” to set my G55 work origin. From now on, after I home and when I’m in the G54 (usually default) WCS, I can send G0 X0 Y0, and my machine will go to the same spot. You could actually just start your carve from wherever your home is and it will still use the correct work origin. Just home your machine and carve. When I’m ready to mill the PCB, I’ll make sure my gCode is is set up for the correct WCS (G55), home, and carve.
Be cautious when using the different coordinate systems. You may have everything set up for your G55 origin, but if your gcode has a G54 in the header (again, default), you’re machine will carve in that WCS. You may think Z3 is 3mm above your workpiece, but if you’re in the wrong WCS it may be closer to the bottom of your workpiece. You can change from working in one WCS to another by sending G55 or G57 or G54 or whatever.

I’m sure there are videos and diagrams out there that will help illustrate. When I’m working with my CNC at home it tends to be quick and dirty…I have a 3yr old and 1yr old, and I can only do so much during a nap time. After they’re in bed, I’m in no condition to operate machinery.

Think of G92 as an offset of the whole thing. All of your work coordinate systems get shifted with a G92. I try to avoid it as it’s temporary. If I used G10 to set my zero, and the power goes out, I can just home and carve when it kicks back on. If I used G92, and didn’t record the current machine coordinate values, I just wasted my stock. Unless I have a 3-axis probe…then I can secure that piece anywhere, probe and carve.

I teach middle school, so it’s nice to talk about this stuff without someone asking “what would happen if I put my hand in there?”


Really though, what would happen? I’m 46 years old and my middle school teacher never answered that question, but I’ve “almost” worked up the nerve to give it a try :wink:

In all honesty though, this is a really great post and I’m slowly learning a lot, thank you for your time!


1 Like

Here is a small video trying to explain what my question is and how the Nomad Classic probe works:

Here is how my macro is after the coordinates for my probe:

; Z-Probe
G53 X[-220]
G53 Z [-42]
G38.2 Z-55 F150

; Set the active WCS Z0
G10 L20 P1 Z10

; Retract from the touch plate
G0 Z55

My new Z axis, now under construction, has necessitated the learning of yet more software, :rage:, not my favorite way to spend my time. But, invest I must.

So, to the point, is there a “best” way for a person with zero “$” ability/knowledge to learn CNCJS?

Oh, and thanks for posting @patofoto I’ve been looking about for a few weeks now at different g-code senders and was immediately impressed by CNCJS’s interface and organization.