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

laser and grbl experiments #492

Closed
alpharesearch opened this issue Sep 15, 2014 · 144 comments
Closed

laser and grbl experiments #492

alpharesearch opened this issue Sep 15, 2014 · 144 comments

Comments

@alpharesearch
Copy link
Contributor

Just like most comment here this is not an issue but I like to get some input and give some feedback.
To play around a little bit I did mount a 2W blue laser+MOSFET to my ShapeOko+grbl and it is working.
I did set it up for the variable spindle pin but didn't notice the min/max RPM settings at first (I guess I should have read all the comments). This cause some confusion because I was expecting 8 bit as default and not 0-1000.
I did notice some dwelling when changing the laser intensity, but i guess MINIMUM_JUNCTION_SPEED should help with this (what value would be a good start for laser?).
Now my main question would be are there any other important setting for laser setups to make?

@chamnit
Copy link
Member

chamnit commented Sep 15, 2014

@alpharesearch : There's a lot you'll have to change and it'll involve some coding. For one, Grbl assumes you are using a spindle that needs to come up to speed before proceeding. Hence, the dwelling when changing laser intensity. Changing minimum junction speed shouldn't have any effect. It'll always dwell.

The DarklyLabs folks making the LazerBlade have already done exactly what you are trying to do. They are using a modified version of Grbl, but it's closed-source via the MIT-license. To do something like this, you'dl basically have to the retain the spindle speed setting through the planner and to the stepper algorithm. There you'd need to update the spindle PWM on-the-fly as the planner blocks are being executed. Not very hard to implement, but not trivial either.

@alpharesearch
Copy link
Contributor Author

It is working good with the CNC settings already. This upgrade was under $100 and took only 2 hours to install and commision. It was a fun weekend project and it adds some more options to the ShapeOko.
Thanks for the tip with the LazerBlade. At least on their Kickstarter FAQ there is a statement that "hard core hackers" will be able to compile the firmware. I guess because the product is not released the firmware aka grbl is not published yet.
@chamnit : I don't want to maintain my own version and have to backport, would you accept a patch that adds this as compile time option but with option to switch between CNC and laser mode as setting? In the end I would like to be able to switch between router and laser on the fly.

@PicEngraver
Copy link

@alpharesearch: You might be interested in this thread in the Shapeoko forum.
http://www.shapeoko.com/forum/viewtopic.php?f=24&t=4203

@alpharesearch
Copy link
Contributor Author

@PicEngraver Thanks for the link! These engravings are very beautiful, it always amazes me what people do with there ShapeOko!
I guess with this method the Z axis controls the power of the laser. Would a new axis make more sense then spindle speed? Or a M command to switch between real Z axis and laser? I guess this would allow for interpolation of the laser power, I guess that is used for engravings a lot?
So far I was only testing cutting paper and a kind of "carving" in plastic and didn't put much thought into engravings gray scale pictures in to wood.
Thanks for all the input so far!

@chamnit
Copy link
Member

chamnit commented Sep 16, 2014

@PicEngraver : Very crafty! One question though. Have you observed any lag between the Z-axis moving and the intended laser power at a particular point?

@alpharesearch : I'm open to adding real-time spindle control to Grbl, but I think it's going to be more complicated than it seems. At least to do it right. Personally, I don't like adding new g-code commands that are outside the published ones. You end up with something like Marlin, where there are dozens and dozens of specialized g-codes that are hard to learn and you have to customize your programs for them. CAM programs don't know what these codes are either, so you have to hand modify them each time.

One idea is to create a Grbl $ command or setting that will control the spindle output state, either pausing for each spindle change (and maybe a delay setting) or no pausing with real-time updating of the PWM. Something like this would need to go into the next version of Grbl. I've got some ideas on how to implement it, but it'll require some refactoring of the planner and how the blocks are handled. I'll need to think about it some more though. For now, I'd probably advise just forking and writing your own implementation.

@PicEngraverToo
Copy link

@alpharesearch: Thank you! Yes, this is the on-the-fly, variable laser intensity 8bit photo engraving process I developed a couple of years ago using the MA3 magnetic shaft encoder tied to the Z axis. Using the Z axis allows me to move the laser to the correct focal point based on material height.

I started out on a CNC router using Mach3 and now testing it out on an Arduino, 9g grbl and a Shapeoko 2. Thank you Sonny for all your development efforts!

I prefer using the MA3 because it gives me 10bit resolution of the varied 0-5 analog voltage to the modulation in a 8bit Z axis depth setting. I use a Z0. to Z-.0256 setting in the PicLaser Lite or PicEngrave Pro 5 beta image to gcode program I use.

US Digital does make 10bit & 12bit PWM versions of these encoders, but I have never tried one. I feel analog is the best way to modulate the driver for the varied intensity control of the laser diode.

@chamnit: No lag that I can detect or observe. I have to be careful not to sharpen the image too much and keep the feedrate moderate (around 60IPM) so the Z axis stepper does not loose any steps. I have my accels set at 1000, mm/sec on all three axis's and the junction deviation set at .010 mm.

@alpharesearch
Copy link
Contributor Author

I have something working in the simulator, see screen shot of plot: http://alpharesearch.de/?p=259
@chamnit I followed your suggestion and added spindle information to the planner block. Now stepper prep buffer function can set the spindle. I can switch with $40=0 to what we have now and $40=1 to new laser mode. I did start adding the compile time #if statements (see example on link)... but with that part I'm not done yet.

@gerritv
Copy link

gerritv commented Sep 19, 2014

Nicely done

@chamnit
Copy link
Member

chamnit commented Sep 19, 2014

@alpharesearch : Great job! I'm glad you were able to get it running so quickly and it's looking like it's working.

A couple of things though:

  • The prep buffer function shouldn't be setting the spindle, technically. The stepper ISR should be doing this as a directly PWM timing (OCR?) register update, but there is only 50msec difference between them, so I don't think you'll really notice it in practice. I suppose I'd have to see how you implemented everything before judging. :)
  • The other thing is that the specialized #defines that change the function calls for all of the compile-time options are starting to get pretty messy. I think it'd be safe to always pass this data, spindle speed and line number, onward to the mc_line and planner functions. Instead, the defines only enable and disable the memory requirements and the code that it uses to work.

Otherwise, looking good!

@alpharesearch
Copy link
Contributor Author

I forked a image carve program from google code and did a little change to map the Z axis to S values. Here is the code: https://github.com/alpharesearch/imagetolaser and here is a screen shot from a simulation: http://alpharesearch.de/?p=267

@chamnit : Thank you. Yes, the #defines start getting big for all the mc and planner functions that pass these values around. I'm not a bit AVR guy and I don't know all the tricks to conserve memory, but if you think this will work OK that would keep the code more readable. If the values are not used should not the compiler not take care if this? I guess that is what you are hinting at?
I just used the prep buffer function as proof of concept (and I didn't find a better place) and I just called the existing spindle function for now. But I agree to move this as close as possible to the start of the block.

@PicEngraverToo
Copy link

PicLaser Lite will generate S command gcode values based on shades of an image to control the varied PWM output for lasers to engrave images. http://www.picengrave.com/PicLaser%20Lite.htm

@alpharesearch
Copy link
Contributor Author

@PicEngraverToo I use Linux... but if you could publish a stamp sized engraving g code file I would like to test it with the new firmware. Only XY movements and S0 to S255 to set the pwm. Thanks for your help.

@PicEngraverToo
Copy link

@alpharesearch: You can copy the code from here.

PicEngraverToo/grbl-S-command-gcode@3966943#diff-0

@alpharesearch
Copy link
Contributor Author

@PicEngraverToo : thanks I did test it with grbl simulator and I can see a woman with a hat. It's pretty small, was I right?

@chamnit : I moved it from the prep in ISR and I can see a big difference. However I still think there is room for improvment. But at least now I have the same result with the new fast and the old slow method. But there is still a very small offset. I will need to test this on the real microcontroller too.

@PicEngraverToo
Copy link

@alpharesearch: You are correct. The size was 12.7mm X 12.7mm with a .254mm X & Y step-over. I generated it first at 25.4mm X 25.4mm, but there was around 100,000 lines of code and I could not figure out how to attach a file. Newbie here. :-) I can generate a larger file for you to test after I figure this out.

@PicEngraverToo
Copy link

@alpharesearch: OK, here is a larger S command code for you to test. It's a little over 700,000 lines long.

http://picengrave.com/downloads/MiscDownloads/Transportation680.txt

@chamnit
Copy link
Member

chamnit commented Sep 20, 2014

@alpharesearch : Awesome. Great progress on this! :)

As for defines, I checked if the compiler ignores unused variables passed to the function. It doesn't, but at this point, I don't think saving every single byte matters as much since we'll be moving on to a more capable processor soon. What matters more is the readability of the codebase IMO. Keep it as is for now, but I'm going to start looking into passing the gcode parser structs instead, which will require some refactoring of the code.

Anywhow, keep us in the loop! I'm loving how you're using grbl_sim for all this and getting those great visualizations of what Grbl is doing!

@alpharesearch
Copy link
Contributor Author

@PicEngraverToo : Right now this file runs very slow. Is there an option to only have whole S values, instead of S69.56 just S69. The PWM is only 8 bit and I did map 0 to 255 so any decimal places don't really matter. If the S value doesn't change it doesn't need to be processed.

@chamnit : While I was copying and pasting variables to all the functions I was think about a struct as well...
Here is a photo from some cardboard (looks like cardboard burns too fast and is more a digital - there is not much left from the gray scale part):
http://alpharesearch.de/wp-content/uploads/2014/09/IMG_20140920_121713.jpg
On the photo there is some offset every other line on the right and left. I'm not sure why, but I did retest this with the master in simulator without my modifications and I can see the same offset. I was always assuming this was caused because I don't change S at the right time (in my code this offset was worse before doing the spindle update in IRS)... but because this is the same issue in hardware and simulator and in new and old version I'm sure it is something in the code and not in my machine. I do see the same in simulations with only going one way (I use G0 to return X0). Could this have something to do how the PWM is setup/working?

@chamnit
Copy link
Member

chamnit commented Sep 20, 2014

@alpharesearch : I quickly looked at your source code. It's not quite right how to implement the spindle control, because you are calling spindle_run(). There's a lot of extra stuff that function does that isn't compatible with the stepper ISR. Instead, I would make a separate function that only sets the PWM OCR register in the ISR. Something very quick to execute. The calculations for the correct OCR value should be done a priori, if possible, but you get probably get it to work quickly without it for now.

@alpharesearch
Copy link
Contributor Author

@chamnit Thanks for your input! I was able to pick the run function apart and moved the calculation in the prep function and only set the bits in the ISR.

Here is a log from grbl simulator test with only the OCR in ISR :

# block number 0
   1.002666950225830 0, 0, 0, 0But there are more bits than just OCR...
   ...
   1.760000109672546 182, 0, 0, 0
   1.770000100135803 187, 0, 0, 0
   1.780000090599060 192, 0, 0, 0
   1.786611795425415 195, 0, 0, 0
# block number 1
   1.790000081062317 197, 0, 0, 0
   1.800000071525574 201, 0, 0, 0
   1.810000181198120 206, 0, 0, 0
   1.820000052452087 212, 0, 0, 0
   1.830000042915344 217, 0, 0, 0
   1.840000033378601 222, 0, 0, 128
   1.850000023841858 227, 0, 0, 128
   1.860000014305115 232, 0, 0, 128
   1.870000004768372 238, 0, 0, 128
   1.880000114440918 243, 0, 0, 128
   1.890000104904175 249, 0, 0, 128
   1.900000095367432 254, 0, 0, 128
   1.910000085830688 260, 0, 0, 128
  ...
   2.130000114440918 399, 0, 0, 128
   2.133105516433716 401, 0, 0, 128
# block number 2
   2.140000104904175 406, 0, 0, 128
   2.150000095367432 413, 0, 0, 128
   2.160000085830688 420, 0, 0, 128
   2.170000076293945 427, 0, 0, 128
   2.180000066757202 434, 0, 0, 128
   2.190000057220459 442, 0, 0, 255
   2.200000047683716 449, 0, 0, 255
   2.210000038146973 456, 0, 0, 255
   2.220000028610229 463, 0, 0, 255
   2.230000019073486 470, 0, 0, 255
 ...
   2.490000009536743 633, 0, 0, 255
   2.492191553115845 634, 0, 0, 255
# block number 3
   2.500000000000000 638, 0, 0, 255
   2.510000228881836 643, 0, 0, 255
   2.520000219345093 649, 0, 0, 255
   2.530000209808350 654, 0, 0, 255
   2.540000200271606 659, 0, 0, 0
   2.550000190734863 664, 0, 0, 0
   2.560000181198120 669, 0, 0, 0
   2.570000171661377 674, 0, 0, 0
   2.580000162124634 679, 0, 0, 0

I'm not sure how exact the block numbering in the simulator is but I guess (or hope) this is the real deal. Of course as faster the feed rate as more error I get. But was buffels me the most is that the updates look like they are behind. I was expecting more like to update right before the new block starts?

And here is the g code I used to test

G0 X0.00 Y0.00
M3 S0
F4000
G1 X2.50 S0
G1 X5.00 S128
G1 X7.50 S255
G1 X10.0 S0

G0 X0.00 Y1.00
G1 X2.50 S0
G1 X5.00 S128
G1 X7.50 S255
G1 X10.0 S0
...
M5

@PicEngraverToo
Copy link

@alpharesearch: Try out this new S command gcode without any decimal places.

http://picengrave.com/downloads/miscdownloads/Transportation680.txt

@alpharesearch
Copy link
Contributor Author

@PicEngraverToo : Thanks for the file... if this was the same data it looks like shaving off the decimal places saved 1.9MB... The g code parser in the master version is now able to skip if the same S values doesn't change. This makes it a lot faster in the old code because a change in S triggers that the whole buffer gets emptied every time...

@samsungite
Copy link

Hi,
This info is not for me ! :-(

My questions related to backlash and lathe chuck timing.

Thanks
Terry

Sent from Samsung Mobile

-------- Original message --------
From: Markus Schulz notifications@github.com
Date:22/09/2014 00:24 (GMT+00:00)
To: grbl/grbl grbl@noreply.github.com
Subject: Re: [grbl] laser and grbl experiments (#492)
@PicEngraverToo : Thanks for the file... if this was the same data it looks like shaving off the decimal places saved 1.9MB... The g code parser in the master version is now able to skip if the same S values doesn't change. This makes it a lot faster in the old code because a change in S triggers that the whole buffer gets emptied every time...


Reply to this email directly or view it on GitHub.

@mschorer
Copy link

@alpharesearch: (how) do you handle adjusting laser-power depending on speed-of-motion? or is it good enough to assume that the laser is moving at a constant speed? shouldn't the S-value adjust "laser energy output per mm" and grbl manage the ramping up/down of laser output in sync to accel/decel and "ground-speed"?

@chamnit: remember the discussion we had about "streaming S-values"? i very much like the idea of not always having to empty the buffers when updating spindle values. for normal cnc operation we would have to provide a way to make the the machine wait for the spindle to reach the required rpm though ... maybe depending on the change rate: no wait if change is < 10%, else wait 1s per 1000rpm ...

@PicEngraverToo: btw, couldn't you compress away the "X..." for the same X value too? should reduce data/filesize by another ~40%.

...
X0 Y0 S98
Y0.127 S66
Y0.254 S75
...
Y95.123 S143
X0.127 Y95.123 S103
Y94.996 S46
Y94.869 S58
...

@samsungite
Copy link

Hi
I dont understand why i am receiving this email !
All very interesting though :-)
On 22 Sep 2014 09:06, "Markus Schorer" notifications@github.com wrote:

@alpharesearch https://github.com/alpharesearch: (how) do you handle
adjusting laser-power depending on speed-of-motion? or is it good enough to
assume that the laser is moving at a constant speed? shouldn't the S-value
adjust "laser energy output per mm" and grbl manage the ramping up/down of
laser output in sync to accel/decel and "ground-speed"?

@chamnit https://github.com/chamnit: remember the discussion we had
about "streaming S-values"? i very much like the idea of not always having
to empty the buffers when updating spindle values. for normal cnc operation
we would have to provide a way to make the the machine wait for the spindle
to reach the required rpm though ... maybe depending on the change rate: no
wait if change is < 10%, else wait 1s per 1000rpm ...

@PicEngraverToo https://github.com/PicEngraverToo: btw, couldn't you
compress away the "X..." for the same X value too? should reduce
data/filesize by another ~40%.

...
X0 Y0 S98
Y0.127 S66
Y0.254 S75
...
Y95.123 S143
X0.127 Y95.123 S103
Y94.996 S46
Y94.869 S58
...


Reply to this email directly or view it on GitHub
#492 (comment).

@mschorer
Copy link

@samsungite: then stop commenting on every post and "unwatch" this project.

@samsungite
Copy link

Hi, i apologise for my ignorance :-)
Its very interesting stuff so i wont dropout just yet :-)
On 22 Sep 2014 09:58, "Markus Schorer" notifications@github.com wrote:

@samsungite https://github.com/samsungite: then stop commenting on
every post and "unwatch" this project.


Reply to this email directly or view it on GitHub
#492 (comment).

@alpharesearch
Copy link
Contributor Author

@mschorer : I don't handle it at all, right now I just set the PWM register when a new block starts, but it would probably be a good idea to process these values in the planner depending on speed.

For laser engraving my workaround is just to add a white boarder to the image at the area where the speed ramps up. From the simulator it looks like after that the speed is pretty consistent.

I do not have a variable spindle so I don't know how long it takes to ramp it up or down, all I have is a Dremel. Right now I just us a bool in the settings to turn it from the old way of doing things to the new way. I guess it would be possible to make this a int and use this number to calculate the delay that is needed for a spindle to ramp up to speed. Is there a algorithm for that? I'm sure I could come up with something but I'm not a math wizard.

I would guess with a CNC and spindle it would be best to slow down the movement while ramping up the speed of the spindle. But with a laser it needs to turn down the power of the laser while the machine come up to speed. Kind of the same functionality but still a little bit different.
The laser use case is much easier to implement, the spindle use case add feed rate overrides as a plus.

@PicEngraverToo : I was able to run your large file and it worked good until my wife turned my computer off :-)

In the imagetolaster program I do compress the axis that is not moved and I also compress all the lines that have the same S value. The next step would be to remove all the space characters.

@chamnit
Copy link
Member

chamnit commented Sep 22, 2014

@mschorer : Yes I remember our conversation. For mills, this still stands. You have to come to a stop before resuming or bits will break. For laser cutters, this is a different situation for which real-time updating of the spindle output is required. But, this has to be a settings only type functionality, having a pause or real-time update depending on rate would still have problems with mills since you can't cover all scenarios robustly.

@alpharesearch : As I was saying before, installing real-time spindle control isn't trivial. You need to do a few more things. For one, you still need to write a separate function to update only the spindle PWM OCR value and not have any plan synchronization calls in it (if you haven't done this already). You also need to change the g-code parser to prevent the planner from synchronizing when a new S value has been sent. You can ignore the execution phase of this, because you are pushing it downstream to the stepper ISR and it'll be executed correctly there. I think all you need to do is comment out the spindle_run() call when there is a spindle speed update. Spindle power is handled separately a few lines down and that DOES require a plan sync still.

@alpharesearch
Copy link
Contributor Author

@chamnit : In regards to any plan synchronization calls there are IF functions in front (but inside #ifdefs, so you want to look 2 lines up and notice there is no semicolon) that only call the synchronization if needed. This is in the gcode parser and it was used in the run function so that is would not cause issues in the ISR. It worked like this but to make it more readable and understandable I started adding extra functions to spindle control.
Should this line of g code not work in real time too (we are at X0): G1 X10 F100 M3 S256
I would think this line should turn the laser on and set power output to 256 plus move from X0 to X10 with feed rate of 100.

@villamany
Copy link

I dont know abot the 0.8 PWM capabilites (i only tested 0.9), maybe someone more experienced can help you. But you can post the GCODE file for discard a file generation issue.

@rusirius76
Copy link

@Dikabro : What medium is that? In the picture it almost looks like a fiberglass or something like that? Could just be the pic.

Some materials have a very nice grayscale capability... Others are very touchy requiring fast feed rates. Poplar for example I find pretty easy to get gray scale on, though faster feed rates open up the range. On the other hand, some white woods I've found (don't know exactly what they were) were just almost a 1-bit medium where it was very difficult to get any sort of variation in color. Basically once it burned it just burned.

It could be the medium or it could just be that you need to get your feed rate up faster?

@PicEngraverToo
Copy link

@rusirius76 Try testing PEP5 & PicSender and consider your laser diode as paint and a sprayer and lower it down and aim it at your material instead of waving it in the air and complaining that it does not perform like you want it to. :-D

One customer's criticism does not warrant a change. ;-)

@alpharesearch
Copy link
Contributor Author

@rusirius76 have a look at my imagetolaser project... maybe you could help with some real world data... I could make a QT GUI and we could make it available for windows too but I need to refine it but I'm not sure about the exact requirements. I only made it (or better forked it) for a quick tool to get the simulator tested because I didn't wanted to fork over any money ...https://github.com/alpharesearch/imagetolaser
But I think it should work just fine and it is foss, we could combine this with a sender too. If we find a foss sender it should be easy to integrate or merge the two.

@kfoltman
Copy link
Contributor

kfoltman commented Feb 9, 2015

Speaking of frontends and QT GUIs, I'm also working on something related - a PCB CAM and a Python GRBL sender/frontend - https://github.com/kfoltman/wharrgrbl - the sender part is not functional yet, but pretty close. The character-counting sender is already implemented, and it seems to work.

So, chances are, if we combine the efforts, we might end up with something that can do PCBs, laser engraving of pictures and maybe even laser exposing (think UV soldermask) and have it drive GRBL directly. This gives some extra possibilities due to integration, for example, auto-Z-probing or redoing the underetched areas on request.

@Dikabro
Copy link

Dikabro commented Feb 9, 2015

@rusirius76 I dont know on what kind of material I engraving, but it is a little bit glossy, maybe it's lacquered. I will try to engrave on different material and will post results here. :)

Do you using 0,9 grbl version on older 0,8c lasermode edition?
If you are using 0,9 grbl version then maybe you could send your code for me in private? :)
But don't send only hex file, because in my system there is Arduino NANO and I need to change pinouts..:)

Last time when I was flashed 0,9g master version on my NANO - my homing function doesn't worked correct like in 0,8c...

@rusirius76
Copy link

@alpharesearch : Very cool... It's funny, I actually just started some code this weekend that will be FOSS. I'm working in visual studio though for a windows platform. .NET already includes a lot of great features for image manipulation. It literally took me about 10 minutes to have some functioning "guts" that would allow you to open any image (.gif, .jpg, .bmp, .wmf, .png, etc), converts it to grayscale (averages the Red, Green, Blue color components of each pixel) and then rewrites those values as that average. Then can do the same to generate gcode based on the values and locations of those pixels.

There's a lot to do in terms of refining it, making it slick and intuitive, and adding lots of features, but it really shouldn't take much development time.

I love what I'm seeing here though... This is exactly what this community needs. A lot of options and tools to make these sorts of projects as accessible as possible.

I'd be glad to test out the imagetolaser and throw out any ideas that come along!

@kfoltman : This is great! I'm actually a bit of an electronics nut myself and am awaiting the arrival of some dry UV film. I wanted to do exactly that, explore the PCB making abilities.

@Dikabro : Yeah, definitely change material. Poplar and Birch work really well for me. I also make sure to sand the surface before etching. Usually 320 grit minimum... Often times polished up with some 600.

I use .9h. Both @alpharesearch and I have versions of it that have been modified for "real-time" spindle control (i.e. laser power adjustments via S commands don't slow things down.) I'd recommend using his though because to be honest I don't remember the last time I pushed mine and I've been working on it quite a bit to clean it up.

@villamany
Copy link

@rusirius76. Yesterday i start a similar project! For the moment i have GUI about finished (very simple). I can convert any image to grayscale, adjust the brightness, contrast and gamma by friendly sliders and then generate a bitmap of the correct size based on desired resolution and desired output image size (in mm) I only need to get each pixel and convert to gcode..maybe tomorrow i can start to generate the first gcodes. Im planing also to add some type of profiles for minimize the no linear output power.

@rusirius76
Copy link

@villamany : Awesome! I'm looking forward to seeing it when it's flushed out!

@rusirius76
Copy link

Ok, I've worked a little bit in my free time to add some image manipulations. Currently it will flip, rotate, invert (make negative for mirror etching, etc), etc... I just finished the dithering routine... I set it up so that other methods can be used (it uses a dither matrix that can be defined based on how you want the error distribution to be applied), but honestly I think it's probably best (and certainly more simple from an end user perspective) to just use Floyd-Steinberg. In my experience it generally produces the best results anyway.

The entire concept with this is to make it as easy as possible for an end user. They don't have to worry about image size, etc.. Just tell it the pixel size you want, the height and width you want the finished gcode to burn, etc...

@villamany
Copy link

i'm starting some test for image to gcode conversion, could someone confirm me if i am using the correct logical for minimize the data stream between PC-GRBL?

-Remove all white spaces from lines
-Send the modal G1 command only at begin instead on each line
-Add only the CR as line end, instead CR+LF
-Send only the X, Y and S values if they are diferent since last update
-Using the format 0.### for coordinates

@rusirius76
Copy link

@villamany : Sounds right to me!

@rusirius76
Copy link

@villamany : also, you have to be careful, so you don't overrun any limits.. but I plan on incorporating a user selectable option for a "buffer" zone around the image. So for example, 5mm of "blank space" around the sides of movement... So that the machine is "up to speed" by the time it actually starts burning pixels... No acceleration during burning...

@alpharesearch
Copy link
Contributor Author

@kfoltman sounds like a very interesting project, I think I need to start learning KiCad again... I once made I little PC keyboard with it: http://alpharesearch.de/?page_id=53 but at that time I use batchPCB.

@rusirius76 I like .net and C#, but if you want to support not just Windows make sure to make it mono compatible.

Regarding the Raspberry Pi 2 it is a lot faster now, I did use the latest version of UGS via VNC and it starts fine and the web page pendant feature was accessible from my other PC. To copy files I use scp (mc under linux or winscp under windows) I think it is more usable now and I'm happy with it.

If you get the latest raspbian image from raspberry pi web page you have Oracle Java installed, but you need to get the rxtx library for serial communication.

sudo apt-get install librxtx-java

now you can start UGC like this (change the linux start line in start.sh to look like this):

java -Djava.library.path=/usr/lib/jni -cp /usr/share/java/RXTXcomm.jar -jar -Xmx256m $rootdir/UniversalGcodeSender*.jar

PS: The next test would be to see how http://octoprint.org/ works with grbl, or make it work with grbl.

@villamany
Copy link

@Dikabro
Copy link

Dikabro commented Feb 10, 2015

Very nice work!!! Simple and good.;)

@rusirius76
Copy link

@villamany : Looking good! I'm actually coding mine in VB.Net. For what I do in my job I end up having to use it a lot more so development for me just comes much faster using it. And with .NET there isn't really much difference anyway! Dithering is an important aspect though, Sometimes images just come out "better" with dithering I've found, and for mirrors or other essentially 1-bit mediums it's just a must. Here's the code I use for it... Should make your life a little easier...

        Dim bm As New Bitmap(pbRender.Image)
        Dim X As Integer
        Dim Y As Integer
        Dim clr As Integer
        Dim DitherTable(0, 0) As Byte
        Dim dErrors(0, 0) As Double
        Dim errorVal As Integer
        Dim dDivisor As Integer
        Dim xLeft As Integer, xRight As Integer, yDown As Integer
        Dim QuickX As Integer, QuickY As Integer

        'The core code is run against a "dither table" which contains distribution of the errors.  This way
        'other dither methods can be implemented later by just supplying a different table.
        'First, prepare a Floyd-Steinberg dither table
        ReDim DitherTable(3, 2)
        DitherTable(2, 0) = 7
        DitherTable(0, 1) = 3
        DitherTable(1, 1) = 5
        DitherTable(2, 1) = 1
        dDivisor = 16

        'Second, mark the size of the array in the left, right, and down directions
        xLeft = 0
        xRight = 2
        yDown = 1

        'Redim a dithering table the same size as the image.
        'We could just use a 2 high array instead of the entire image and reset values each time we
        'move to another line, but I think this should be faster, and memory shouldn't be a problem
        'for modern machines.
        ReDim dErrors(pbRender.Image.Width, pbRender.Image.Height)

        'Now loop through the image, calculating errors as we go
        For X = 0 To bm.Width - 1
            frmStatus.pbStatus.Value = X / (bm.Width - 1) * 100
            For Y = 0 To bm.Height - 1
                'When the image is loaded it's converted to grayscale, so R, G, and B are all the
                'same value for a given pixel, so we just use G.
                'Set clr to the original value + any error stored in the error table.
                clr = (CInt(bm.GetPixel(X, Y).G)) + dErrors(X, Y)

                'Now let's figure out if it should be black or white.
                If clr >= 127 Then
                    'We're setting the pixel black, so the error is the difference between original pixel
                    '(plus error applied) and 255.
                    errorVal = clr - 255
                    'now set the pixel black
                    bm.SetPixel(X, Y, Color.FromArgb(255, 255, 255))
                Else
                    'Setting it white.  Error is just the original pixel value + error applied
                    errorVal = clr
                    bm.SetPixel(X, Y, Color.FromArgb(0, 0, 0))
                End If

                'If there is an error, spread it according to the dither table
                If errorVal <> 0 Then

                    'Spread across the relevant pixels according to the dither table formula
                    For i = xLeft To xRight
                        For j = 0 To yDown

                            'ignore already processed pixels
                            If (j = 0) And (i <= 1) Then Continue For

                            'ignore pixels that have a zero in the dither table
                            If DitherTable(i, j) = 0 Then Continue For

                            QuickX = X + i
                            QuickY = Y + j

                            'Next, ignore target pixels that are off the image boundary
                            If QuickX < 0 Then Continue For
                            If QuickX > bm.Width - 1 Then Continue For
                            If QuickY > bm.Height - 1 Then Continue For

                            'Now apply the error here.
                            dErrors(QuickX, QuickY) += (errorVal * (CSng(DitherTable(i, j)) / dDivisor))
                        Next j
                    Next i
                End If
            Next Y
        Next X
        'We've swept the whole image, so let's put it back in the picturebox.
        pbRender.Image = bm

@villamany
Copy link

Nice! I will try to implement it.

@chamnit
Copy link
Member

chamnit commented Feb 10, 2015

Ok fellas. This topic has veered off course and has gotten out of hand. I'm closing this issue. Should you want to open another one on the specific topic of laser GUIs for Grbl, go ahead.

@chamnit chamnit closed this as completed Feb 10, 2015
@rusirius76
Copy link

I was actually thinking the same thing... I went ahead and created a forum for everyone here to discuss pretty much anything to do with laser engraving. It's located at www.engraving-lasers.com. Lot of work to do yet in setting it up, but it's there at least and it'll let us discuss this stuff somewhere more appropriate. Sorry for running over your issue thread @chamnit.

@alpharesearch
@villamany
@Dikabro
@EliteEng

@zesava
Copy link

zesava commented Oct 17, 2015

Hi everyone. I will leave here my five coins :) I have builded 3dpburner by villamany and was confused how fast i may tuning laser power/feed rate for different materials. So i wrote my own app.
screen

with it you can adjust parameter during engraving. App was tested with AlphaResearch version at Feb/04/2015 and with regular grbl v0.9i for Z head mode. Hope someone found this usefull.
https://drive.google.com/open?id=0B_ZjDNHJ9krcZC12bDRfZjFkc0U

@Dikabro
Copy link

Dikabro commented Oct 19, 2015

Can't import 8bit picture...

@zesava
Copy link

zesava commented Oct 19, 2015

App accepts only 8bit *.BMP.

@Dikabro
Copy link

Dikabro commented Oct 19, 2015

Could you make 16 bit modification?

@zesava
Copy link

zesava commented Oct 22, 2015

if you look at grbl source code(config.h), you will find next line

Use by the variable spindle output only. These parameters set the
maximum and minimum spindle speed
"S" g-code values to correspond to the maximum and minimum pin voltages. There are 256 discrete and equally divided voltage bins between the maximum and minimum spindle speeds.

so there is no sense to make 16 bit image resolution, coz 16 bit means
65,535 colors of gray, but we have only 256(8bit) output. So this
modification will have no influence for the engraving.

@Dikabro
Copy link

Dikabro commented Oct 22, 2015

I understand that. But the problem is that I can't open any image on your software. It doesn't allows for some reason.

@zesava
Copy link

zesava commented Oct 22, 2015

http://lmgtfy.com/?q=8+bit+grayscale+bmp

2015-10-22 20:56 GMT+03:00 Dikabro notifications@github.com:

I understand that. But the problem is that I can't open any image on your
software. It doesn't allows for some reason.


Reply to this email directly or view it on GitHub
#492 (comment).

Live Free Or Die Hard

@StuartB4
Copy link

StuartB4 commented Jan 5, 2017

@Dikabro.

You have to click the GRBL button and connect to the COM port first. Then click the GCODE button and the Open image button is available.

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