Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved auto tool changer support #437

Open
4 of 12 tasks
scottlaird opened this issue Mar 31, 2019 · 35 comments
Open
4 of 12 tasks

Improved auto tool changer support #437

scottlaird opened this issue Mar 31, 2019 · 35 comments

Comments

@scottlaird
Copy link

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 Display circular arcs with G02 (clockwise) and G03 (counterclockwise) in the 3D GCode viewer #1 (slot number extracted from T~ command, slot location calculated by macro).
  2. Handle the second tool change by unloading the tool into slot Display circular arcs with G02 (clockwise) and G03 (counterclockwise) in the 3D GCode viewer #1, remembering where it came from the in first tool change, and then loading the tool from slot Dev #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?

  • NPM
  • Download the CNCjs Desktop Application

CNC Controller

  • Grbl
  • Smoothieware
  • TinyG/g2core

Hardware

  • Raspberry Pi
  • Desktop or Laptop
  • Mobile Device

Operating System

  • Not Applicable
  • Windows
  • Mac
  • Linux
@scottlaird
Copy link
Author

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.

@saxa
Copy link

saxa commented Apr 1, 2019

Cool, is this router all driven by grbl ?

@scottlaird
Copy link
Author

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.

@scottlaird
Copy link
Author

  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.

@saxa
Copy link

saxa commented Apr 1, 2019

@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.

@MitchBradley
Copy link
Contributor

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.

@karoria
Copy link

karoria commented Apr 2, 2019

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.

@scottlaird
Copy link
Author

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?

@MitchBradley
Copy link
Contributor

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.

@karoria
Copy link

karoria commented Apr 2, 2019

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.

@karoria
Copy link

karoria commented Apr 2, 2019

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 :)

@cheton
Copy link
Collaborator

cheton commented Apr 3, 2019

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:

(global=[JSON.stringify(global)]) 

All supported JavaScript global objects are listed here.

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,
};

@cheton
Copy link
Collaborator

cheton commented Apr 3, 2019

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.

@cheton
Copy link
Collaborator

cheton commented Apr 4, 2019

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: 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.

@scottlaird
Copy link
Author

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.

@MitchBradley
Copy link
Contributor

MitchBradley commented Apr 4, 2019

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 /bin/cncjs.

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 /dist/cnc/web)

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)

@scottlaird
Copy link
Author

Thanks! That should make life much more pleasant.

@scottlaird
Copy link
Author

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.

@MitchBradley
Copy link
Contributor

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.

@scottlaird
Copy link
Author

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.

@scottlaird
Copy link
Author

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.

https://www.youtube.com/watch?v=qZWI_mKBo1k

@karoria
Copy link

karoria commented Apr 5, 2019

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?

@cheton
Copy link
Collaborator

cheton commented Apr 5, 2019

@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.

@karoria
Copy link

karoria commented Apr 5, 2019

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.

@cheton cheton assigned MitchBradley and unassigned MitchBradley Apr 5, 2019
@cheton
Copy link
Collaborator

cheton commented Apr 5, 2019

@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.

@karoria
Copy link

karoria commented Apr 5, 2019

Thanks @cheton. Can you also suggest some workaround to save last program line sent to controller before power failure?

@scottlaird
Copy link
Author

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.

@MitchBradley
Copy link
Contributor

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.

@nesquik011
Copy link

nesquik011 commented Apr 5, 2019 via email

@scottlaird
Copy link
Author

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.

@karoria
Copy link

karoria commented Apr 6, 2019

Thanks @MitchBradley. Can you elaborate more or give any link regarding battery powered logger? How about connecting external EEPROM to g2core/due? Any how, i will have to struggle interfacing it with data transmission.

@MitchBradley
Copy link
Contributor

For a logger, pretty much any microcontroller would work. Connect its RX line to the RX line on the Due so it sees the same data as the Due. Keep the last few lines, or simply a line counter, in RAM. Power the micro with a battery connected to a charging circuit so the micro will stay powered for some time after external power drops. When data stops arriving, store the buffered lines in EEPROM or to and SD card, or write then to a display.
Using an external EEPROM on the g2core Due would be difficult because EEPROM writing is relatively slow and the time it takes would cause motion control problems.
The "problem" of interfacing with the data transmission is really very easy. You can connect many receivers to the same serial data line and, so long as they are configured to the same settings (baud rate, etc) they will all see the same data stream. Multiple transmitters don't work, but multiple receivers is trivial.
The tricky part is how to present the information to the user, but even that is not too difficult. Deciding how you want to present it is the key decision that drives the system design.
Instead of a rechargeable battery, you could use a 6V lantern battery which will power a micro for a long time. Set up a diode-or circuit so that a mains-powered adapter supplies the micro when mains power is available, automatically switching to the battery if mains power is lost. That way the battery will not drain when power is only, leaving more charge to keep the micro on for a long time after a power outage.

@karoria
Copy link

karoria commented Apr 6, 2019

Thanks a lot @MitchBradley for this valuable guidance. I will definitely work on it.

@cheton cheton added this to the 1.9 milestone Apr 16, 2019
cheton added a commit that referenced this issue Apr 20, 2019
…rt (#437) (#460)

* Update translation keys

* Add a new event that is triggered when the controller is ready to start (#437)
cheton added a commit that referenced this issue Apr 20, 2019
…rt (#437) (#460)

* Update translation keys

* Add a new event that is triggered when the controller is ready to start (#437)
cheton added a commit that referenced this issue Apr 20, 2019
…rt (#437) (#460)

* Update translation keys

* Add a new event that is triggered when the controller is ready to start (#437)
cheton added a commit that referenced this issue Apr 20, 2019
…rt (#437) (#460)

* Update translation keys

* Add a new event that is triggered when the controller is ready to start (#437)
@cheton cheton modified the milestones: 1.9, 1.10 Apr 22, 2019
cheton added a commit that referenced this issue Apr 22, 2019
… executable (#440)

* Avoid relative path hell

* Folder restructure

* Work in progress

* Fix incorrect route of user accounts

* Enhances the evaluate expression library that enables full support for assignment and sequence expressions (#442)

* Enables full support for assignment expression and sequence expression

* eslint fixes

* [Feeder][Sender] Add global variables support (#443)

* [Macro][Sender] Add global variables support

* Returns global variables with populateContext()

* Update macro variables usage

* Update macro variables usage

* Supports primitive types and global variables

* Enhancement for evaluating expressions (#444)

* Enhancement for evaluating expressions

* Centralize global objects in one place

* Rename context to vars

* eslint fixes

* Update variables

* Update package.json

* Update dependencies

* Rename cnc to cncjs

* Upgrade Three.js from 0.94 to 0.103

* Update resource.json

* Fix a warning that the shading option is removed from MeshMaterial

* Change the render order

* Render cutting tool and cutting pointer in the 3D visualizer

* Fix for Marlin controller first-move bug (issue #312) (#449)

* Fix eslint errors in 4a4b67b

* Update resource.json

* [Marlin] Fixed a bug of calling a controller initialization method that has been removed

* Fix an issue that dropdown menu gets clipped by container with overflow:hidden property (#445)

* Fix a overflow bug in the console widget (#452)

* [g2core] Address an issue that spindle will restart after stopping program execution (#428) (#451)

[g2core] Address an issue that spindle will restart after stopping program execution (#428)

* Add support for specifying mount points in the .cncrc file (#459) (#461)

* Add a new event that is triggered when the controller is ready to start (#437) (#460)

* Update translation keys

* Add a new event that is triggered when the controller is ready to start (#437)

* Fix for the bug @cheton found in #454 (comment) (#462)

* Rename bin/legacy-cli to bin/cnc

* Update .cncrc

* Update dependencies

* Update dependencies

* Update resource.json

* Update Dockerfile

* Turn into full screen web app on mobile devices (#402)

* Update supported Node.js versions
@scottlaird
Copy link
Author

@nesquik011, a partial version of the code is now available at https://github.com/scottlaird/cncatc. As I said before, it's of limited use as-is, but it's now open source under the Apache license. I have a couple pending changes that'll go in soon, but I'm mostly working on finishing assembling the CNC itself right now. Tool-change work is on hold until I finish milling (and then installing) my 1400x1000mm aluminum base plate.

@nesquik011
Copy link

nesquik011 commented Apr 23, 2019

@scottlaird you gave cncjs new life form :D i am happy you are doing this , and i would love if you share videos of how you setup things , and build the machine , if you dont mind sir , and it would be wonderful if you talked about the ATC itself
thank you so much you dont know how long i have been waiting for this to happen ( years )

i wish it could work with many ATCs and machine soon

@cheton cheton pinned this issue May 7, 2019
@cheton cheton added this to Needs triage in 1.10 via automation May 9, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
1.10
  
Needs triage
Status: No status
Development

No branches or pull requests

6 participants