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

Help needed, color change macros #142

Open
Ams-Laser opened this issue Apr 18, 2022 · 63 comments
Open

Help needed, color change macros #142

Ams-Laser opened this issue Apr 18, 2022 · 63 comments
Assignees

Comments

@Ams-Laser
Copy link

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Author

@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
Copy link
Author

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
Copy link
Author

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

@tatarize
Copy link
Contributor

tatarize commented Apr 20, 2022

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
Copy link
Author

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
Copy link
Author

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
Copy link
Author

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

@Ams-Laser
Copy link
Author

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

Thanks

@tatarize
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Author

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
Copy link
Contributor

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
Copy link
Author

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Author

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

Thanks
Edward

@Ams-Laser
Copy link
Author

Ams-Laser commented Apr 26, 2022

@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
Copy link
Author

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
Copy link
Contributor

"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
Copy link
Author

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
Copy link
Contributor

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
Copy link
Author

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
Copy link
Contributor

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
Copy link
Author

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

is that statement correct ?

thanks
Ed

@tatarize
Copy link
Contributor

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

@Ams-Laser
Copy link
Author

"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
Copy link
Contributor

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
Copy link
Author

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
Copy link
Contributor

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
Copy link
Author

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
Copy link
Author

test.noz.mp4

First "dry" test, (NO Z)

thanks
Ed

@tatarize
Copy link
Contributor

tatarize commented May 1, 2022

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
Copy link
Author

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
Copy link
Author

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
Copy link
Contributor

tatarize commented May 4, 2022

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
Copy link
Author

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

@Ams-Laser
Copy link
Author

Hello,
started working on the main project
479f0384-b81e-49fb-83cf-84cbf290ec3d

Thanks for the help
Ed

@tatarize
Copy link
Contributor

tatarize commented May 8, 2022

There is officially a method of splitting the DST files into multiple files but I never saw examples of it done. There's some code in the header for the previous start location of the last file or something but I'm not sure it does much of anything. I would think the machine would just follow the commands directly and if the file didn't say to return to a home position it should actually remain where the last file started off. In theory for DST files you could just span it between multiple files stopping at literally any point. At least I would think that would be the rule. A lot of machines shouldn't really cut the thread if they aren't told to, but it would differ based on the machine.

If your doing the gcode I don't see why it would need to split at all but you could just slice the code at any new line position and it should work perfectly fine. If you need only a general preview you can also output the embroidery file to a png file and it will write that directly into a working png file, which would work fine as a preview. I think there's some info for setting a guide in the png as well. So if you have a bunch of files you could use pyembroidery to simply convert all the files in the directory into png files so you'd have previews of them all.

Yeah, I could certainly see sourcing the original stuff for a USD$100K - 7 head machine could absolutely be an uphill battle. And the controller stuff could basically be done with fairly cheap gcode controller card so long as you could convert from traditional embroidery formats into gcode.

There are a few worthwhile features you might actually need from the controller software you set up, which are a bit heftier than just convert from one format to another format. For example, you need to make sure your design is within the hoop. This often involves jogging the embroidery machine a bit then holding down the needle to see that the needle will not strike the hoop. This is typically done in quick and hull fashion. In the first it does a solid rectangle outline of the loaded design, in the latter it does the convex hull of the design (think rubber band path around all the needle points). It should also deal with the thread breaking or running out of bobbin or thread. Modernly this amount of computing does not exceed a Raspberry Pi worth of power, but do need to pick up on the signal, and it might be nice to set this up with a touch screen or so.

The serial port gcode stuff shouldn't be that hard. It's mostly invoking pyserial to set up the connection from whatever os/computer setup you have. Since the intefacing code you're using is GRBL the regular stuff shouldn't be too difficult. Though if you don't have python experience I could see it being a bit hard.

@Ams-Laser
Copy link
Author

Hello,just to show you the updates on working on my new embroidery machine, im building one from scratch before modifing the big brother one
instalacion de soporte y guias lineales Y

demo.programa.bordado.1.mp4
demo.envio.de.datos.CNC.Bordadora.AMS.mp4

Software done in Python, using your library for the conversion and image generation

Thanks!!!!!!

@tatarize
Copy link
Contributor

Looks pretty nice. The file transfer stuff isn't too hard to do in python either but if it's just sending the gcode over to the card, there should be a lot of things that do that equally well.

@Ams-Laser
Copy link
Author

hello, just come back from other stuff i had to work on and letting you know how it goes, i manage to make my GRBL compatible sender based on your converter, here is a video of it working

WhatsApp.Video.2023-03-10.at.6.40.15.PM.mp4

now i need a sewin machine tecnitian to fix my machine timing , once done i will get back with a video showing the actual treaded stitches

Thanks a lot for the help

@tatarize
Copy link
Contributor

This is a really impressive project. That may be the best DIY embroidery I've seen. I had talked it over with my brother who knows a lot of solid stuff on industrial embroidery machines and it seems like a lot of grbl cards will have a lot of the stuff you need. You could even probably hook up the door alarm to the thread break and have the machine stop when that's triggered. Etc. It's a really good idea.

@Ams-Laser
Copy link
Author

@tatarize Hello, i have found one little issue on the DST2Gcode converter script

this part of the code

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}", "(PAUSE)\n"),
    # Overrides cmd_needle==0 value.
    "0": "(NEEDLE_00)\n",
    # Overrides cmd_needle==1 value.
    "1": "(NEEDLE_01)\n",
    # Overrides cmd_needle==2 value.
    "2": "(NEEDLE_02)\n",
    # Overrides cmd_needle==3 value.
    "3": "(NEEDLE_03)\n",
    # Overrides cmd_needle==4 value.
    "4": "(NEEDLE_04)\n",
    # Overrides cmd_needle==5 value.
    "5": "(NEEDLE_05)\n",
    # Overrides cmd_needle==6 value.
    "6": "(NEEDLE_06)\n",
    # Overrides cmd_needle==7 value.
    "7": "(NEEDLE_07)\n",
    # Overrides cmd_needle==8 value.
    "8": "(NEEDLE_08)\n",
    # Overrides cmd_needle==9 value.
    "9": "(NEEDLE_09)\n",
    # Overrides cmd_needle==10 value.
    "10": "(NEEDLE_10)\n",
    # Overrides cmd_needle==11 value.
    "11": "(NEEDLE_11)\n",
    # Overrides cmd_needle==12 value.
    "12": "(NEEDLE_12)\n",

generates this output

(NEEDLE_01)
G01 X-6.700 Y4.200
(STITCH)
G01 X0.000 Y-1.000
(STITCH)
G01 X0.000 Y-1.000
(STITCH)

the problem is
this "G01 X-6.700 Y4.200" this coordenate is still a positionig coordenate and should not get stitched

is there a way to get this output instead:

G00 X-6.700 Y4.200
(NEEDLE_01)
(START)
G01 X0.000 Y-1.000
(STITCH)
G01 X0.000 Y-1.000
(STITCH)

this way the material positions where the actual stitch begins
and then the needle_01 macro takes place
then we start stitching
next the actual stitches

attached the py file that i use for conversion, the DST and the fixed file

hope you can help
Thanks
Ed.

AMSGCODE.py.txt
cuadros.dst.txt
sigzag.gcode.fix.txt

@tatarize
Copy link
Contributor

Yeah, what you want is some of the code for the jump to the new location. Most embroidery programs call this command JUMP basically they have their sewing head sewing and it's really hard to stop so there's specialty commands that need to be reached. So rather than stitch at a location it moves to the location and waits for the stitch which tends to happen fairly quickly. If they can't make it to that location they call for JUMP which is usually a stitch but it blocks the needle bar. So it could still have sewn that but it didn't, this is also used to make really long stitches since sometimes you want a longer stitch than the device could travel in a single hit of the needle.

As such if you add the jump command in the values you'll get the G00 for those:
"jump": "G00 X{dx:.3f} Y{dy:.3f}\n",

This would, in theory add the commands for the jumps which bring you to the right position.

Or maybe you'd be better off replacing the needle-set with the G00 command:

    "needle_set": {
        # None, given a tuple of key creation value and a default value (if no key matches)
        None: ("{cmd_needle}", "(PAUSE)\n"),
        # Overrides cmd_needle==0 value.
        "0": "(NEEDLE_00)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==1 value.
        "1": "(NEEDLE_01)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==2 value.
        "2": "(NEEDLE_02)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==3 value.
        "3": "(NEEDLE_03)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==4 value.
        "4": "(NEEDLE_04)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==5 value.
        "5": "(NEEDLE_05)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==6 value.
        "6": "(NEEDLE_06)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==7 value.
        "7": "(NEEDLE_07)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==8 value.
        "8": "(NEEDLE_08)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==9 value.
        "9": "(NEEDLE_09)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==10 value.
        "10": "(NEEDLE_10)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==11 value.
        "11": "(NEEDLE_11)\nG00 X{dx:.3f} Y{dy:.3f}\n",
        # Overrides cmd_needle==12 value.
        "12": "(NEEDLE_12)\nG00 X{dx:.3f} Y{dy:.3f}\n",
    },

This would add the G00 X{dx} Y{dy} bits of the needle. This should actually have a lot of the position update. So the needle update would do position update at the needle change.

(COMMAND_END: 1)
(gcode part)
G21 G91
(SPEED)
(mm units, relative positioning, speed)
(NEEDLE_01)
G00 X-33.600 Y20.800
G01 X-6.700 Y4.200
(STITCH)
G01 X0.000 Y-1.000
(STITCH)

Running this change against cuadros.dst produced the above shift. Before it would only do the stitch after that.

@tatarize
Copy link
Contributor

The GenericWriter will write out the metadata then the threads. Then the segments which are individual stitch commands and their positions. As a rule, if your code provides a segment for the command then it updates the positions. If you're using entirely relative coordinates this means the Needle-Change might not provide the DX DY for it

If you're using G90 rather than G91 this wouldn't matter, but, here you would need to provide either position shifts for any commands you use, or provide the positions in absolute positioning. Without the needle commands providing the position change as well, you're left with unused dx, dy. Which could put you in the wrong positions.

@Ams-Laser
Copy link
Author

NEEDLE_00)

Hello, is there like a dictionary or manual of all the variables i can call from whithin the amsgcode.py file ?
sorry for being lazy, this might already be documented somewhere..

Thanks
Ed

@Ams-Laser
Copy link
Author

Ams-Laser commented Mar 23, 2023

@tatarize , how are you decoding a needle change from de command bits ? i can only decode the normal, jump, sequin, commands.
Thanks,
Ed

@tatarize
Copy link
Contributor

Different readers need different color-change codes, the biggest difference is needle-change tends to occur before a color block and a color-change occurs afterwards. Some formats like .U01 will use needle_change rather than color_change.

The gcode writer dictionary does this by setting the thread_change_command

    "thread_change_command": NEEDLE_SET,

The needle_set command is extended with optional dynamic values. This could be done with nearly anything if they need that kind of work.

    "needle_set": {
        # None, given a tuple of key creation value and a default value (if no key matches)
        None: ("{cmd_needle}", "(PAUSE)\n"),
        # Overrides cmd_needle==0 value.
        "0": "(NEEDLE_00)\n",

The relevant part is there's a dictionary here that defines no-key matches. This is value which also contains cmd_needed potentially and the default command if there isn't a dictionary entry that matches. So if the None value gave "cmd-{cmd_needle}" then the entries in the rest of the dict would need to be "cmd-0": "my needle switch command"

Generally the code does this by referencing the dictionary with a lookup dictionary since you can call str.format() on any text you want and then any matching "{format} text" parts will be converted to whatever was in the dictionary. So you can write a super-generic output routine.

        self.format_dictionary.update(
            {
                "index": self.command_index,
                "command": self.command,
                "cmd_str": self.cmd_str,
                "cmd": self.cmd,
                "cmd_thread": self.thread,
                "cmd_needle": self.needle,
                "cmd_order": self.order,
            }
        )

In this there's only a few useful specific things like {cmd_needle} and I'm not sure this is specifically referenced or described.

@tatarize
Copy link
Contributor

Other than that, you'd need to specify anything that is type of command. So you can rewrite segments like sequin_mode, sequin_eject, stitch, trim, jump, color_change, needle_set, stop, fast, slow, end. All of which tend to do things in many different files types. Many filetypes will lack these commands and things like"

     "write_speeds": False,

Would strop things like fast and slow which would rarely be loaded outside of perhaps .U01 format or if specifically written into the data.

@tatarize tatarize self-assigned this Mar 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants