vlachoudis / bCNC

GRBL CNC command sender, autoleveler and g-code editor
GNU General Public License v2.0
1.56k stars 532 forks source link

Laser plugin: issue with isInside() function #1172

Open juankygali opened 5 years ago

juankygali commented 5 years ago

Hi, I'm trying to develop a plugin to process gcode in a specific way so that my machine can "print" PCB's moving in horizontal lines. The behaviour of the machine will be: etching when it is inside paths (traces of the pcb).

My idea is to detect points inside paths to decide if we have to etch or not. By processing a map of virtual points located along the the board, it would generate the gcode to do all the horizontal passes. It's similar to the pyrograph plugin but starting from a gcode file, not a image file.

The results I got were the following: result 1 path In this test I saw the plugin was working, although it spent a lot of time. I moves with G1 command inside path (continuous lines were drawn, not accurately but it is a matter of giving higher value to the resolution parameter)

Testing a file with a lot of paths: screenshot from 2019-02-26 08-21-47 The time consumed in processing was much... It didn't work because the plugin failed when detecting inside paths (no G1 command was generated inside paths, the function isInside() was returning false).

I put the part of code I was using to do the detection:

for y in range(0,n_steps_y):
            bool_row=[]
            for x in range(0,n_steps_x):
                for bid in app.editor.getSelectedBlocks():
                    for path in app.gcode.toPath(bid):
                                               #here I evaluate if the point is inside
                                    result = path.isInside(points_matrix[y][x])
                        if result: #if it is true, it is inside path, I save the value in a position of the row
                            bool_row.append(True)
                            break
                        else: #if it is not inside it will be a false
                            bool_row.append(False)
            bool_matrix.append(bool_row) #I save the row in a matrix

Not sure if I'm using correctly the function isInside()

I hope you can help me. I would leave the hole code if it was needed. Please ask me if something is not clear.

Thanks a lot!!

sfinexer commented 5 years ago

@juankygali, Why use a zigzag and not a snake? Can your plugin draw inside/outside the outline of an image (Inkscape)? I need to vyzhech inside the outline of the image obtained by the program Inkscape.

juankygali commented 5 years ago

Hi @sfinexer. Yes I would like to improve the code to do a "snake" movement, but by the time it was just a test. The plugin is now coded to "draw" inside the outline, but it will be easy to change to the opposite (draw outside).

However, it spents a lot of time to process... I'm not sure if I'm approaching it well.

Sorry but I don't understand what you mean with "vyzhech" 😅

sfinexer commented 5 years ago

@juankygali translation )) burn/pyrography.

I think this is a very useful plugin. Can you make a patch?

Harvie commented 5 years ago

Duplicate of #933

juankygali commented 5 years ago

@juankygali translation )) burn/pyrography.

@sfinexer Ok, I understand, so you need to do almost the same process as me. But are you obtaining the gcode file from Inkscape? Maybe Inkscape can make the process I'm trying to get... Just wondering. My purpose with this is to get the gcode directly from Eagle and then process it in bCNC.

I think this is a very useful plugin. Can you make a patch?

I will upload the python file to this thread, but before I would like to clean up the code and maybe modifying to make the "snake" motion.

MARIOBASZ commented 5 years ago

using intersection you can get it to make the horizontal layout only within the routes and not waste time in horizontal layout without burning. It takes a long time to process (I do not know if it can be done faster in some way). intersection works on gcode. Then you have to burn the shape of the tracks. (I have uploaded at some point something similar - even in development - for PCB with 2 cutters of different diameter). However, is not it convenient to simply use a pocket operation?

juankygali commented 5 years ago

Hi @MARIOBASZ and thanks for your support.

First, I saw that intersection function was the way to do this, but then I realized that isInside function was already using it... So would not be the same?

About using pocket operation, I tried it but I wasn't able to get anything because it crashes. Maybe I'm doing something wrong.

pocket

Sorry for my ignorance, but my knowledge in this topic is limited.

Un saludo.

Harvie commented 5 years ago

@juankygali I've aready given you link to #933. There is some bug in intersection, which affects isinside in some cases. I would be more than happy if you could help me figure out what is going on, since islands and therefore tabs are dependent on this code.

BTW do you use latest git master? There are some checks regarding this code that were not released yet.

juankygali commented 5 years ago

Thanks for your reply @Harvie.

Yes I took a look to #933 and realized that there are some changes in the code that I don't have in the git master. I will try to understand what is done, testing it and hoping to figure out something interesting.

Regards.

MARIOBASZ commented 5 years ago

I hope you find the inconvenience of inside! Pocket crashes if there is no space to generate it inside, instead of generating nothing. If someone can modify this, it would be a help. However Profile In behaves correctly. A solution that occurs to me, (ok is rudimentary) is: make profile In, if a route is generated, make a pocket, if not continue

juankygali commented 5 years ago

Ahhh ok @MARIOBASZ, I see your point. Well, in my case the purpose is moving in horizontal lines although I didn't need to burn in some areas. That's because the PCB will have a lot of traces and I think it will be more time consuming to pass only inside paths one by one than passing line by line along the whole board. Just a matter of traveled distance.

juankygali commented 5 years ago

@sfinexer I made the plugin able to use a snake motion to generate the gcode

snake

snake2

I attach the file of the plugin if you want to try something... At least it worked for 1 path designs.

pyrograph_copy.zip

MARIOBASZ commented 5 years ago

I think the problem with Inside is in the boundary line, if the two traces match to intersect

MARIOBASZ commented 5 years ago

@juankygail, I'll look at your code when I can, I'm curious to see it. This is what I generate with dif (I do not remember if it is with any modification), I will see if it can be generated inverted (that generates the route inside)

image

juankygali commented 5 years ago

It's a quite interesting result @MARIOBASZ. How do you get that? I'm trying but without result.

First I think you island the traces, then you generate the line pattern (with some plugin) and finally make the difference between both... Right? If you could explain me it would be great

MARIOBASZ commented 5 years ago

@juankygail, 1- I open the traces of pcb (I use PCB Gcode). I mark them as islands with "Island" 2- In your case, is to generate the horizonales roads with Plugin Flaten Pocket type Raster 3- It should work ... but I just noticed: if the lines coincide, it seems that it does not generate the route (I should check how to solve this problem)

MARIOBASZ commented 5 years ago

Changing eulerize by split2contourn prevents the program from being blocked. ((Lines 79 and 80)

paths_newbase.extend (newbase.eulerize ())

paths_newbase.extend (newbase.split2contours ()

juankygali commented 5 years ago

@MARIOBASZ I've been following the steps you explained and the result is interesting. Maybe it is far from solving my issue, but I think it's a good method.

Using difference, I got the following: difference

Using intersection (the closest result to my application) I got this: intersect

It works but only takes 1 path, don't know why for the moment

Changing eulerize by split2contourn prevents the program from being blocked. ((Lines 79 and 80)

paths_newbase.extend (newbase.eulerize ())

paths_newbase.extend (newbase.split2contours ()

Not sure about what these two functions are doing, but as you said I see that in some point eulerize crashed... I changed it for split2contours and seemed to work.

MARIOBASZ commented 5 years ago

If I remember correctly, intersection was thought for only two objects. must continue evaluating the rest of the selected blocks. Are you a programmer? I'm not in my machine to send what I modified (I think some error is sometimes generated, maybe the same problem of overlapping lines?) I do not programmer maybe you can help me automate tasks: I have made a variant to convert objects to solids, it works good for two or more objects if they all "intersect". If object A intersects B, C intersects D and D intersects B and E, it does not connect all the figures, a solid AB is generated, and another CDE. I lack the time (and enthusiasm) to continue polishing this. Using difference, intersection and solid connection, more profile IN, profile ON, in successive operations, I can mill PCB tracks with 2 different diameter cutters much faster. The same goes for a poster or logo, but many successive operations manually, and I have not yet been able to automate them and work as a plugin. Could you help me? I have asked for help in a PCB isue but I have not received an answer, and it is frustrating. Two things would be very important to solve: Problem of superposition of the limits lines, and that pocket does not lock if there is no space (although for what I have written, I use profile out and then pocket to deceive him) #1037 #988

MARIOBASZ commented 5 years ago

Be careful with this problem: #1175

juankygali commented 5 years ago

I was reading the issues referenced, I see that you are trying to do something similar to me.

My programming knowledge is very poor, I barely understand the code and I need a lot of time to develop something useful... But I tried to make the plugin because I wasn't able to make the machine behave as I wanted (moving in horizontal lines, burning inside) with any plugin or a mix of them.

So, some questions are in my mind about your purposes: -Why do you need to make unions of objects? Aren't you starting from a file with the whole PCB? -Milling with 2 different cutters, in what cases?

Harvie commented 5 years ago

Eulerize() is work in progress experimental feature, that i created because i didn't knew that i can use split2contours... I think i will remove it altogether if it turns out that split2contours() does the same thing.

juankygali commented 5 years ago

I solved a mistake that I was doing in the code. Now the plugin is able to process every path.

yeeeeeees It spent 1 second, because the file is so simple.

For a more complex file: yeeees The resolution parameter was set to 10 (10 points per horizontal line) and the time consumed about 3 minutes. Obviously we will need to put a higher value of resolution, and wait more than 3 minutes :')

The error was that the boolean values that isInside() returns were not saved correctly, overwritting themselves. Stupid error that I commited.

juankygali commented 5 years ago

Updated plugin pyrograph_copy_2.zip

MARIOBASZ commented 5 years ago

I have never used laser or the pirograph plugin, have you solved the problem when there are coincidences between lines to intersect? Have you tried doing a "join" of all the tracks and then intesection? A temporary solution, not clean for your use, is that either the traces or the route to be subtracted, are converted from straight lines to "advance in sawing or zigzag of 0.0001mm" (I think something similar to how arcfit should work or linearize, or to generate trochoidal style). I obviously prefer a satisfactory solution to the intersection problem when segments are superimposed. The drawback is the slowness: minutes or maybe hours depending on the complex ....

MARIOBASZ commented 5 years ago

Milling with 2 strawberries, 0.10 + 0.70 if I want that in most places the separation between tracks is that (I have skills to generate short circuits when welding in small separations). Or make a poster with letters, and the angles are more pronounced instead of so rounded: 2 problems that are generated with the 0.7: In the angles is one. Where it invades another track or adjacent letter. (Gcode solves this for tracks by making a trace for 0.1 and another for 0.7, but there are critical areas where you can maybe rough out 0.5mm) For a poster, I do not know An operation that is roughing + termination, that is, two tools, may be convenient at times. Solid Union has served me for this, and also to generate some routes joining two figures without needing to make calculations saving time.

juankygali commented 5 years ago

I have never used laser or the pirograph plugin, have you solved the problem when there are coincidences between lines to intersect?

For the moment, I only tested with paths that don't intersect. That's because the pcb I'm loading in bCNC are not going to have paths intersecting. However, I will test it.

Have you tried doing a "join" of all the tracks and then intesection?

Yes I tried, following your steps. Difference worked well but the result generated is the opposite to what I need. With intersection something was failing, it just took one path. I joined the blocks as you say but the result was the same... Maybe it needs to be tested more.

About the purpose of using 2 tools to mill, I believe I'm getting the idea: with the biggest you mill internal areas, with the other you profile the shapes, right? It seems a more complex gcode to generate automatically. As you see, my "method" is a bit rudimentary but quite simple. In addition, won't pocketting the shapes take longer to mill than milling in horizontal lines? In fact I don't know about milling and maybe it is not the ideal way to proceed, but I pose the situation.

MARIOBASZ commented 5 years ago

If you want to send me and i test your pcb with my intersection, if you tell me what diameter to set for the raster. (Processing takes a long time, I do not know if it's the responsibility of python, bcnc or my computer)

juankygali commented 5 years ago

The time consumed depends mostly on the code I think... Although I observed that only 1 core of the CPU was working when processing. I'm not sure if it depends on bCNC or the OS (I use Ubuntu) image

In my main computer, the processing is taking less time because the power of the CPU. However my final purpose is to have it working on a Raspberry.

I tested my plugin with a real PCB, real toolsize/resolution and result with is this: image It took 42 minutes...

Conclusion: it takes so much time altough seems to detect inside correctly.

If you want to try, the diameter of my laser is about 0.2mm. I'm using a random design from Eagle, exported to gcode with pcb-gcode ulp. Then I load it in bCNC. I leave the PCB I was using to test:

pruebas nRF52832_MCU.top.etch.ngc.zip

Harvie commented 5 years ago

Updated plugin pyrograph_copy_2.zip

Why don't you use git? Just fork bCNC, use git to clone it from github to your pc, do changes and use git to commit+push them back to github...

juankygali commented 5 years ago

Sorry @Harvie but I'm not used to github, I will do what you say next time.

By the way, do you know why bCNC uses only 1 core when processing? I don't know about parallel computing or process management of OS but I'm curious to know why.

Harvie commented 5 years ago

do you know why bCNC uses only 1 core when processing?

Parallel processing is not something that magicaly happens by itself... Software author has to carefuly separate the job into multiple streams, execute new threads to handle them, while taking care that these threads are not acessing same memory regions at the same time (and therefore creating conflicts) and then combine the outcomes of all threads back to single meaningful result.

I am not very experienced with python performance tuning, but it seems to me that it's very slow language. Especialy when iterating over large arrays. That's why we use "numpy" library for some of the bulk calculations, it calls code written in C to achieve this stuff 1000x faster (i am using this when preprocessing 3D meshes for slicing in bCNC). But not everything can be solved by numpy library.

juankygali commented 5 years ago

Ok @Harvie so the slow process is caused generally by the coding in python. Well, interesting issue but difficult to handle...

MARIOBASZ commented 5 years ago

@juankygali, if in the picture the continuous lines are laser burning G1 and the dotted laser off G0, it seems to be burning also off the tracks I do not understand the reason why the intersection in this case generates only in the first block analyzed (in general it works for me, but sometimes I have to do some manual correction) instead of all the blocks. Good news at least for your use !: If you modify difference to intersect (if island.isInside)   and you choose the Raster as an island (in my case I have tried it with an outer rectangle pocket) the result should give this: image

image

Better still than I imagined, imagine that there would be external traces with setores without defining alternatively

@Hervie, if you manage to make this work fast, (I did not know what you wrote about the PC's core, juankygali, where are you from?) it would be great: To be able to use two milling cutters, roughing and finishing, whether for pcb, logo, poster, molds and die-casting in aluminum, etc.) would be really good! Hugs to both

MARIOBASZ commented 5 years ago

correction image

juankygali commented 5 years ago

@MARIOBASZ this seems to be really great. Can you specify better the steps to follow? I'm not getting it.

I selected the pattern as an island, and then? I'm a bit lost image

Ok, I got the first path: image

MARIOBASZ commented 5 years ago

Okay. 1- Mark the pattern (as you name it) as an island: this action compares this block (island) with all the other selected blocks (not islands) 2-Select all the blocks to evaluate: pcb tracks and pattern 3- click on modified dif for intersection 4-You can eat quietly, go for a bike ride, have a romantic date, or look like a fool the monitor (usually my option ...) 5-Maybe it could be automated:  1-Open .etch.tap generated from pcbgde 2- Option 1: Import .mill.tap also generated from pcbgcode Option 2: Surely you can modify flatten so that you take the measurements of .mill Option 3: Generate the box by the limits of area to be machined (as it does limits for scanning) plus an offset to choose, and generate the pattern with flatten + raster, or, you can make a pocket type raster for a non-rectangular shape ? It would be nice to flatten the option to generate vertical or horizontal. 3-The name of the generated burn_pattern block could have a name as not burn_pattern (optionally name plus island mark) 5-Run selects all blocks. (or the option to select only those selected). Compare the burn_pattern block with those that are not called burn_pattern (or with those that are not islands) 6-Go for a bike ride, have a romantic date, eat, or watch the monitor like a fool (I usually choose one of these last two options ...) 7-BCNC should have done the job. Otherwise, go back to point 6 8-If @Harvie uses his knowledge, and manages to make this run faster, there may be fewer romantic dates and people walking on bicycles Harvie, thanks again for your contributions! Barcelona has Messi, you and Vlachoudis are ours (I consider myself a stubborn Frederick "Fred" Flintstone) Hughs Note: This plugin that is the work of Harvie, name us thanks our concerns

juankygali commented 5 years ago

OMG, amazing explanation!

But I don't understand what you are modifying in diff

3- click on modified dif for intersection

If you modify difference to intersect (if island.isInside)

Is it somewhere in the code?

juankygali commented 5 years ago

Sorry sorry... I got it image

Modifying the code will add segments from INSIDE of the islands instead of outside: Changing this: image To this: image

Good discovery @MARIOBASZ xDD

juankygali commented 5 years ago

5-Maybe it could be automated:

@MARIOBASZ I would like to check the diff code, to see if it can be adapted for our purpose. I hope to have some time these days, let's see if I can do something to make things more automatic... Let's see

MARIOBASZ commented 5 years ago

curiosity: burn inside, leave your pcb "painted" and then with acid remove the copper without puncturing?

juankygali commented 5 years ago

Burning inside would be for a negative photorresist board: the area exposed to light is protected against the acid, so the copper remains.

The easiest way to make a pcb will be using positive photorresist boards: what you burn with laser is what will be removed with the acid. It is more similar to milling with a tool. Like this:

pad_m4_s100_v500 pad_m4_s150_v500

Harvie commented 5 years ago

@juankygali Nice!

BTW I saw interresting cheap method to do PCBs using laser. Use cheap black spray paint (different brands may give different results) to cover the board, let it dry and use laser to burn away the paint in places where you want to etch. Then wash the board with soap and water, only burned paint will be removed. If your laser is powerfull enough to burn black paint, you don't need to pay for actual photoresist.

Another method might be done by preparing sludge of alcohol and printer toner. You then cover the board with it and leave the alcohol to evaporate. Once dry, you can use laser to selectively sinter the toner to the board.

In both cases you can then etch the board as usual...

juankygali commented 5 years ago

@Harvie Interesting method, I did'n know that. Maybe my laser is not powerful enough (it is 1W) to burn the paint but I have to try.

The second method will be equivalent to the negative photorresist (right?), but first I will need to generate a gcode file with the passes in horizontal/vertical direction as I was thinking for the plugin. Once generated, I will have to make a pcb to test because I haven't tried yet, and see if it works as well as I want

MARIOBASZ commented 5 years ago

@Harvie, I know you are solving many questions, can you run these plugin faster (1 core - many cores)? Another problem is that the display becomes very slow and bcnc if there are many lines

juankygali commented 5 years ago

@MARIOBASZ I made something interesting with the modified difference plugin:

difference

The gcode is generated to burn inside in horizontal lines, but instead of using my method of giving the plugin a "resolution" parameter to generate points, compare if they were inside, etc, etc... I'm using intersectPath that gives us the points where island and paths are intersecting. Then, sorting these points the gcode is easy to write.

The best of all is that it seems to work faster, for example this file took few seconds: image

image

Now, I would like to improve the plugin to make the "snake motion" to avoid wasting time going from one side to the other. I also want to generate the island automatically according to the number of lines (horizontal passes) we need. And finally, the option to generate the same thing but with vertical lines.

Are you thinking in something more that can be implemented in the plugin? Let me know to see if I can do something.

MARIOBASZ commented 5 years ago

Great if this works in seconds !! Maybe you find a solution to problem # 1175? In the images would seem to burn inside and outside (helps visualize if it stops showing G0 movements), or am I wrong?

MARIOBASZ commented 5 years ago

When you generate the block, you can make it generate with name and comment "island", or you can generate the burnt block pattern with name burnedPattern to compare. Snake movement is what you call what raster flatten generates? It would be good to choose vertical or horizontal snake movement

juankygali commented 5 years ago

Maybe you find a solution to problem # 1175?

I don't think so, because the problem with coincident segments seems to depend on the the function intersectPath, or the application of it inside the difference plugin. I saw that intersectPath was returning the same intersection point more than once. And maybe it is creating some confusion...

In the images would seem to burn inside and outside (helps visualize if it stops showing G0 movements), or am I wrong?

It is burning only inside, G0 movement is written outside paths.

Snake movement is what you call what raster flatten generates? It would be good to choose vertical or horizontal snake movement

Yes, pattern=raster flatten. I will update as soon as I have advances.

juankygali commented 5 years ago

I managed to automate the generation of the snake pattern according to the tip tool size, and also taking the pattern as island and intersecting with the paths.

With a tip tool size of 0.2mm it took only 15-20 seconds. image image