EmbroidePy / pyembroidery

pyembroidery library for reading and writing a variety of embroidery formats.
MIT License
210 stars 37 forks source link

Help needed, color change macros #142

Open Ams-Laser opened 2 years ago

Ams-Laser commented 2 years ago

Hello, as far as i could understand (im new to python) the folloing code is where the color change comands go

elif command == COLOR_CHANGE: write_string_utf8(f, "M00\n")

now, if y want to add color change support for a modified muty needle machine, and i need to execute ceratain code for each one of the 9 needles available, how could i get the color we are changeing to ?

any help is greatly apreciated

Ed

tatarize commented 2 years ago

Vpype has a solid solution to this a bit, since you can correctly define the routines. Here you might be better off editing the data directly. There is some work with regards to making a profile based corrected branch for gcode writing. Part of the issue here is that gcode especially hobbyist gcode can vary greatly from version to version. The gcode built in is based on one original hobbyist whose code didn't have color changes but rather paused the machine for them and rather than stitching per normal was hooked up to sew with the rotation of the wheel. Basically it was a hacked sewing machine with an XY plotter, and used the sewing machine wheel to drive the needle up and down. The result was that color changes would be done with M00 and stitches done with movement along the Z axis.

A few years after writing that I figured out the much better method of doing that. Specifically because there are so many more gcode users among plotting community and I had some of my work adapted there to help with vpype. Namely you can define a profile for the gcode and then using that profile define the different parts of the different commands.

The branch to do this generic-writer wasn't fully finished but I can check what my progress was since it seems like the easiest way forward for your project here. I opened pr #143 to go over it and evaluate what was done. I'll check, I think it was really close at the time. And it's the only way to properly capture all the different things in gcode that you might need or want to adjust.

tatarize commented 2 years ago

Okay, I pushed the generic writer forward and fixed some of the other stuff. So now you can quickly make a duplicate pure code version of the gcode writer.

        gcode_writer_dict = {
            "scale": (-0.1, -0.1),
            "pattern_start": "(STITCH_COUNT: {stitch_total})\n"
            "(THREAD_COUNT: {color_change_count})\n"
            "(EXTENTS_LEFT: {extents_left:.3f})\n"
            "(EXTENTS_TOP: {extends_top:.3f})\n"
            "(EXTENTS_RIGHT: {extends_right:.3f})\n"
            "(EXTENTS_BOTTOM: {extends_bottom:.3f})\n"
            "(EXTENTS_WIDTH: {extends_width:.3f})\n"
            "(EXTENTS_HEIGHT: {extends_height:.3f})\n"
            "(COMMAND_STITCH: {stitch_count})\n"
            "(COMMAND_COLOR_CHANGE: {color_change_count})\n"
            "(COMMAND_TRIM: {trim_count})\n"
            "(COMMAND_STOP: {stop_count})\n"
            "(COMMAND_END: {end_count})\n",
            "metadata_entry": "({metadata_key}: {metadata_value})\n",
            "thread_entry": "(Thread{thread_index}: {thread_color} {thread_description} {thread_brand} {thread_catalog_number})\n",
            "stitch": "G00 X{x:.3f} Y{y:.3f}\nG00 Z{z:.1f}\n",
            "color_change": "M00\n",
            "stop": "M00\n",
            "end": "M30\n",
        }
        EmbPattern.write_embroidery(
            GenericWriter,
            pattern,
            "myfile.gcode",
            gcode_writer_dict,
        )

This doesn't go into details with all the features but if you need to change color change which is M00\n there you can do that and it'll write that out. This formatting scheme has been used to create all manner of gcode, and formats as distinct as svg to json and various rare ascii-like formats.

tatarize commented 2 years ago

I focused on purely getting it to work so if you have need for some more specifics with the gcode I could certainly help with that. The "stitch" format uses G00 which is isn't typical but it was doing the sewing with the Z value. If you need that to be G01, or any other conversions that's fairly easily doable. There's hooks for jump as well which would properly go G01.

It's new and there's basically no documentation, yet, so if you have some additional questions kindly do ask.

The core part works like another project I did that sort of used the same scheme: https://github.com/plottertools/vpype-gcode/

Parameters that it accepts are:

        self.metadata_entry = settings.get("metadata_entry", None)
        self.thread_entry = settings.get("thread_entry", None)
        self.pattern_start = settings.get("pattern_start", None)
        self.pattern_end = settings.get("pattern_end", None)
        self.document_start = settings.get("document_start", None)
        self.document_end = settings.get("document_end", None)
        self.color_start = settings.get("color_start", None)
        self.color_end = settings.get("color_end", None)
        self.color_join = settings.get("color_join", None)
        self.block_start = settings.get("block_start", None)
        self.block_end = settings.get("block_end", None)
        self.block_join = settings.get("block_join", None)
        self.segment_start = settings.get("segment_start", None)
        self.segment = settings.get("segment", None)
        self.segment_end = settings.get("segment_end", None)
        self.segment_join = settings.get("segment_join", None)
        self.stitch_first = settings.get("stitch_first", None)
        self.stitch_last = settings.get("stitch_last", None)
        self.stitch = settings.get("stitch", None)
        self.stop = settings.get("stop", None)
        self.jump = settings.get("jump", None)
        self.trim = settings.get("trim", None)
        self.needle_set = settings.get("needle_set", None)
        self.color_change = settings.get("color_change", None)
        self.sequin = settings.get("sequin", None)
        self.sequin_mode = settings.get("sequin_mode", None)
        self.slow = settings.get("slow", None)
        self.fast = settings.get("fast", None)
        self.end = settings.get("end", None)

The main blocks are pattern, document, color, block. These all have start, end, and join values. Segments refer to all stitches regardless of types. Stitch are specific to stitches, stop, jump, trim, needle_set, color_change, sequin, sequin_mode, slow, fast, and end commands all also exist and are specific to just those commands.

Pattern refers to the entire pattern. Document is just from the first stitch entry to the next end value. Color refers to color change'd blocks of commands. Block refers to clumps of uninterrupted stitches. The formatting here gives some examples of different properties but there's a lot of other values that aren't referenced but could be. For example thread entries will notably allow you to output all the thread metadata index color description brand catalog_number chart details weight all of these are prefixed with thread_ so if you wanted to just list the thread description and color. "thread_entry": "{thread_description}, {thread_color}" would let you format that output.

tatarize commented 2 years ago

Relevant to your original question. If you have this setup and you want to say issue an M6 toolchange you would replace the color_change code with: "color_change": "M06 T{cmd_needle}\n", this gives the M06 command and the command's needle value which isn't common issued through other means. As I assume whatever needle device you have will use and reuse these needles with whatever sort of gcode head you have for it.

tatarize commented 2 years ago

Do note I just updated pyembroidery to bring this functionality to you, so you'll need to do pip install -U pyembroidery to use that.

Ams-Laser commented 2 years ago

@tatarize First of all i want to thank you for the quick response to my request, being new to python, im in the process of digesting all this new information,

regarding: Relevant to your original question. If you have this setup and you want to say issue an M6 toolchange you would replace the color_change code with: "color_change": "M06 T{cmd_needle}\n", this gives the M06 command and the command's needle value which isn't common issued through other means. As I assume whatever needle device you have will use and reuse these needles with whatever sort of gcode head you have for it.

i could use:

if {cmd_needle]=1: "G0 A100 \n" elseif {cmd_needle}=2: "G0 A200 \n"

and so on for the 9 needles available ?

the "G0 AXX" command is to position the acive needle using axis "A"

am i correct ?

Thanks Ed

Ams-Laser commented 2 years ago

hello

also according to:

Rapid Overrides

Immediately alters the rapid override value. An active rapid motion is altered within tens of milliseconds. Only effects rapid motions, which include G0, G28, and G30. If rapid override value does not change, the command is ignored. Rapid override set values may be changed in config.h. The commands are: 0x95 : Set to 100% full rapid rate. 0x96 : Set to 50% of rapid rate. 0x97 : Set to 25% of rapid rate.

we could use the set to 100% for stitch fast, and set to 25% for stitch slow this woudl mimic the original machines

Ed

Ams-Laser commented 2 years ago

@tatarize BTW what country/timezone are you from? im living in Guadalajara Mx, central time

tatarize commented 2 years ago

GMT-8. About the same time zone but weird sleep schedule.

You'd want your color change command to reference the cmd_needle value:

"color_change": "G0 A{cmd_needle}00\n",

So altogether we'd be looking at code like:

gcode_writer_dict = {
            "scale": (-0.1, -0.1),
            "stitch": "G00 X{x:.3f} Y{y:.3f}\nG00 Z{z:.1f}\n",
            "color_change": "G0 A{cmd_needle}00\n",
            "slow": "S500\n"
            "fast": "S1500\n"
            "stop": "M00\n",
            "end": "M30\n",
        }
        EmbPattern.write_embroidery(
            GenericWriter,
            pattern,
            "myfile.gcode",
            gcode_writer_dict,
        )

As an example. Assuming the stitch code was right. I added in commands for slow and fast these commands are in the pyembroidery standard as standard commands but most files will not possess them. But, if we're writing gcode then it's entirely possible and plausible to add in those commands, these are standard for .u01 type files on a Barudan machine but if you're using gcode you can actually directly set the speed at which things move. Assuming you have some kind of stitching mechanism it should work fine for that.

The code here should be able to write whatever you need. The A100 for needle 1 and A200 for needle doesn't quite let needle 2 be called needle 200 but you can just add the 00 after the {cmd_needle} there. Also, this setup assumes you begin with needle 1. If that's not the case and you have a different config and you need it to give the needle command at the start of the file which is entirely possible. You'd need to switch away from color_change operations and use needle_set operations.

You'd do this with an extra setting being sent to the writer for thread_change_command=NEEDLE_SET the difference here is that needle sets (though rarer than color change). Occur before a color block to indicate the set needle. In theory most machines start at the correct needle and tend to just stop or sometimes have preset needle code values to go to the next element. The exception to this is again .u01 format by Barudan which sets gives the needle to set as part of the file itself.

Most of this stuff depends on how the gcode controller is controlling the embroidery machine. Which is actually why it needs something like generic writer. The main reason is that there can be any arrangement of hobbyist machines and to cover them all requires something so general and generic that it can write out most different formats.

For example the following code:

        pattern = EmbPattern()
        pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "red")
        pattern.add_command(SLOW)
        pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "blue")
        pattern.add_command(FAST)
        pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "green")

        gcode_writer_dict = {
            "scale": (0.1, -0.1),
            "thread_change_command": NEEDLE_SET,
            "write_speeds": True,
            "pattern_start": "G21 G90 F6000 (mm units, absolute positioning, speed)\n",
            "thread_entry": "(Thread{thread_index}: {thread_color} {thread_description} {thread_brand} {thread_catalog_number})\n",
            "block_start": "G00 X{x:.3f} Y{y:.3f} (Starting new location)\n",
            "stitch": "G01 X{x:.3f} Y{y:.3f}\n",
            "slow": "F1000\n",
            "fast": "F6000\n",
            "needle_set": "G00 A{cmd_needle}00  (Changing to color: {cmd_thread})\n",
            "end": "M30\n",
        }
        file = "file-generic.gcode"
        EmbPattern.write_embroidery(
            GenericWriter,
            pattern,
            file,
            gcode_writer_dict,
        )

Produces this gcode:

G21 G90 F6000 (mm units, absolute positioning, speed)
(Thread0: #ff0000 None None None)
(Thread1: #0000ff None None None)
(Thread2: #008000 None None None)
G00 A100  (Changing to color: 0)
G00 X0.000 Y0.000 (Starting new location)
G01 X0.000 Y0.000
G01 X0.000 Y-10.000
G01 X10.000 Y-10.000
G01 X10.000 Y0.000
G01 X0.000 Y0.000
G00 A200  (Changing to color: 1)
F1000
G01 X0.000 Y0.000
G01 X0.000 Y-10.000
G01 X10.000 Y-10.000
G01 X10.000 Y0.000
G01 X0.000 Y0.000
G00 A300  (Changing to color: 2)
F6000
G01 X0.000 Y0.000
G01 X0.000 Y-10.000
G01 X10.000 Y-10.000
G01 X10.000 Y0.000
G01 X0.000 Y0.000
M30

Basically if you need it to write the gcode for you that's quite able to be sorted out. You just need to know the exact sort of things you specifically need in the gcode. If you tell me what that might be, I could likely tell you if it requires something that the program can't do (I would then likely update it). But generally whatever sort of thing you need it should be able to to do that.

You could send the rapid speed change commands and they would, in theory work, but I think those are for GRBL and they tend to be realtime commands. Which means regardless when you sent them they take effect immediately. You might more correctly and properly want F commands which should set the feed rate which is the speed in some setups.

Once you pin down the formatting right, I could certainly advise you on how to make the system output that format. But, it sounds like what you're doing is replacing a busted and not-easy-to-replace (or costs as much as a house) controller card for a particular embroidery machine, and it might be easier to get an off the shelf GRBL device and a raspberry pi, then you could just and send the embroidery files having them convert to grbl and control the device. It might be hard to do things like thread break detection, since I don't know how that works etc (but there are a couple triggers for emergency stop on many gcode controller cards), but it all sounds doable.

I'm quite happy to make sure you can convert whatever format into whatever form of gcode you end up with. Since that's well within the scope of this project. Though stuff like remi (python remote interface) and pyserial (send data to across the serial for the grbl directly) would be nice for such a project might be beyond the scope there. But, I'll make sure you can do the conversion to your format of gcode from typical embroidery formats.

Ams-Laser commented 2 years ago

hello,

regarding the gcode output: G21 G90 F6000 (mm units, absolute positioning, speed) (Thread0: #ff0000 None None None) (Thread1: #0000ff None None None) (Thread2: #008000 None None None) G00 A100 (Changing to color: 0) G00 X0.000 Y0.000 (Starting new location) G01 X0.000 Y0.000 G01 X0.000 Y-10.000 G01 X10.000 Y-10.000 G01 X10.000 Y0.000 G01 X0.000 Y0.000

G00 A200 (Changing to color: 1) HERE THE 1 BEFORE THE 00 IS THE NEEDLE NUMBER

the problem is i need to insert certain commands depending on the nedle number like for needle 0 i could send: G0A51 //move needle positioner to needle 0 coordenates G0B8 //engage neddle clutch M25 0x0 turn on needle 0 light

or can any other block of code

i need to be able to define different code blocks for each needle

as per the real time feed overrides this is ok since im using GRBL this would mimick the slowdown of the machine

Thanks for the help

Ed

Ams-Laser commented 2 years ago

would it be possible to insert code blocks based on the needle number we are changeing to?

this would alow to: make this universal for any gcode controlled machine turn on light or buzzer to alert use a color change is needed disengage needle clutch if needed set needle changer position engage neddle clutch if needed resume stitching

i king of thing of this genericwriter as a cnc post procesor file i will be more than happy to provide the needed explanation on how a cnc postprocesor works and what parameters an embroidery postprocessor would ever need, it will be lots more than what i ever need but it will be universal for anyone building a machine to be able to get a custom gcode output

as i will be using stepper axis to control needle change, but someone might be using a servo or other means

this way it will be more like a universalgcodewriter, or a emb.gcode.postprocessor

i would be more than happy to help finishing a fully featured postprocessor :)

Ed

Ams-Laser commented 2 years ago

Hello something happen, now im not getting any output on mi gcod file ed

Ams-Laser commented 2 years ago

@tatarize can you please help me get my otput back :(

Thanks

tatarize commented 2 years ago

Any indication of what was done differently. There's likely a minor error and I'd need to see the code to diagnose it.

tatarize commented 2 years ago

Specific code sections based on the needle selected isn't properly achievable you could write or use a gcode post-processor. And while that is out of the realm of the project all you're doing is basically writing anything you want for the needle switch and then changing the needle based on that. So if you set the needle code to write Needle2\n you'd just line by line check the resulting gcode and do a match and replace within the text. It's not that difficult, but there's not context specific gcode switching based on the specific needle number. There might, however, be an easy enough way to do that in the code.

tatarize commented 2 years ago

https://www.delftstack.com/howto/python/python-replace-line-in-file/ for example covers that sort of basic scripting process.

Sorry for the delay on the reply. I'll look into giving you methods of specific needle sets values to gcode. That sounds like a reasonable enough request.

tatarize commented 2 years ago

I added 1.4.35. It's now possible to rewrite some segment code like that:

    def test_generic_write_gcode_multi(self):

        pattern = EmbPattern()
        pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "red")
        pattern.add_command(SLOW)
        pattern.add_block([(5, 5), (0, 100), (100, 100), (100, 0), (5, 5)], "blue")
        pattern.add_command(FAST)
        pattern.add_block([(10, 10), (0, 100), (100, 100), (100, 0), (10, 10)], "green")

        gcode_writer_dict = {
            "scale": (0.1, -0.1),
            "thread_change_command": NEEDLE_SET,
            "write_speeds": True,
            "pattern_start": "G21 G90 F6000 (mm units, absolute positioning, speed)\n",
            "thread_entry": "(Thread{thread_index}: {thread_color} {thread_description} {thread_brand} {thread_catalog_number})\n",
            "color_start": "G00 X{x:.3f} Y{y:.3f} (Starting new location)\n",
            "stitch": "G01 X{x:.3f} Y{y:.3f}\n",
            "slow": "F1000\n",
            "fast": "F6000\n",
            "needle_set": {None: ("{cmd_needle}", "default value {cmd_needle}\n"), "1": "G0A51\n", "2": "G0B8\n"},
            "end": "M30\n",
        }
        file = "file-generic.gcode"
        EmbPattern.write_embroidery(
            GenericWriter,
            pattern,
            file,
            gcode_writer_dict,
        )

The needle_set command shows the general format. Basically the None value of the dict is to be a tuple of key, and default. The rest of the dictionary calls the main dictionary entries which either exist or get replaced with the dictionary. For example running that code results in:

G21 G90 F6000 (mm units, absolute positioning, speed)
(Thread0: #ff0000 None None None)
(Thread1: #0000ff None None None)
(Thread2: #008000 None None None)
G00 X0.000 Y0.000 (Starting new location)
G0A51
G01 X0.000 Y0.000
G01 X0.000 Y-10.000
G01 X10.000 Y-10.000
G01 X10.000 Y0.000
G01 X0.000 Y0.000
G0B8
F1000
G01 X0.500 Y-0.500
G01 X0.000 Y-10.000
G01 X10.000 Y-10.000
G01 X10.000 Y0.000
G01 X0.500 Y-0.500
default value 3
F6000
G01 X1.000 Y-1.000
G01 X0.000 Y-10.000
G01 X10.000 Y-10.000
G01 X10.000 Y0.000
G01 X1.000 Y-1.000
M30
Ams-Laser commented 2 years ago

Any indication of what was done differently. There's likely a minor error and I'd need to see the code to diagnose it.

im running same code as wen i started

import pyembroidery import sys infile=str(sys.argv[1])+".DST" outfile=str(sys.argv[2])+".gcode" pyembroidery.convert (infile, outfile)

i do get a file output but no code just like

STITCH_COUNT: 1) (THREAD_COUNT: 0) (EXTENTS_LEFT: 0.000) (EXTENTS_TOP: 0.000) (EXTENTS_RIGHT: 0.000) (EXTENTS_BOTTOM: 0.000) (EXTENTS_WIDTH: 0.000) (EXTENTS_HEIGHT: 0.000) (COMMAND_END: 1) M30

thanks

tatarize commented 2 years ago

You need to put it in the backticks to keep the tabs. In Python the tabbing is quite essential to the the code.

The output there says there is no code. That the extends go only to 0 and the only command in the pattern you gave it was "END".

The issue isn't the code it's apparently the DST. If you zip it up and include it here I could test it directly but I think you might have deleted the dst contents at some point.

Ams-Laser commented 2 years ago

You need to put it in the backticks to keep the tabs. In Python the tabbing is quite essential to the the code.

The output there says there is no code. That the extends go only to 0 and the only command in the pattern you gave it was "END".

The issue isn't the code it's apparently the DST. If you zip it up and include it here I could test it directly but I think you might have deleted the dst contents at some point. files.zip

attached the files im testing with and the output i get

Thanks

tatarize commented 2 years ago

Worked fine.

python DST2GC.py comis myoutput

You might be adding the dst of the filename into the script code which is causing it to not find the file and thus an empty file.

tatarize commented 2 years ago

Try this script:

import pyembroidery
import sys

pyembroidery.convert(sys.argv[1], f"{sys.argv[1]}.gcode")

It's a bit more simplistic but it'll be pretty easy. You call it on any file or even drag and drop a file on it as a script and it'll do the conversion pretty easy for you. It just appends .gcode to the output file which isn't an issue to do .dst.gcode and it makes it really clear what file that started with.

tatarize commented 2 years ago

Using the latest version. Note I just pushed a newer version to make sure this would work correctly.

from pyembroidery import *
import sys

gcode_writer_dict = {
    # This is the scaling from 1/10MM to MM which is gcode standard. Flipping Y-axis.
    "scale": (0.1, -0.1),
    # We are using the needle change rather than color change command.
    "thread_change_command": NEEDLE_SET,
    # This tells it to write speed changes rather than strip them this is typically only a
    # Thing within U01 file formats but gcodes can write speed changes with the F command.
    "write_speeds": True,
    # Default commands at the start of the pattern.
    "pattern_start": "G21 G90 F6000 (mm units, absolute positioning, speed)\n",
    # This writes thread info, using () brackets to make them GCODE comments.
    "thread_entry": "(Thread{thread_index}: {thread_color} {thread_description} {thread_brand} {thread_catalog_number})\n",
    # This occurs when a new color is started. block_start could also be use for intercolor location changes
    "color_start": "G00 X{x:.3f} Y{y:.3f} (Starting new location)\n",
    # Default stitch command.
    "stitch": "G01 X{x:.3f} Y{y:.3f}\n",
    # Example of slow command sets the feed rate to 1000
    "slow": "F1000\n",
    # Example for fast command this is 6x the slow speed. Note this is an example batch of code
    "fast": "F6000\n",
    # Needle set with optional dynamic values.
    "needle_set": {
        # None, given a tuple of key creation value and a default value (if no key matches)
        None: ("{cmd_needle}", "default value {cmd_needle}\n"),
        # Overrides cmd_needle==1 value.
        "1": "G0A51\n",
        # Overrides cmd_needle==2 value.
        "2": "G0B8\n",
    },
    # Called at the end of the gcode.
    "end": "M30\n",
}

# This section performs the actual writing with the above dictionary.
EmbPattern.write_embroidery(
    GenericWriter,
    EmbPattern(sys.argv[1]),
    f"{sys.argv[1]}.gcode",
    gcode_writer_dict,
)

I added a bunch of python comments to explain each section and what it was doing to make it more adaptable.

Here's tog.py as a script (to-g as in gcode) .

tog.zip

python tog.py comis.DST works.

I formatted everything out nicely and tried to make sure it had comments and explained what it should be doing.

Your job is likely not messing with the python that much but getting all the regular parts to work well with grbl code.

Ams-Laser commented 2 years ago

EXCELENT!!!!!!!!!! will go play with it now, ill let you know how it went

Thanks Edward

Ams-Laser commented 2 years ago

@tatarize , from command line i still get blank output, but dropping a dst on the py file works great!!!! just one litle thing to add we are missing the z value in mm to complete 1 stitch and the actual z output to do the stitching

if it isnt much to ask, can you please add also the tread cut commnads section so i can energize the tread cut solenoids (since im converting a tajima machine to gcode controller

thanks

Edward

Ams-Laser commented 2 years ago

Hello, i have tryed this line

# Default stitch command.
"stitch": "G01 X{x:.3f} Y{y:.3f} Z{Z%.1f}\n",

but did not work

Ed

tatarize commented 2 years ago

"stitch": "G01 X{x:.3f} Y{y:.3f} Z{z:.1f}\n", Note the {} brackets are formatting strings values so you need z which is lower rather than upper case and you need the color : the section there is Z{z:.1f} which is Z as a string value then in the formatting brackets it does the variable z (note case matters) and the formatting which is .1f which means float point with one value of decimal. It seems like the 3 issues (case, lack of color and extraneous %) could have been copy and pasted.

The Z value depends on the type of system you have setup. In some hobby setups it does the wheel turning since it's hooked to a sewing machine wheel. In your case I do not know what you use to trigger the needle down, and I did not assume.

Ams-Laser commented 2 years ago

The Z value depends on the type of system you have setup. In some hobby setups it does the wheel turning since it's hooked to a sewing machine wheel. In your case I do not know what you use to trigger the needle down, and I did not assume.

Hello, thanks again, im still trying to understand phyton,

yes, th z value is the number of mm needed to advance z axis to turn the wheel 1 full turn,

if we could have a setting within the tog.py like :

use Z for stitch= YES, NO Stitch Z Value=12

if use Z for stitch =NO then: stitch commands=" whatever code needed"

else: do not output Z values or stitch commands

please note we would need the Z axis or stitch commands to be on a separate line from the XY moves this to guarant that the move has been completed before we stitch

Thanks again Ed

tatarize commented 2 years ago

So would movement commands have Z0 and stitch commands use Z12? I'm thinking Z is needle position so you want to indicate position and say Z12 to change needle position down and Z0 to get it back up again before moving?

You'd do your stitches: "stitch": "G01 X{x:.3f} Y{y:.3f}\nZ12\nZ0\n",

That's three lines go to position, needle down, needle up. Writing it is easy if the right commands are sorted out. There are some formats where the order matters, but I think default is "move then stitch" but some commands in some formats mean "stitch then move", but I think this should be correctly sorted for you in pyembroidery.

In this case each stitch you are adjusting then counter adjusting the z level.

Ams-Laser commented 2 years ago

Great, this works for incremental seretings

"stitch": "G01 X{x:.3f} Y{y:.3f}\nG91\nZ150\nG90\n",

this is my output: G01 X-36.800 Y-32.100 G91 Z150 G90 G01 X-36.500 Y-32.500 G91 Z150 G90 G01 X-36.200 Y-33.000 how about for users requiring absolute coordinates (and avoid some communication overhead)

is there a way to have Z increment a set value for each stitch like in the original file where:

if command == STITCH: write_string_utf8(f, "G00 X%.3f Y%.3f\nG00 Z%.1f\n" % (x, y, z)) z += increment_value

mabe leave a option to alow both cases for diferent setups ?

thanks

Ed

tatarize commented 2 years ago

Rather than switch from G91 and G90 back and forth you could stay in G91 and use dx and dy for the values there.

"stitch": "G01 X{dx:.3f} Y{dy:.3f}\nZ150\n",

So long as during the startup routine you set G91 rather than G90 that should be fine. Note inside the {} format brackets the code there uses dx and dy rather than x and y which provides the difference in x from the previous location.

tatarize commented 2 years ago

The z value does exist and it does increment exactly like in the original file. If you set z_increment to 150 and you give the {z:.3f} that would be the same as the original file. It still has a z value and it increments as was the case in regular gcode.

        gcode_writer_dict = {
            "scale": (-0.1, -0.1),
            "pattern_start": "(STITCH_COUNT: {stitch_total})\n"
            "(THREAD_COUNT: {color_change_count})\n"
            "(EXTENTS_LEFT: {extents_left:.3f})\n"
            "(EXTENTS_TOP: {extends_top:.3f})\n"
            "(EXTENTS_RIGHT: {extends_right:.3f})\n"
            "(EXTENTS_BOTTOM: {extends_bottom:.3f})\n"
            "(EXTENTS_WIDTH: {extends_width:.3f})\n"
            "(EXTENTS_HEIGHT: {extends_height:.3f})\n"
            "(COMMAND_STITCH: {stitch_count})\n"
            "(COMMAND_COLOR_CHANGE: {color_change_count})\n"
            "(COMMAND_TRIM: {trim_count})\n"
            "(COMMAND_STOP: {stop_count})\n"
            "(COMMAND_END: {end_count})\n",
            "metadata_entry": "({metadata_key}: {metadata_value})\n",
            "thread_entry": "(Thread{thread_index}: {thread_color} {thread_description} {thread_brand} {thread_catalog_number})\n",
            "stitch": "G00 X{x:.3f} Y{y:.3f}\nG00 Z{z:.1f}\n",
            "color_change": "M00\n",
            "stop": "M00\n",
            "end": "M30\n",
        }

This dictionary gives the same output as the original gcode writer, in fact, there's a test in pyembroidery that makes sure that's the case. Exporting both files and making sure the files are identical. So yes, you can output the same z-like code for both.

Ams-Laser commented 2 years ago

Rather than switch from G91 and G90 back and forth you could stay in G91 and use dx and dy for the values there.

"stitch": "G01 X{dx:.3f} Y{dy:.3f}\nZ150\n",

So long as during the startup routine you set G91 rather than G90 that should be fine. Note inside the {} format brackets the code there uses dx and dy rather than x and y which provides the difference in x from the previous location.

this will definitivetly work better, tought there was not an incremental mode

going to test and get back,

thanks Ed

Ams-Laser commented 2 years ago

Worked like a charm !!!!!

sorry for my poor python knoledge if i understood correctly, adding the following lines to the tog.py

        "pattern_start": "(STITCH_COUNT: {stitch_total})\n"
        "(THREAD_COUNT: {color_change_count})\n"
        "(EXTENTS_LEFT: {extents_left:.3f})\n"
        "(EXTENTS_TOP: {extends_top:.3f})\n"
        "(EXTENTS_RIGHT: {extends_right:.3f})\n"
        "(EXTENTS_BOTTOM: {extends_bottom:.3f})\n"
        "(EXTENTS_WIDTH: {extends_width:.3f})\n"
        "(EXTENTS_HEIGHT: {extends_height:.3f})\n"
        "(COMMAND_STITCH: {stitch_count})\n"
        "(COMMAND_COLOR_CHANGE: {color_change_count})\n"
        "(COMMAND_TRIM: {trim_count})\n"

this will make the file have the file information written to it ?

i tried but just didnt change any output on the file

mabe the sintax is not right ?

Thanks

Ed.

tatarize commented 2 years ago

The syntax there defines "pattern_start" and when you put strings next to each other like that, they append. The \n is a normal carriage return. You can add in G90 at the end there or just replace pattern_start with that. Also, GRBL might prefer comments with ;. So ;bounds {extents_left:.3f}, {extents_top:.3f}, {extents_right:.3f}, {extents_bottom:.3f} might be preferred for the comment there.

That specific line sets a "pattern_start" which will be written at the start of the pattern, so you can give statistics, or set G90 as a value or anything else you need.

You don't need to be a pythonista just understand a bit how dictionaries and format strings are formatted. All the writer is doing is applying the different parts of the writer output and formatting them with the strings you give it for that format part. All you should need it to make a valid dictionary.

In theory adding that to the file would change thing unless something else also defines pattern_start and just got it overwritten. If that's the case you need to append those lines in the order you need them in.

Ams-Laser commented 2 years ago

The syntax there defines "pattern_start" and when you put strings next to each other like that, they append. The \n is a normal carriage return. You can add in G90 at the end there or just replace pattern_start with that. Also, GRBL might prefer comments with ;. So ;bounds {extents_left:.3f}, {extents_top:.3f}, {extents_right:.3f}, {extents_bottom:.3f} might be preferred for the comment there.

cant get it to work, looks like there is somewhere within the python moduler a file that should contain all the usable variables i can call within the tog.py script, if this is the case could you point me in the direction,

and mabe a sample on how to get output to the file like for the total ammount of stitches the variable might be {stitch_total} but i dont know where within the tog.py put it or how to format it

Thanks Ed

tatarize commented 2 years ago

Part of the issue is likely something you're doing is stripping tabs. In python, unlike most languages removing the blank spaces and tabs makes it unable to be executed. The posted script I placed above is formatted correctly. Most of python is written in an IDE so it's pretty easy to tell that all the tabs line up correctly. But, that's the most likely what's happening. You can use backticks (key just to the left of 1-key on most keyboards. Use three of them '''python then between that and the ending one with the ''' on the other side you can put formatted text. I could probably reformat what you're trying for you and put it into a zipped py file.

Here's a couple more examples: tog-scripts.zip

The zabs does the absolute value with z set to 150. Note the first line in the dictionary defining the writer sets the z value. And zrel does the relative value. Though there might be an issue if some stitch was missing. I would think it would be fine but it might need to add in a jump command to make sure those get processed.

Ams-Laser commented 2 years ago

Hello for the trim command code can i use : "TRIM": "M105 G4P100 M106n\n",

is that statement correct ?

thanks Ed

tatarize commented 2 years ago

"trim": The key should be lower case. And if you're covering trim you might also want to cover jump.

Ams-Laser commented 2 years ago

"trim": The key should be lower case. And if you're covering trim you might also want to cover jump.

Finally i was able to add something and worked LoL.

Thanks we now have gcode its time to do some real live testing

Thanks again Ed

tatarize commented 2 years ago

You are quite welcome. Thanks for pushing me to finish up that feature. I'm sure there are other hobbyist implementations of other formats where this same feature set will come in handy.

Ams-Laser commented 2 years ago

i will even try to make the python script to stream the output to GRBL, (if i manage to learn a bit these days)

Thanks Again Ed

tatarize commented 2 years ago

For that you need pyserial since that's the go to serial library. Connect to the serial port and then do character counting protocol (typically, unless it's going so slow it won't matter) to queue and send the code to the device.

I'd be surprised if the basic usecase isn't covered, e.g.: https://onehossshay.wordpress.com/2011/08/26/grbl-a-simple-python-interface/

Ams-Laser commented 2 years ago

what i need is to stream line by line but keep track on what line im at is a "FEED HOLD" is triggered by hardware then the tread broke send a soft reset use 2 inputs as back and fwd to scroll back and fort on the gcode coordenates moves (without sending Z commands) then send the stitch comand and continue

(this is why i dont use the absolute mode, its easyer to resume)

Ed

Ams-Laser commented 2 years ago

https://user-images.githubusercontent.com/87819514/166128563-19287989-c8bb-4dfd-83f4-5295de9cec43.mp4

First "dry" test, (NO Z)

thanks Ed

tatarize commented 2 years ago

My guess was changing the core board control circuits for a fancier thing surrounded with a big otherwise-dead industrial embroidery machine. Seems like you could totally swap that in there. In fact, it wouldn't be too hard to give it some of the most advanced UI around, thought that's likely outside your expertise of minor editing of the python code, it seems like you could stream basically any embroidery to the machine pretty much right away. A lot of the computers that embroidery machines have are very weakly established screens with very little in the UI.

Ams-Laser commented 2 years ago

Im looking into hiring at Frelancer.com to do some sort of gui for me, (unless youre interested in creating Pyembroidery-GUI) a raspbery py touchscreen and aduino mega would make a bad ass embroidery hardware engine, im willin to do some minor funding if needed

Ed

Ams-Laser commented 2 years ago

New stone in the road, is it posible to "split" a file ? like a setting for "MAX STITCHES=30,000" and output be "file_1.gcode file_2.gcode" thanks Ed

tatarize commented 2 years ago

I'm probably a lot too swamped with other things to do such a thing, there is a very minor pyembroidery-gui which is embroidepy and I'm planning on doing a much more advanced one but those are not towards the top of the stack of things I'm actively working on. And they are more towards the idea of actually making embroidery yourself than they are related to the idea of processing and executing embroidery over a serial connection. I assume it's mostly embroidery folders selecting the embroidery looking at a preview and then converting that embroidery to gcode and then sending the gcode over pyserial to the grbl device.


Currently it's not possible to split a file, but this seem reasonable. Did you need to do divide the pattern or are you just dividing up the gcode file? If you divided the pattern it would matter for the color/thread order since you would get different threads for different needles rather than planning out needle reuse only at the end. You'd need to map colors to colorblocks and divide the pattern and figure out which are the correct colors for the each part of the pattern. Though your code is using set_needle rather than color_change so it would still have the same effect, but in code you'd set needle 4 and that would be color 1 in the threadset. Though I think here you're actually just wanting shorter gcode files without needing to do anything weird or putting in stops, end of document, or anything for the transition? Would this just basically be writing the 30000 to one file then moving to the next file? Or so you have anything more related to the actual code in mind?

Ams-Laser commented 2 years ago

i have one old embroidery machine that can only handle 10,000 stitches if i could split the DST file to a liitle less tahn that and have a second DST file where i can continue it will make that machine more usable, I was thinking on just spliiting the DST file a 50 or 100 stithes before the "split size"

appending at the end of a file : "split stitch code" wich can be a set of "go back and forth the last 3 stitches" (to lock the tread), "do a tread cut", "jump to 0,0" (returning to origin, but mabe not needed),

appending to the start of a continuation file: "continue stitching code" like "move to next stitch position," stitch 3 stitches, stitch same 3 sttitches backwards (tread locking again)" and continue the file

I guess there would bee the need to copy the initial setup from the original file (treads, metadata, etc) but machine would be able to continue normally since needle 2 still be needle 2 on the 2nd part, am i right?

as for the Gcode split it would be most the same, add "split code (i wouldnt kno how to use the last 3 stitches to send them in reverse order)"then a new file copy the machine state setup from the 1st part of the file add the continue stitching code, and continue on

Thanks for pointing to that GUI, even as simple as it is it has the most dificult part (preview) the rest is a matter of spiting the gcode out the serial port (still hard for me, but it should be easyer than doing the preview, LoL)

Thanks again Ed