#### Description
I would like cncjs to be able to support the following auto tool changer scenario:
Given a gcode file that looks roughly like this:
T1 M6
… (milling goes here)
T3 M6
…
T4 M6
…
T1 M6
…
And assuming a CNC with an ATC and an appropriate tool change macro, cncjs should be able to:
1. Handle the first tool change line by loading the tool from slot #1 (slot number extracted from T~ command, slot location calculated by macro).
2. Handle the second tool change by unloading the tool into slot #1, remembering where it came from the in first tool change, and then loading the tool from slot #3.
3. Handle the third and fourth tool changes as expected.
This still isn’t enough to give a great ATC experience–at a minimum, we need to figure out what to do with any tool that is in the changer before the start of milling, and we need to be able to handle aborting halfway through milling without getting completely lost WRT tools, but this is a start.
#### Versions
– CNCjs: 1.9.x
– Node.js: 6.x
– NPM: 5.x
#### How Do You Install CNCjs?
– [x] NPM
– [ ] Download the CNCjs Desktop Application
#### CNC Controller
– [x] Grbl
– [ ] Smoothieware
– [ ] TinyG/g2core
#### Hardware
– [x] Raspberry Pi
– [ ] Desktop or Laptop
– [ ] Mobile Device
#### Operating System
– [x] Not Applicable
– [ ] Windows
– [ ] Mac
– [ ] Linux
评论 (30)
#2 – saxa 于 2019-04-01
Cool, is this router all driven by grbl ?
#3 – scottlaird 于 2019-04-01
> Cool, is this router all driven by grbl ?
The router is all grbl. There’s an additional bit of tool-change logic and software running on an Arduino sitting between the grbl board and the spindle. It controls relays that control the pneumatic solenoids that drive the tool changer, a relay that turns power on and off to the spindle, and a bunch of more-or-less optional components that make my life easier, like an LCD display so I can see what RPM it’s running at. The tool change code includes safety features that are designed to keep it from ejecting tools while the spindle is spinning, for example. It’s a few hundred lines of code.
If there’s interest, I can package it up and open source it at some point, but it’d be more useful as an example than as actual code to use.
#4 – scottlaird 于 2019-04-01
1. Add loops and logic to macros. I’m not sure how best to do this, but there’s a lot of prior art–this looks a lot like most HTML template systems. I don’t know if any existing node libraries would fit well into CNCjs or not. Has anyone looked into this before, or have strong opinions?
2. Add the ability to directly interact with the tool changer hardware from inside of the macro. This seems easy, design-wise. Write an ATC-specific library, instantiate an object of it inside of CNCjs, and then pass it into the macro context. So you could say something like %SLOTEMPTY = myAtc.slotEmpty(SLOT). Obviously generalizing that and finding a reasonable way to expose other libraries into macros would be important.
3. Add the ability for gcode to directly trigger tool change macros. At a minimum, it should be possible to designate a specific macro for handling M6. I think this would be a straightforward extension to the current event code. Ideally, given a mature tool-change system, it should be possible to run a gcode job with tool changes without any clicking after hitting ‘run’. Adding more generic gcode macro support (canned cycles, etc) is out of scope.
#5 – saxa 于 2019-04-01
@scottlaird , many thanks. I am retrofitting an oxy fuel cnc machine but it a big one 5m wide and 10 long.
So my idea is to put a spindle on it also for drilling or milling some holes on the parts we produce, I would also like to set up the automatic clamping of the parts, so this is why it interests me, and I am ready to help out. My only problem is that I have never done something like that although I know how to program and I know how to maintain machines. Nothing so difficult in that way but its always good to
hear from persons who already done it and can give a good advise.
Sorry for a bit off topic, but from what I saw I have AC servo drives and I think I need to use the modified version of GRBL for driving those. But over all I am ready to help with that tool change thingy.
#6 – MitchBradley 于 2019-04-01
With a machine that size, I would seriously consider a commercial control like UCCNC. A crash on such a machine could be expensive in all sorts of ways. CNCjs is great for hobbyist and light commercial use, but it has a lot of “moving parts” software-wise, many of which change rapidly and thus do not get the benefit of deep and long-term testing. On my benchtop Taig mill, I have 2 N-m closed loop steppers that can pull 180W each. They are powerful enough to frighten me a bit. With anything as big and powerful as your machine, I think I would want software that is tightly integrated and thus less subject to communication delays between components, and very well tested.
#7 – karoria 于 2019-04-02
I want to use 3 phase industrial servo motors for my next VMC machine. Can we get feedback of servo to cncjs or g2core? I think there are two parts of feedback. One is a broad feedback like servo drive is running or in alarm state. Another one is to read and display the coordinates of actual move instead of sent pulses…
Any of them is possible by any means of work around? I am ready to invest my time on this fully close loop system. BTW, I also want to give absolute servo a try so as to get rid of limit switches or just use them as second level safety.
#8 – scottlaird 于 2019-04-02
This is kind of getting away from the topic at hand; servos aren’t that closely related to tool changing ![]()
In general, Grbl doesn’t have direct support for servos, or for closed-loop motors of any kind, and there’s really no way to expand it on existing hardware.
However, some drivers can make servos look like steppers and vice-versa. For instance, look at Leadshine’s CS-Dxxx closed-loop stepper drivers–they support both a “step and direction” interface (basically, it looks like a stepper) and a “cw/ccw” interface (it looks like a servo). Similarly, a number of Leadshine’s servo drivers can also support step and direction, so it’d probably be possible to drive them with Grbl, but I don’t know that it’d make a lot of sense given how much they cost.
Consider asking on https://github.com/gnea/grbl for generic Grbl questions?
#9 – MitchBradley 于 2019-04-02
I have integrated (driver and motor in one package) closed loop steppers on my mill, connected to g2core, which supports ALARM inputs. I got them for about $110 each. They either go the full distance without losing steps, or they go to alarm state.
#10 – karoria 于 2019-04-02
Thanks @scottlaird for the answer. Sorry for raising question in wrong thread. BTW, industrial servos also support pulse and direction strategy. So it will run out of the box. The only concern is to receive feedback to controller. I will start a new thread for this now.
#11 – karoria 于 2019-04-02
Thanks @MitchBradley for sharing your experience. I will think on it. However my idea is to use fully closed loop servo like siemens or panasonic which will take away lots of hurdles towards a reliable machine. We will talk more on new thread so as not to spoil the main topic of tool changer ![]()
#12 – cheton 于 2019-04-03
Hi @scottlaird
CNCjs v1.9.18 is released. Now you can declare global variables without losing all the values.
Here are some examples:
“`
%global.startTime = Date.now()
%global.activeTool = Number(tool) || 0
%global.state.cx = (xmax + xmin) / 2
%global.state.cy = (ymax + ymin) / 2
%global.state.cz = (zmax + zmin) / 2
%global.state.dx = Math.abs(xmax - xmin) || 0
%global.state.dy = Math.abs(ymax - ymin) || 0
To check current values, you can use inline comment to output global variables like this:
`gcode`
(global=[JSON.stringify(global)])
All supported JavaScript global objects are listed here.
`js
export const GLOBAL_OBJECTS = {
// Function properties
parseFloat,
parseInt,
// Fundamental objects
Object,
Function,
Boolean,
// Numbers and dates
Number,
Math,
Date,
// Text processing
String,
RegExp,
// Structured data
JSON,
};
“
#13 – cheton 于 2019-04-03
With the newly enhanced evaluate-expression library, it is possible to provide a function interface to communicate with external libraries, so you can create an instance of object to return the state or interact with an external hardware.
I will see if there is any chance to do that. Something like command-line options can be used to pass a JavaScript file with exported modules that allows you to connect macros with the underlying system.
#14 – cheton 于 2019-04-04
As far as I know, @ahedderich initiated his work for adding auto tool changer support last year, all changed files in the pull request are available at here: https://github.com/cncjs/cncjs/compare/master…ahedderich:tool-changer
You can first take a look for what he did, I will merge his code in a future release if it is a feasible solution.
#15 – scottlaird 于 2019-04-04
Thanks. I’m building 1.9.18 on the Raspberry Pi connected to my CNC now. It takes a while :-). I should probably figure out how to cross-compile it.
#16 – MitchBradley 于 2019-04-04
Despite many tries, I have not succeeded in completely building recent versions of CNCjs on the Pi Zero that runs my mill. It always runs out of memory and dies in the build-prod-web step.
However, it turns out (as @cheton has confirmed) that the web portion of the code is platform independent, so it is possible to just copy that from another build machine. So what I do is run the “npm run build-prod-server” step on the Pi, then build everything on a PC, then copy dist/cnc/web from the PC to the Pi.
Even if you succeed with a full Pi build, the hybrid build approach is much faster due to the extreme speed and memory difference between PC and Pi.
Here is the recipe:
– On Pi:
– npm run clean
– npm run prebuild-prod
– npm run build-prod-server
– create symlinks named “cncjs”, and “cncjs-server” in /usr/local/bin, referring to
Note: if you are using a version prior to cncjs-1.10, you must say build-prod-app instead of build-prod-server above.
– On PC or Mac:
– npm install
– copy dist/cnc/web/* to the Pi (at
The procedure above avoids running eslint, stylint, and test on the Pi, which are time-consuming and redundant.
(Edited on 2019-5-6 to reflect the new name build-prod-server)
#17 – scottlaird 于 2019-04-04
Thanks! That should make life much more pleasant.
#18 – scottlaird 于 2019-04-05
That sequence seems to work fine. I didn’t need to create the cnc/cncjs/cncjs-server links because they already existed pointing into /usr/lib/node_modules/cncjs, which was a symlink into my git tree.
That took a couple minutes total, vs over an hour on the Pi. Although in its defense, it was out of memory and swapping onto a SD card for most of that.
#19 – MitchBradley 于 2019-04-05
Long ago in a galaxy far away, I decided that the first order predictor of a computer’s speed is the effective memory bandwidth. CPU clock rate is largely unimportant except insofar as it correlates with memory bandwidth, and when you are swapping, your effective bandwidth goes asymptotically to 0, until you run out of swap space, at which point it is “start over” time. Of course one can invent workloads that behave differently, but for general purpose use, if you know the memory bandwidth and have enough memory, you know the performance.
#20 – scottlaird 于 2019-04-05
I’ve heard good arguments that the best metric is really the number of cache-miss memory reads per second, which isn’t quite the same as memory bandwidth, but they’re close enough for today. Especially when swapping.
#21 – scottlaird 于 2019-04-05
The global variables are working great; CNCjs even remembers tool locations across jobs, which is better than I was expecting.
I was able to load and unload several tools in succession this evening.
#22 – karoria 于 2019-04-05
That’s excellent. Does cncjs remembers these locations after power off and restart? Or that is something we need to define in gcode header lines each time?
#23 – cheton 于 2019-04-05
@karoria Global variables will not persist in the server once a serial connection is closed. Each time you establish a new serial connection, you will need to run a macro to declare global variables.
Note: Reload the browser won’t affect global variables stored in the server.
#24 – karoria 于 2019-04-05
Got it. Thanks @cheton. Can we automate this process at the time of connection to controller? I am asking this as i am seriously working to make a commercial product from cncjs+g2core. One more concern is to remember program line number at the time of power failure. Any work towards these concerns will be highly appreciated.
#25 – cheton 于 2019-04-05
@karoria It is possible to add a new “startup” event that will be triggered when a CNC controller has started, you can send several lines of G-code or run a system script, just like the startup blocks that Grbl runs every time you power on Grbl or reset Grbl.
I can add it to the backlog for the next release.
#26 – karoria 于 2019-04-05
Thanks @cheton. Can you also suggest some workaround to save last program line sent to controller before power failure?
#27 – scottlaird 于 2019-04-05
Instead of loading and saving globals, you’d be better off wiring up some sort of transactional store (sqllite comes to mind as being relatively easy but not ideal), creating a DB object in the controller startup, and then exposing that via globals. Then instead of storing whatever you want in globals directly, you’d actually be storing it in an external storage system. It’d be more work, but you’d get better correctness without race conditions around power loss and macro execution.
I’m not really a Node guy; there might be a solution with fewer dependencies that would make general sense here. There’s probably some sort of transactional key-value store that is lightweight enough to make a standard part of CNCjs (or perhaps already a part via transitive dependencies), unlike sqllite which would be kind of a pain to add for all platforms.
#28 – MitchBradley 于 2019-04-05
> Thanks @cheton. Can you also suggest some workaround to save last program line sent to controller before power failure?
That’s a very difficult problem to solve in CNCjs because of uncertainties in how the different system components behave on power failure. A much more robust solution would be to construct a little battery-powered logger device that watches the transmit line to the controller.
#29 – nesquik011 于 2019-04-05
Scottlaird may i have copy of the arduino system you use please ?
#30 – scottlaird 于 2019-04-06
I’m working on open-sourcing it. I need to jump through a few hoops in order to make my employer happy first, though, before I can release it on github.
Mind you, it’ll probably be mostly useful as example code, unless you feel like building an exact copy of what I have. There are a few things that could be left out to save money, and some other things that seem to be mostly pointless in practice. It should be possible to clean it up into something that is modular enough to be usable as a off-the-shelf ATC controller, but that’s not a big priority of mine this month.
OTOH, it’s not really all that much code, and it’s fairly straightforward, so hopefully it’ll be useful as-is.
#1 – scottlaird 于 2019-04-01
A bit of background on what I’m trying to do: I’m working on getting ATC working for me. I have an AMB FME-W DI spindle (basically a newer version of the old 1050W Kress, with 0-10V speed control and a factory tool changer) connected to a Grbl-driven CNC. The AMB tool changer is driven by 2 pneumatic lines, one unlocks the tool and the other ejects the tool and clears dust.
I have an Arduino sitting between my Grbl controller and a pair pneumatic solenoids that send air to the AMB spindle’s ATC. For the moment, the tool-change Arduino watches Grbl’s spindle speed, spindle reverse, and coolant lines (Grbl’s only outputs), and decides when to eject based on those. It works well enough, but it’ll never be bulletproof, because there’s no way for the tool changing system to provide any feedback at all to Grbl or CNCjs right now. So things like https://www.youtube.com/watch?v=7cLCOPLvp_g will happen.
I’d like to find ways to extend CNCjs to make it possible to sanely implement tool changers and get a reasonable user experience out of the whole thing. Part of that will almost certainly involve finding a good way to provide feedback from the ATC controller into my CNCjs tool-change macro so that the controller can say things like “slot 5 is full” or “the tool hasn’t ejected yet”. Since CNCjs macros don’t have any looping or logic constructs right now, and CNCjs doesn’t have any obvious way to talk to additional non-gcode devices, this should be a lot of fun.