abey79 / vpype

The Swiss-Army-knife command-line tool for plotter vector graphics.
https://vpype.readthedocs.io/
MIT License
714 stars 63 forks source link

`write` command: add support for gcode output #139

Closed tatarize closed 3 years ago

tatarize commented 3 years ago

Vpype is already pretty solid to write gcode.

You set the units to inch or cm and then you send the points to G1 Xv.vvv Yv.vvvv with a little bit of header information and footer information. You don't need to mess with any of the fancier commands since you're just writing the data out. G1 means go there and draw that, G0 means go there with the pen up.

abey79 commented 3 years ago

with a little bit of header information and footer information

That's the crux of the matter imo. How to design the UX of this feature to make it actually useable for people, ie. have the right header, footer, unit, scaling and offset?

tatarize commented 3 years ago

Couple options. They basically write themselves. They are -g20 -g21 -g90 -g91. -header "M0\nG002\n" -footer "M99\n"

Most of that stuff doesn't affect the output. Except those gcode switches will have massive effects on what you should produce. You might want to specify the type of Mcode for stop but beyond that they'd have to either feed you the stuff you want in the file or not have that stuff in the file. But, then other options wouldn't be breaking changes.

tatarize commented 3 years ago

The important factors are -g20 and -g21 which divide between inches and mm. And -g90 and g91 which are absolute and incremental. The rest of the stuff (I made up those mcodes there) don't need anything with them until people ask for them. So you just have them feed you what footer or header information they want appended to that code. And you're done. That'll actually be enough to output gcode successfully, everything else is features that will remain compatible with that original API.

tatarize commented 3 years ago

The offset and work offset stuff isn't things you need to worry about. They'd either fix that themselves in vpype or not worry about it. Also the work offsets are for the canned routines that work like subroutines within gcode, aren't things you'd have to write. Everything else is features. Since it wouldn't matter too much for the API.

abey79 commented 3 years ago

They'd either fix that themselves in vpype or not worry about it.

I disagree with this. I strive for predictability in vpype. What is in the pipeline (show -a -u cm) should be what ends up on paper, including scale and offset (unless --center is used in write, in which case the offset is automatically adjusted). A lot of work went into that for HPGL output. I have nothing against a "hacky" gcode plugin that would require the user to "cheat" with scale and translate in vpype to get the right thing at the end, but I wouldn't include it in vpype core.

tatarize commented 3 years ago

I'm not saying making it hacky. I'm saying there's some other gcode routines that don't need to be supported initially. They could adjust that stuff themselves or make a feature request as needed.

Gcode has some fancy stuff like work offset routines that work like subroutines. Where you tell it the gcode you're using and work offsets and it will apply the cam routine to run a particular set of gcode with this particular offset. Calling 0,0 the origin for most output is fine. You're still capturing the main output that most people would use. And modifications of that output are features.

The important thing here would be API design, not leading to any breaking changes. You'd need commands that fully capture what the gcode is doing without needing anything that breaks the API later.

For example if you wrote gcode without any options set, you'd need to write something default but correct for default. So you'd write any feed rates in g94 units/s (units=mm by default here) mode. You'd opt for g17 (XY plane coords), even though you could support g18 (XZ) and g19 (YZ) later. The lack of the option doesn't mess with anything. We'd start in g21 (same as g71) rather than g20 (same as g70) since mm is the default unit when no units are expressed. But, messed up the orientation and expressed things in +y is bottom and gcode says +y is top, then there's an issue. They either need to express a flag to get gcode written correctly or you need a breaking change to fix that.

What's more, you put the default of these options into the header yourself so the regardless of the machine it knows what you're writing.

So you start out with a default header that says g21 g17 g91 g94. Maybe ask some users what a proper F command for them would be by default. Expressed in g94 units mm/s or whatnot and then go ahead and print that stuff out in your header followed by all your basic g0 and g1 commands. Then if they want options, you would say let them switch g90 for g91 and write your code in absolute values rather than relative values. or if they wanted you could switch to g20 from g21 and you'd write thing scaled to inches rather than mm. And the procedures to make that work are a bit obvious.

I'm not saying make it hacky and subpar. I'm saying it's pretty easy to future proof this write routine where people in future versions can have more options but the options they already use aren't going to suddenly change what output it was giving before. You don't need to support all of the gcode spec stuff (which actually varies a lot from machine to machine and most folks use pre-processor scripts for their gcode). You can basically just make write-gcode write: g21 g17 g91 g94 and write the g0 and g1 code with 4 digits after the radix point. Just express if your code is mm with g21 and your code is absolute with g90 and your code uses XY with g17 and so long as you do that your code is correct gcode. Options could be added in later. The amount of digits after the radix could be defined, using g91 instead of g90 could be an option, same with g21 vs g20.

So you'd initially just write

G21
G17
G90
...
G0 X0.000 Y0.000
G1 X0.000 Y0.000
...
M30

With no options and write your G0 moves and G1 draw line commands in absolute coordinates with 4 digits after the radix in mm, with the +y direction being towards the top. Then everything else would be features. Then offer up -g21 and -g20, and -g90 and -g91 features later on.

tatarize commented 3 years ago

The things you'd actually need to consider are do you set "M6 T1" when you output a layer with a different color of pen-width? You'd do "M6 T2" etc, based on the tool changes. Because if you decide on a behavior it needs to stay consistent, or you have a forced option or a breaking change in your future. But, that's all I'm saying. For the most part you could hack out a working bit of gcode output in a half an hour, making for a solid default output.

And that output could be properly future-proofed.

abey79 commented 3 years ago

The multitude of scenarii and the need for multiple iteration based on user feedback reinforce my impression that this needs to be a plug-in with a dedicated command, at least at the beginning. If/when it matures sufficiently, it won't be too late to integrate into vpype core. I might eventually give it a try but I'm lacking test hardware to test and I have other things I want to work on first. Ideally, someone interested in the feature would come forward and work on this a bit, in which case I'd glad to assist.

tatarize commented 3 years ago

It does need some feedback as to what some gcode for plotter looks like. Does it have M6 T1 stuff for pen switching or not, I'm not sure if that should be default or not. But, the basic output is pretty easily mapped out. We'd be talking maybe 20 lines of code.

tatarize commented 3 years ago

Okay, having consulted with some folks. Gcode should require a gcode configuration attribute.

Then just have a generic default version that exports the data in the sort of standardized way I proposed earlier. Then anything else is just a different configuration, sharing what code can be shared and producing different strokes for different folks. It would be pretty easy to specify such things and the default output would be kinda basic and write that into something resembling gcode. It sends all the more difficult choices to future formats that are required to be specified.

Though this would again depend on having a standardized way to do some basic writing of files. That or it would get gwrite as a command. And everything gets a different write command.

tatarize commented 3 years ago

https://github.com/tatarize/vpype-gcode

Works and is very general.

https://github.com/tatarize/vpype-gcode/blob/main/vpype_gcode/gwrite.py

Basically allows specifying the entire grammar.

Options:
  -v, --version TEXT    version to write
  -h, --header TEXT     header to write
  -m, --move TEXT       move to write
  -l, --line TEXT       header to write
  -b, --preblock TEXT   preblock to write
  -B, --postblock TEXT  postblock to write
  -c, --prelayer TEXT   prelayer to write
  -C, --postlayer TEXT  postlayer to write
  -h, --footer TEXT     header to write
  -s, --scale FLOAT     scale factor
  -x, --flip_x          flip_x from native
  -y, --flip_y          flip_y from native
  -r, --relative        use relative coordinates
  --help                Show this message and exit.

Maybe needs some additional feedback, but it's perfectly workable for writing stuff out. And should cover like 99% of the desired bits of gcode, letting people modify the output pretty significantly.

tatarize commented 3 years ago

This actually expanded and with a great rewrite from @theomega is pretty svelte. The hope would be to include that into vpype directly and deprecate vpype-gcode.

tatarize commented 3 years ago

Closing this down since gcode support in the plugin is being pulled towards main etc.